Subject: Priority and speed (Long...)
To: None <port-i386@netbsd.org>
From: Grant Stockly <gussie@stockly.com>
List: port-i386
Date: 06/17/1999 00:23:02
I've got a little problem.  I've written two different software programs.

One compiles for DOS, one on a i386 BSD machine (and I don't know what else).

I'm having a little problem with the BSD machine.  The programs I've
written stream data 8bits at a time through the parallel port at 16kbytes/s
-EXACTLY-.  The computer sends another byte when the BUSY line physically
goes high (from outside the computer) [computer thinks its low].

So, at 128000 wires a second, the 486DX20 dies a very quick death.

Stats:

Computers running PASCAL DOS program:
486 SX 16 - Plays from ram at full speed, skips when HD read.
486 SX 33 - Plays from ram at full speed, skips every 5 HD access (HD
access every second)
486 DX 120 - Plays from ram at full speed, skips every 20 to 3 seconds (it
is a strange computer.  Today the primary IDE bus stopped working.  :\  )
PII 200MHz - Plays full speed from both ram and HD.  works like a charm.

Computer running C DOS program:
486 DX 20 - Plays from ram at 1/7th full speed, doesn't ever play when HD
accessed.

I'm not about to beleive that a DOS box running a Pascal program is faster
than a UNIX box.

Some things that you might find interesting:
UID of app: 8065
PRI of app: 52-64 (it was changing constantly!)
RAM used: 423k (ram buffer...)
CPU used: 92%

I'm guessing there might be a way to set priority of a program?  I'd like
to force the program to use the best priority available.  I don't care
about network access or any other server tasks that might be setup.  I'm
also wondering if there is a way to read a file in the background.  Kind of
like a circular buffer.  I'd like to be able to play from a buffer [a], and
while streaming that buffer it will fill buffer [b].

Thanks for your time,
Grant

Pascal code that runs on DOS machines: (UNIX code futher down...)

program mp_play;
uses crt,dos;


const lpt_data = $278;
      lpt_ctrl = lpt_data+1;

const max_block_size =16*1024;
      BUSY = 128;
      INIT = 4;
      STROBE = 1;

type TArray = array[0..max_block_size-1] of byte;
     PArray = ^TArray;

procedure PlayByte(b:byte);
VAR ctrl : Byte;
Begin
asm
   cli;
end;
     while (port[lpt_ctrl] and BUSY)=BUSY do;
     port[lpt_data] := b;
     ctrl := port[lpt_ctrl+1];
     port[lpt_ctrl+1] := ctrl OR 1;   { STROBE  }
     while (port[lpt_ctrl] and BUSY)<>BUSY do; { processing...}
     port[lpt_ctrl+1] := ctrl AND ($e); { /Strobe }
asm
   sti;
end;
End;

procedure PlayBuffer(P:PArray;size:word);
Var i : word;
    b : byte;
 ctrl : Byte;
Begin
     For i := 0 to size-1 do
     begin
{          PlayByte(p^[i-1]);}
     asm
{        cli;}
     end;

                while (port[lpt_ctrl] and BUSY)=BUSY do;
                port[lpt_data] := p^[i];
                ctrl := port[lpt_ctrl+1];
                port[lpt_ctrl+1] := ctrl OR 1;   { STROBE  }
                while (port[lpt_ctrl] and BUSY)<>BUSY do; { processing...}
                port[lpt_ctrl+1] := ctrl AND ($e); { /Strobe }
     asm
        sti;
     end;
     end;
End;


procedure play_mp3(name : String);
VAR Buf : PArray;
    f : File;
    result : word;
    i,l : longint;
    h0,h1,m0,m1,s0,s1,hs0,hs1:Word;
    t0,t1:Extended;
begin
     port[lpt_ctrl+1] := port[lpt_ctrl+1] OR INIT;
     delay(100);
     GetMem(Buf,SizeOf(Tarray));     { Get memory }
     {$i-}
     Assign(f,name);
     Reset(f,1);
     {$i+}
     if ioresult=0 Then Begin
        l := filesize(f) div max_block_size;
        i := 0;
        GetTime(h0,m0,s0,hs0);
        t0 := s0+m0*60;
        t1 := t0;
        Repeat
              write('Playing block ',i,' of ',l+1,' kB/s:
',(i*max_block_size*8)/(t1-t0+1):10:10,'     ',#13);
              inc(i);
              BlockRead(f,buf^,max_block_size,result);
              PlayBuffer(buf,result);
              GetTime(h1,m1,s1,hs1);
              t1 := s1+m1*60;

        until eof(f) or keypressed or (result<>max_block_size);
        Close(f);
     end else writeln('File error!');
     FreeMem(Buf,SizeOf(Tarray));     { release memory }
{     port[lpt_ctrl+1] := port[lpt_ctrl+1] AND ($F-INIT);}
end;

begin
     clrscr;
     Writeln('Playing file:'+paramstr(1));
     repeat
           play_mp3(paramstr(1));
     until keypressed;
end.


C code running on UNIX:

#include <stdio.h>
#include <err.h>

#include <sys/types.h>

#include <machine/pio.h>
#include <machine/sysarch.h>

#define	DATA	0x378
#define	STATUS	0x378+1
#define	CONTROL	0x378+2

#define	BUSYo	0x80
#define	STROBEo	0x01
#define	BUSYa	0x7F
#define	STROBEa	0xFE

#define mp3_second 128000
#define file_second mp3_second


static inline void
setaccess(u_long * map, u_int bit, int allow)
{
	u_int           word;
	u_int           shift;
	u_long          mask;

	word = bit / 32;
	shift = bit - (word * 32);

	mask = 0x000000001 << shift;
	if (allow)
		map[word] &= ~mask;
	else
		map[word] |= mask;
}

int
main(int argc, char **argv)
{
	u_long          iomap[32];
	u_long		i;

        FILE    *mpeg_file;
        u_long  filesize;
        u_long  curread;
        char    mpeg_storage[file_second];
        int     stop;
        char    *namefile;


        if( (mpeg_file = fopen("./sample.file", "rb")) == NULL) {
                printf("Error reading %s!\n", namefile);
                exit(1);
        };

        fseek(mpeg_file, 0, SEEK_SET);

        filesize = 0;
        curread = 0;
	stop = 0;


	if (i386_get_ioperm(iomap) == -1)
		errx(1, "i386_get_ioperm failed");


	setaccess(iomap, CONTROL, 1);
	setaccess(iomap, STATUS, 1);
	setaccess(iomap, DATA, 1);

	if (i386_set_ioperm(iomap) == -1)
		errx(1, "i386_set_ioperm failed");

	do {
		curread = fread(mpeg_storage, 1, file_second, mpeg_file);
		filesize = filesize + curread;
		printf("Played %d bytes\n", filesize);
		if ( curread < file_second ) {
			stop = 1;
		};

		i = 0;

		do {
			while((inb(STATUS) & BUSYo) == BUSYo);
			outb(DATA, mpeg_storage[i]);
			outb(CONTROL, (inb(CONTROL) | STROBEo));
			while((inb(STATUS) & BUSYo) != BUSYo);
			outb(CONTROL, (inb(CONTROL) & STROBEa));
			i++;
		} while( i != curread ) ;

	} while( stop != 1 );

	return(1);


};