I am looking for a way to create a simple duel thread handler in 16-bit dos. I would like if someone could give me some code(with comments please, but without is ok to) for it that I can mess with. The main problem I am having is getting my thread handler to jump to a instruction then jump back to the handler. I use ml.exe and link16.exe to create my program and I use Dosbox to run the programs and I am only a beginner in masm, if it helps.
Any help would be appreciated, thanks :bg.
The normal method is to replace the IP saved on the stack during the call to the handler with the saved IP of the other thread, and then "returning" (a misnomer, because it will return to an entirely different thread). FWIT you are in way over your head trying to do this, especially in DOS.
-r
Maybe so but, I'd still like to do it, thanks for your input.
The problem is that getting it to call back o he handler. I was thinking that if I found out how instructions are sored in memory i could set aside a section in memory then go to a thread, get the next instruction, store it in memory and directly after put "jmp (thread handler address here)" to get it to call back. After i would do this for the next thread then loop. :dazzled:
Would this work?
-If this would I don't have enough knowledge to do it and please help.
Sorry for my last post my "t" key is broken on my keyboard and i keep forgetting to use a virtual keyboard. So If A word doesn't sound right like "o" or "he" it is most likely "to" or "the".
You can't just copy the instructions, for many reasons. First and foremost, if it's a JMP instruction, then it will do just that, and never return. Also, memory addressess will be all wrong.
There are two main ways to do: preemptive or cooperative. In the latter, each thread must specifically call a function to return control to the handler, which is easier, but allows for misbehaving programs. Because threads will run until they decide to give back control, the system is very fragile. In the former, you have to hook the timer interrupt, and decide on every 'tick' whether to keep running the current thread or switch to a new one.
-r
I realize that if i were to jump to a location it will not return, but will keep running from that point. But will it work if I rearrange the code by putting it in a new part of memory, like i said in one of my other posts? What I was saying in that post was, that basically replace the code to be executed with a jump to an edited section of the code. Like (Code to execute) -followed by in memory the jump back to handler. Once executed and jumped back to handler the handler will resume he thread after the section that tells it to jump to the edited version of that part of code. Once done the old jump will be replaced with the original code and a new one created for the next line of code.
I'm having trouble understanding why you would take an already complex task and complicate it even further by moving instructions around in memory. This is not how threads are normally managed. What is your goal here?
Well I'm new to asm and my goal is to create a simple two thread handler I plan on using this to handle drawing the mouse cursor and running the program at the same time(not literally at the same time, but instructions from each thread inter woven). I am currently looking into the possibility of using software interrupts to switch threads.
You are much better off just trying co-operative multi-tasking in DOS. Basically having a Yield() type function and switching between tasks/threads in a round-robin fashion. The task switch involves stacking the current context, changing the stack to the next task and un-stacking the context and continuing. Each task has it's own stack and context. You can use interrupt to perform various operations, but I wouldn't use it to actually switch tasks as you may often find yourself interrupting DOS code, and DOS isn't very re-entrant or forgiving.
You might also look at things like uCOS/II, it used to have DOS based examples.
Ok, I'll try that but i would still like to know how to store instructions(and operands) for future reference.
Quote from: www.:).com on November 06, 2010, 02:28:22 AM
Ok, I'll try that but i would still like to know how to store instructions(and operands) for future reference.
It's all bytes of data in memory, copy it from one place to another, or save it to a file.
Quotemy goal is to create a simple two thread handler I plan on using this to handle drawing the mouse cursor and running the program
The mouse cursor is normally drawn in sync with mouse motions, in response to a hardware interrupt. A thread that runs intermittently will not be able to reliably keep up with the motions.
Quote from: clive on November 06, 2010, 03:43:51 AM
Quote from: www.:).com on November 06, 2010, 02:28:22 AM
Ok, I'll try that but i would still like to know how to store instructions(and operands) for future reference.
It's all bytes of data in memory, copy it from one place to another, or save it to a file.
Do you happen to know how many bytes can make up an instruction?
Quote from: MichaelW on November 06, 2010, 05:13:13 AM
Quotemy goal is to create a simple two thread handler I plan on using this to handle drawing the mouse cursor and running the program
The mouse cursor is normally drawn in sync with mouse motions, in response to a hardware interrupt. A thread that runs intermittently will not be able to reliably keep up with the motions.
I realize that, but I think that is only when you are using a default cursor such as:
mov ax, 02
int 33h
I think this is to turn on the dos mouse.
If not please correct me.
I am using a custom mouse i get the current position of the mouse as follows:
mov ax, 03
int 33h ; cx now holds X coordinate dx holds Y coordinate
; convert X and Y coordinates to linear here
; draw to that location here
Quote from: www.:).com
Do you happen to know how many bytes can make up an instruction?
Yes, but it depends, the x86 uses a variable length instruction encoding. I can compute the length, but it is a non-trivial task.
Now normally when moving blocks of instructions around, one puts a label in front, and behind the block, and then computes the delta. Object files typically contain metadata describing the length of blocks of instructions.
Perhaps you should review the topics of assemblers, disassemblers and machine code, and perhaps linkers and loaders.
Observe that instructions are encoded with different sizes, depending on the opcode, and operand(s)
00401450 _AddProcRef: ; Xref 004065DF 0040669D 00406938 004069F9
00401450 ; 00406D96 00406DD0
00401450 A1444C4100 mov eax,[_ProcRefList]
00401455 85C0 test eax,eax
00401457 7465 jz loc_004014BE
00401459 8B0D44104100 mov ecx,[_ProcRefMax]
0040145F 8B15404C4100 mov edx,[_ProcRefCount]
00401465 3BD1 cmp edx,ecx
00401467 7570 jnz loc_004014D9
00401469 53 push ebx
0040146A 56 push esi
0040146B 57 push edi
0040146C 8D0409 lea eax,[ecx+ecx]
0040146F 68A8124100 push offset off_004112A8 ; 'AddProcRef(),NewProcRefList',000h
00401474 6A0A push 0Ah
00401476 50 push eax
00401477 A344104100 mov [_ProcRefMax],eax
0040147C E87FFBFFFF call _allocate
00401481 8BD8 mov ebx,eax
00401483 A1404C4100 mov eax,[_ProcRefCount]
00401488 8B35444C4100 mov esi,[_ProcRefList]
0040148E 8BFB mov edi,ebx
00401490 8D0C80 lea ecx,[eax+eax*4]
00401493 D1E1 shl ecx,1
00401495 8BC1 mov eax,ecx
00401497 C1E902 shr ecx,2
0040149A F3A5 rep movsd
0040149C 8BC8 mov ecx,eax
0040149E 83E103 and ecx,3
004014A1 F3A4 rep movsb
004014A3 8B0D444C4100 mov ecx,[_ProcRefList]
004014A9 51 push ecx
004014AA E8A1FBFFFF call _release
004014AF 83C410 add esp,10h
004014B2 8BC3 mov eax,ebx
004014B4 A3444C4100 mov [_ProcRefList],eax
004014B9 5F pop edi
004014BA 5E pop esi
004014BB 5B pop ebx
004014BC EB1B jmp loc_004014D9
004014BE loc_004014BE: ; Xref 00401457
004014BE 8B1544104100 mov edx,[_ProcRefMax]
004014C4 68C4124100 push offset off_004112C4 ; 'AddProcRef(),ProcRefList',000h
004014C9 6A0A push 0Ah
004014CB 52 push edx
004014CC E82FFBFFFF call _allocate
004014D1 83C40C add esp,0Ch
004014D4 A3444C4100 mov [_ProcRefList],eax
004014D9 loc_004014D9: ; Xref 00401467 004014BC
004014D9 85C0 test eax,eax
004014DB 7453 jz loc_00401530
004014DD 8B0D404C4100 mov ecx,[_ProcRefCount]
004014E3 668B542404 mov dx,[esp+4]
004014E8 8D0C89 lea ecx,[ecx+ecx*4]
004014EB 66891448 mov [eax+ecx*2],dx
004014EF A1404C4100 mov eax,[_ProcRefCount]
004014F4 8B0D444C4100 mov ecx,[_ProcRefList]
004014FA 8B542408 mov edx,[esp+8]
004014FE 8D0480 lea eax,[eax+eax*4]
00401501 89544102 mov [ecx+eax*2+2],edx
00401505 8B44240C mov eax,[esp+0Ch]
00401509 50 push eax
0040150A E851FBFFFF call _strmalloc
0040150F 8B0D404C4100 mov ecx,[_ProcRefCount]
00401515 8B15444C4100 mov edx,[_ProcRefList]
0040151B 83C404 add esp,4
0040151E 8D0C89 lea ecx,[ecx+ecx*4]
00401521 89444A06 mov [edx+ecx*2+6],eax
00401525 A1404C4100 mov eax,[_ProcRefCount]
0040152A 40 inc eax
0040152B A3404C4100 mov [_ProcRefCount],eax
00401530 loc_00401530: ; Xref 004014DB
00401530 C3 ret
ok thanks.
Mouse driver function 2 hides the mouse cursor and function 3 gets the button status and mouse position. Since you are referring to mouse-driver functions, I assume that you will be depending on a mouse driver to interface with the mouse, and that by "custom mouse" you mean a custom mouse cursor.
For the text modes the mouse driver provides a way to control how the cursor affects the appearance of the character under it. For the graphics modes the mouse driver provides a relatively simple way to define and use a custom cursor, but note that the cursor must fit in a 16x16-pixel block for the most commonly used display modes.
The mouse driver also provides a method for a user program to effectively hook into the mouse hardware interrupt. This method will work better than the separate thread that you are proposing, and it is much, much easier to implement.
O, i didn't know that, and Thanks for correcting me I thought it was the other way around function 01 hid the cursor and 02 showed it.
The attachment does not attempt to implement a custom cursor, but it does show how a mouse-driver interrupt subroutine can be implemented and basically how it works.
This code implements a custom cursor, consisting of a single pixel to keep it simple.
;=========================================================================
.model small, c
.386
include support.asm
.stack
;=========================================================================
.data
;=========================================================================
prevx dw 0
prevy dw 0
backcolor dw 0
;=========================================================================
.code
;=========================================================================
;---------------------------------------------------------------
; These procedures assume that the VGA is operating in mode 13h,
; and that ES has been loaded with the segment address of the
; graphics display buffer.
;---------------------------------------------------------------
GetPixel_13 proc uses bx cx dx x:WORD,y:WORD
mov ax, y ; pixel byte address = y*320+x
mov cx, 320
mul cx
mov bx, ax
add bx, x
xor ah, ah
mov al, es:[bx]
ret
GetPixel_13 endp
SetPixel_13 proc uses ax bx cx dx x:WORD,y:WORD,color:WORD
mov ax, y ; pixel byte address = y*320+x
mov cx, 320
mul cx
mov bx, ax
add bx, x
mov ax, color
mov es:[bx], al
ret
SetPixel_13 endp
;=========================================================================
MouseInit proc
mov ax, 3533h
int 21h
mov ax, es
test ax, ax
jnz @F
ret
@@:
xor ax,ax
int 33h
test ax, ax
jnz @F
ret
@@:
mov ax, 12
mov cx, 1 ; set only mask bit 0, cursor position changed
push cs
pop es
mov dx, InterruptSub
int 33h
mov ax, 1
ret
MouseInit endp
;=========================================================================
InterruptSub proc
push ds
push es
push ss
pop ds
push 0A000h
pop es
;--------------------------------------------------------------
; Convert the virtual-screen x coordinate (0-639) to a display
; pixel coordinate (0-319). For mode 13h the virtual-screen y
; coordinate (0-199) requires no conversion.
;--------------------------------------------------------------
shr cx, 1
;------------------------------------------------------------
; Erase the cursor by restoring the saved background at the
; previous cursor position, save the current coordinates for
; the next cycle, save the background at the new position,
; and draw the cursor at the new position.
;------------------------------------------------------------
invoke SetPixel_13, prevx, prevy, backcolor
mov prevx, cx
mov prevy, dx
invoke GetPixel_13, cx, dx
mov backcolor, ax
invoke SetPixel_13, cx, dx, 1
pop es
pop ds
retf
InterruptSub endp
;=========================================================================
.startup
;=========================================================================
mov ax, 13h
int 10h
call MouseInit
print hexword$(ax),13,10
call waitkey
;=========================================================================
.exit
end
the default cursor for video mode 13h is big and clunky - lol
here is one i created for that mode :U
you may want to replace the F6 and FE values with your own palette values of black and white
; mode 13h cursor
;
; width = 7
; height = 12
;
; 0 = x
; F6 = black
; FE = white
;
CBMEXI DW 0F6h,0,0,0,0,0,0
DW 0F6h,0F6h,0,0,0,0,0
DW 0F6h,0FEh,0F6h,0,0,0,0
DW 0F6h,0FEh,0FEh,0F6h,0,0,0
DW 0F6h,0FEh,0FEh,0FEh,0F6h,0,0
DW 0F6h,0FEh,0FEh,0FEh,0FEh,0F6h,0
DW 0F6h,0FEh,0FEh,0FEh
DW 0FEh,0FEh,0F6h
DW 0F6h,0FEh,0FEh,0FEh,0FEh,0F6h,0
DW 0F6h,0F6h,0F6h,0FEh,0FEh,0F6h,0
DW 0,0,0,0F6h,0FEh,0FEh,0F6h
DW 0,0,0,0F6h,0F6h,0F6h,0
my notes say the height is 11 pixels
but i see 12 lines of data - not sure why that is - lol
i may have decided not to use the bottom line of data
Thanks, and as for the 12 lines filled in when there are only to be 11 is the last a black line? Because when I set pixels on the screen for some reason there is one black pixel to the right of where I set the pixel. Do you happen to know why it does this or is it what I use to run them (dosbox)?
without seeing the code - no
yes - the bottom line is (partially) black
any location in the bitmap that contains a 0 is not z-buffered and over-written by a cursor pixel
i.e., the current pixel values at those locations are left unmodified
otherwise, all the F6 locations are black cursor pixels and all the FE locations are white cursor pixels
it has been a long time since i have written any code for mode 13h
perhaps the table needs to be defined as one more line than is declared in the mouse cursor set function
i don't recall
i do seem to recall that word values are used so that the high byte may serve as the actual z-buffer
as i said...
Quotemy notes say the height is 11 pixels
but i see 12 lines of data - not sure why that is - lol
i may have decided not to use the bottom line of data
try using 12 lines of data and telling the function you want a cursor of 11 lines height
Well i'm wondering why it puts a black pixel next to it. Here is some code i wrote that simply sets the entire screen to green. After that it sets the first pixel to blue and if you look closely there is a black pixel next to it. If you would like to test it assemble it using ml.exe and link16.exe in masm32\bin directory. I would not run it in real dos because for some reason when i assembled it it would not change back to text mode. wonder why? I recommend using dosbox at: http://www.dosbox.com/
; Question for masm form
.model small
.stack
.data
.code
AppMain:
mov ax, 00a000h ; mov segment of 13h video memory in to es for quick reference
mov es, ax
mov ax, 13h ; switch the video mode to 13h -- 320 X 200, 256 colors
int 10h
mov ax, 2 ; move the vga color for green into ax
mov di, 0 ; reset di to 0 so wee can fill the whole screen
FillScreen: ;Shows that this is were we fill the screen
mov es:[di], ax ; put the color ax into di
inc di ; increment di by 1
cmp di, 64000 ; see if di is at byte 64000 because we fill whole screen (320 * 200 = 64000)
jne FillScreen ; cheak to see if we have filled screen if so continue with rest of program
; Set first pixel to blue
mov ax, 1 ; set the regester i use for color to blue
mov di, 0 ; set the regester i use for pixel positioning to 0 -- first pixel
mov es:[di], ax ; set the pixel
mov ah, 07 ; Wait for key press
int 21h
mov ax, 03 ; switch video mode back to 80 X 25 -- text mode
int 10h
mov ax, 4c00h ; Exit to dos
int 21h
end AppMain
Quote from: www.:).com on November 07, 2010, 03:00:06 PM
I would not run it in real dos because for some reason when i assembled it it would not change back to text mode. wonder why?
It does switch back to text mode, but since the code does not pause after the switch, you can't see it (or at least I can't the way I'm executing it). Try adding this code after the mode switch:
mov ax, 40h ;
mov es, ax ; load segment address of BIOS data area into ES
mov bx, 49h ; load offset address of current video mode into BX
mov dl, es:[bx] ; get the value into DL
add dl, 30h ; anticipating a one-digit value, convert to decimal digit
mov ah, 2 ; and display it
int 21h
mov ah, 07 ; Wait for key press
int 21h
Dave,
I was interested to see what your cursor looked like, but I don't understand the definition or how it's supposed to be used. For mode 13h a 7x11 cursor should occupy 77 bytes in the display buffer, not 84 words. For the mouse driver Set Graphics Cursor Block Function (9), you specify the cursor as two 16x16 bit masks, 32 words total.
Quote from: MichaelW on November 07, 2010, 04:46:55 PM
Dave,
I was interested to see what your cursor looked like, but I don't understand the definition or how it's supposed to be used. For mode 13h a 7x11 cursor should occupy 77 bytes in the display buffer, not 84 words. For the mouse driver Set Graphics Cursor Block Function (9), you specify the cursor as two 16x16 bit masks, 32 words total.
Thanks, but i'm not shore I understand what you are saying.
- Remember I am a beginner(only understand the fundamentals).
sorry guys
looking further at my code, i had implemented drawing and un-drawing the cursor myself - lol
give me a few minutes and i'll post the resultant exe :P
ok - here it is
to run sf1mg2.com:
the W parameter allows creation of the map to be viewed
so, at the command prompt type:
SF1MG2 W
the first time you run it, it will generate a map
however, if the map is already present, some text notes will appear
press O to see it generated again or V to view the one already generated
(pressing V does not allow you to view map generation, of course)
once you are in there, a map appears
you can move the mouse about and click to bring up the measurement calipers
clicking again starts a measurement and again ends it
when you are done playing with that (lol), press ESC to exit (twice if calipers have been used)
THEN, you will see the cursor that i posted earlier (it is only used for the exit menu - lol)
note: to get out of full screen mode after exit, press Alt-Enter
Quote from: www.:).com on November 07, 2010, 05:00:06 PM
Thanks, but i'm not shore I understand what you are saying.
- Remember I am a beginner(only understand the fundamentals).
I'm not sure what you are asking, but here is a quick demo of a user-defined cursor and the Set Graphics Cursor Block function:
;=========================================================================
.model small
.386
.stack
.data
;------------------------------------------------
; Define screen and cursor masks for a crosshair
; cursor. Cursor hot spot at 7,7.
;
; The mouse driver will AND the screen mask bits
; with the corresponding screen pixel bits and
; XOR the result with the cursor mask. In truth
; table form:
;
; screen mask cursor mask resulting screen bit
; 0 0 0
; 0 1 1
; 1 0 unchanged
; 1 1 inverted
;
; Note that the masks bits are expanded as
; necessary for the current graphics mode.
; For example, for mode 13h each mask bit is
; expanded to 8 bits and these bits are then
; combined with the 8 attribute bits for the
; corresponding screen pixel.
;------------------------------------------------
;0123456701234567
screen_mask dw 1111111111111111b ;0
dw 1111111111111111b ;1
dw 1111111011111111b ;2
dw 1111111011111111b ;3
dw 1111111011111111b ;4
dw 1111111011111111b ;5
dw 1111111111111111b ;6
dw 0000001110000001b ;7
dw 1111111111111111b ;0
dw 1111111011111111b ;1
dw 1111111011111111b ;2
dw 1111111011111111b ;3
dw 1111111011111111b ;4
dw 1111111111111111b ;5
dw 1111111111111111b ;6
dw 1111111111111111b ;7
cursor_mask dw 0000000000000000b ;0
dw 0000000000000000b ;1
dw 0000000100000000b ;2
dw 0000000100000000b ;3
dw 0000000100000000b ;4
dw 0000000100000000b ;5
dw 0000000000000000b ;6
dw 1111110001111110b ;7
dw 0000000000000000b ;0
dw 0000000100000000b ;1
dw 0000000100000000b ;2
dw 0000000100000000b ;3
dw 0000000100000000b ;4
dw 0000000000000000b ;5
dw 0000000000000000b ;6
dw 0000000000000000b ;7
;=========================================================================
.code
;=========================================================================
MouseInit proc
mov ax, 3533h
int 21h
mov ax, es
test ax, ax
jnz @F
ret
@@:
xor ax,ax
int 33h
test ax, ax
jnz @F
ret
@@:
mov ax, 1
ret
MouseInit endp
;=========================================================================
.startup
;=========================================================================
mov ax, 13h
int 10h
call MouseInit
test ax, ax
jz @F
mov ax, 9 ; Set Graphics Cursor Block
mov bx, 7 ; hot spot x coordinate
mov cx, 7 ; hot spot y coordinate
push ds ; ES:DX -> screen and cursor masks
pop es
mov dx, OFFSET screen_mask
int 33h
mov ax, 1 ; Show Cursor
int 33h
@@:
mov ah, 07
int 21h
;=========================================================================
.exit
end
So what you are saying is each pixel I write to is stretched out to fill 8 bits in video memory?
in video mode 13h, each pixel takes one byte
what video mode are you using ?
Quote from: www.:).com on November 07, 2010, 05:59:22 PM
So what you are saying is each pixel I write to is stretched out to fill 8 bits in video memory?
Each pixel that you specify in the cursor masks is expanded to match the bits per pixel for whatever display mode is active.
Yes, I use model 13h. So when the memory actually gets written to the screen it is stretched side to side?
well - i wouldn't use the term "stretched"
it merely converts or translates bits into color values
Well yea, but the term stretched is what i use do describe what it looks like on the screen. :dance:
Quote from: www.:).com on November 07, 2010, 03:00:06 PM
Well i'm wondering why it puts a black pixel next to it.
In case you have not already figured this out, the reason is that your instruction:
mov es:[di], ax ; set the pixel
Is setting two bytes, one with the value from AL (=1), and one with the value from AH (=0). An easy fix would be:
mov es:[di], al ; set the pixel
O well that was stupid of me, thanks for correcting me. :U