I/O delay

Developer's Forum, for discussion of bugs, code, and other developmental aspects of DOSBox.

I/O delay

Postby Grunt » 2019-7-06 @ 16:04

Hello guys,
I've been trying to slow down I/O (especially disk reading) so I can emulate real I/O responses from old computer in DosBox. I've notice that such a thing is alredy implemented and used in DosBox.

dos/dos.cpp:
Code: Select all
71: #define DATA_TRANSFERS_TAKE_CYCLES 1
72: #ifdef DATA_TRANSFERS_TAKE_CYCLES
73:
74: #ifndef DOSBOX_CPU_H
75: #include "cpu.h"
76: #endif
77: static inline void modify_cycles(Bits value) {
78:     if((4*value+5) < CPU_Cycles) {
79:      CPU_Cycles -= 4*value;
80:      CPU_IODelayRemoved += 4*value;
81:   } else {
82:      CPU_IODelayRemoved += CPU_Cycles/*-5*/; //don't want to mess with negative
83:      CPU_Cycles = 5;
84:   }
85:}

procedure modify_cycles() is then called from reading and writing into file:
Code: Select all
644:   case 0x3f:      /* READ Read from file or device */
645:      {
646:         Bit16u toread=reg_cx;
647:         dos.echo=true;
648:         if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) {
649:            MEM_BlockWrite(SegPhys(ds)+reg_dx,dos_copybuf,toread);
650:            reg_ax=toread;
651:            CALLBACK_SCF(false);
652:         } else {
653:            reg_ax=dos.errorcode;
654:            CALLBACK_SCF(true);
655:         }
656:         modify_cycles(reg_ax);
657:         dos.echo=false;
658:         break;
659:      }

Unfortunately, I can't figure out how it works. I/O read and write is definitley slower with modify_cycles (respectively disk I/O with DATA_TRANSFERS_TAKE_CYCLES 0 is fast as a lightning on modern PC) but it is still not enough. Even if I just try to leave CPU_Cycles = 5; there hardcoded.
I did found a way, which is SDL_Delay:
Code: Select all
77: static inline void modify_cycles(Bits value) {
78:   SDL_Delay(10);
79:   if((10*value+5) < CPU_Cycles) {
80:      CPU_Cycles -= 10*value;
81:  ....

This works how anticipated. But it is not correct way how to delay execution. Entire DosBox app is delayed (including drawing functions, recording, etc.), not just execution of virtual machine.

So question follows: Which is proper way how to slow down or delay execution of core (VM?) in DosBox? Lets say in order hundreds of milliseconds or even whole second, not just a few cycles. Just so I can emulate seek times of old HDD or floppy disks.
User avatar
Grunt
Newbie
 
Posts: 3
Joined: 2019-7-05 @ 17:19
Location: Europe

Re: I/O delay

Postby Qbix » 2019-7-09 @ 10:25

Not a clear answer for you, as I have stumbled with it a few times a well.
But take a look on how BEEP is implemented or int14_wait.
That shows a way to pause the system without blocking the entire machine, but it is not really ideal.
Water flows down the stream
How to ask questions the smart way!
User avatar
Qbix
DOSBox Author
 
Posts: 10873
Joined: 2002-11-27 @ 14:50
Location: Fryslan

Re: I/O delay

Postby Grunt » 2019-7-09 @ 18:11

Ok, so answer is CALLBACK_Idle();. Now it is not exactly how do I remember it, it's even better:
Image

It is perfect. Thanks a lot.
Attachments
doom.gif
Last edited by Grunt on 2019-7-13 @ 13:53, edited 1 time in total.
User avatar
Grunt
Newbie
 
Posts: 3
Joined: 2019-7-05 @ 17:19
Location: Europe

Re: I/O delay

Postby Qbix » 2019-7-09 @ 20:40

what did you end up using ? how many milliseconds ?
Water flows down the stream
How to ask questions the smart way!
User avatar
Qbix
DOSBox Author
 
Posts: 10873
Joined: 2002-11-27 @ 14:50
Location: Fryslan

Re: I/O delay

Postby Grunt » 2019-7-13 @ 16:42

Just a random number of calls for given cycle speed:

Code: Select all
static inline void modify_cycles(Bits value) {
   int i;
   

   for (i=0;i<80;i++)
     CALLBACK_Idle();
}

  • i<10 - too little
  • i<100 - too much
  • i between 40 and 80 - just fine for me.
Only as I said, some of the games uses either case 0x3f: /* READ Read from file or device */ or case 0x40: /* WRITE Write to file or device */ while writing text on screen or somehow else end up in modify_cycles() and they shouldn't. Vanilla DOOM for example uses direct writing on screen and works just fine (modify_cycle() is used only for real disk I/O - notice the flickering floppy disk):
Image

There is no reason to require some milliseconds anyway. CALLBACK_Idle() stalls execution for pretty long to require accuracy in order of milliseconds.

Only except...are you sure CALLBACK_Idle is the right guy for the job?
Code: Select all
void CALLBACK_Idle(void) {
[u]/* this makes the cpu execute instructions to handle irq's and then come back */[/u]
   Bitu oldIF=GETFLAG(IF);
   SETFLAGBIT(IF,true);
   Bit16u oldcs=SegValue(cs);
   Bit32u oldeip=reg_eip;
   SegSet16(cs,CB_SEG);
   reg_eip=CB_SOFFSET+call_idle*CB_SIZE;
   DOSBOX_RunMachine();
   reg_eip=oldeip;
   SegSet16(cs,oldcs);
   SETFLAGBIT(IF,oldIF);
   if (!CPU_CycleAutoAdjust && CPU_Cycles>0)
      CPU_Cycles=0;
}


I'm not sure.
Attachments
output.gif
User avatar
Grunt
Newbie
 
Posts: 3
Joined: 2019-7-05 @ 17:19
Location: Europe


Return to DOSBox Development

Who is online

Users browsing this forum: No registered users and 1 guest