I have here an old laptop and intend to send/receive data on the parallel port in set time intervals (20 kHz max).
The laptop has MS DOS 7.1 installed, as well as Turbo C. Is it possible to create threads in DOS via some lib, and if not, how would I implement ISRs in C? So far I have only done this in assembler, and I'm not quite sure how exactly to mix C and assembler without breaking everything.
I could install TinyCore, but I kinda want to keep MS DOS so I can play Commander Keen.
Name:
Anonymous2011-03-17 17:04
>>1
No. You'll have to hook interrupts and write a scheduler yourself.
Name:
Anonymous2011-03-17 17:17
What point in using DOS today?
Name:
Anonymous2011-03-17 17:22
>>2
Can I just pass C function addresses as ISR? If so, what would I do about the IRET?
I'm a little confused on how to do it.
>>1 I'm not quite sure how exactly to mix C and assembler without breaking everything.
Use the fucking ``asm'' keyword only if needed and if in doubt disassemble shit to look how it adds up with your program.
Also: shit dude you never heard of dosbox?
Name:
Anonymous2011-03-17 17:45
>>4
You can't use C functions as interrupt handlers without special compiler support, because it won't know to preserve all the registers and the stack.
It should be dead easy to mix C and assembly, though, you just need to know what ABI you are using.
Write a makefile to compile/assemble to object files, then link them together.
>>6
An old laptop, because it was a spare part, and having a keyboard and screen makes a nice interface without having to pay for additional hardware for in-/output. >>7
I have basic knowledge of x86 assembly; I know how to work with interrupts and all the basic instructions. I also have a ~250 pages document here for the times I'm in doubt. My problem is neither C or asm, I just need to call a function every 50µs (i.e. 20kHz).
Also: What benefit could dosbox do in my case? >>8
Well, fuck. I already thought that'd be a problem. I was hoping to use C for the ISR, since I might have to use trigonometric and/or exponential functions, and doing that in asm is a pain.
As an alternative I was thinking about using clock() in a loop to determine when to call the function, since a little jitter is acceptable. The UI can lag a little for all that I care, I'm just not sure if it could work.
>>10 I just need to call a function every 50µs (i.e. 20kHz).That's quite fast. What I would do is determine the CPU's speed then see how many ticks are in one second, then adjust that to your requirements. I would say to hook interrupt 8 or 1C, but by default those are called only every 18.2 times per second, which is much slower than your need, which means you'll need to program the timer, read http://wiki.osdev.org/Programmable_Interval_Timer for information on how to do this.
Name:
Anonymous2011-03-17 20:53
>>10
You can call C functions from your ISR, just make sure you preserve all the scratch registers.
>>12
That just leaves the problem to tell my ISR where my function is. I'd just load the ISR in a TSR program and then start the C program, writing the address in the memory, but those two programs would probably end up in different segments, and I don't really know what to do then.
>>11
It's a 233MHz CPU, so I figured I had enough cycles to spare for a waiting loop. At least that's what I hoped for. Thanks for the link though, it could really help if my documentation runs out of information.
For anyone that is interested, using the timer chip worked pretty well, since Turbo C knows how to deal with ISRs. >>11-kun's idea was pretty much the answer to my problem. clock() is useless, as it only runs at 18.2Hz.
Name:
Anonymous2011-03-20 4:36
In the ISR, save the DS, ES, SS, SP, BP, AX, BX, CX, DX, SI, and DI of the current thread. Then, load those registers from the next thread and IRET. The next thread's stack already has its FLAGS, CS, and IP saved from the previous task switch (and you've already switched to the next thread's stack by loading SS and SP). For this, the ISR has to be for the _actual_ timer interrupt, not something generated by DOS or the BIOS. Read up on the 8086. The stack looks like this after an interrupt:
Previous Stuff <- Old SP
Return FLAGS
Return CS
Return IP <------ New SP
IRET pops IP, CS, and then FLAGS.
On the 80186 for 2 threads, you can just do something like:
Of course, the other thread will need its own stack, and ThreadSS:ThreadSP will need to point to the top of it. Also, the initial register state for it will have to already be on its stack.