SWAGOLX.EXE (c) 1993 GDSOFT ALL RIGHTS RESERVED 00027 HARDWARE DETECTION 1 05-28-9313:48ALL SWAG SUPPORT TEAM Write to TWO Monitors IMPORT 9 └╫å# {π> Hi I am looking For some help on use 2 monitors at the same time... 1π> is mono and the other is vga. I would like to just post a certainπ> screen on the mono and leave the vga like normal..ππVGA Text mode memory begins at $b800, VGA Graphics memory at $A000, andπMDA/Herc memory begins at $b000. If you plan on running Text and Text,πtry something like this:π}πTypeπ WhichMonitor = (MDA, VGA);ππProcedure ChangeCel (Row, Column, Foreground, Background, Character : Byte;π Which : WhichMonitor);πVarπ Point : Word;πbeginπ If Which = MDA thenπ Point := $b000π elseπ Point := $b800;π MemW[Point : (Row - 1) * 160 + Col * 2] :=π (Foreground + Background * 16) * 256 + Character;π end;π{πOf course, there are more optimized ways to do this, but this shouldπportray the basic concept. Herc Graphics and VGA Graphics would beπdone in much the same manner, but I don't have an Herc With my VGA toπcheck it.π} 2 05-28-9313:48ALL SWAG SUPPORT TEAM ALOCSIZE.PAS IMPORT 21 └╫┬y *--* 03-31-93 - 21:47:03 *--*π/. Date: 03-30-93 (23:45) Number: 24023 of 24035π To: PEDRO PACHECO Refer#: 23957πFrom: ERIC LU Read: NOπSubj: allocation Units Status: PUBLIC MESSAGEπConf: R-TP (552) Read Type: GENERAL (A) (+)ππPP>> Is there any way to find (in Pascal) what's de size of each allocation uniπPP>> in a Hard drive?ππPedro,π See if the following is what you wanted...ππ-------------------------------- Cut ----------------------------------ππProgram Int21_36;πUses Crt,Dos;πProcedure DiskfreeSpace( DriveCode: Byte);πVarπ Regs: Registers;π SectorsPerCluster,π AvailableClusters,π BytesPerSector,π ClustersPerDrive,π(63 min left), (H)elp, More? AllocationSize,π Capacity,π Free: LongInt;πbeginπ Regs.AH := $36;π Regs.DL := DriveCode;π MSDos(Regs);ππ {************* Obtaining Infos ******************}π SectorsPerCLuster:= Regs.AX;π AvailableClusters:= Regs.BX;π BytesPerSEctor := Regs.CX;π ClustersPerDrive := Regs.DX;ππ {************* Calculations ********************)π AllocationSize := BytesPerSector * SectorsPerCluster;π Capacity := SectorsPerCluster * BytesPerSector * ClustersPerDrive;π Free := SectorsPerCLuster * AvailableClusters * BytesPerSector;ππ {************* Display *************************}π Writeln(' Sectors Per Cluster = ',SectorsPerCluster:15,'');π Writeln(' Available Clusters = ',AvailableClusters:15,'');π Writeln(' Bytes Per Sector = ',BytesPerSector:15,'');π(63 min left), (H)elp, More? Writeln(' Clusters Per Drive = ',ClustersPerDrive:15,'');π Writeln(' Allocation Size = ',AllocationSize:15,' Bytes');π Writeln(' Drive Capacity = ',Capacity:15,' Bytes');π Writeln(' Free Space = ',Free:15,' Bytes');πend;ππbeginπ ClrScr;π DiskFreeSpace(0); {Get Current Drive Info}π readln;πend.πππ----------------------------- Cut ----------------------------------ππ The above should be ready to run as I have tested on my computer..π It's got more infos.. I was learning it as I was typing it in so Iπ made it more than what you need.π hope this is what you wanted to know...ππ Ericππ---π(63 min left), (H)elp, More? ■ OLX 2.1 TD ■ It's only a hobby ... only a hobby ... only aπ * Casino Bulletin Board * Hammonton/Atlantic City NJ U.S.A. 1-609-561-3377π * PostLink(tm) v1.05 CASINO (#18) : RelayNet(tm)ππ(63 min left), (H)elp, end of Message Command? 3 05-28-9313:48ALL SWAG SUPPORT TEAM Determine Cluster Size IMPORT 5 └╫8∩ {π> Is there any way to find the size of each allocation Unit in a Hard drive?π}ππUses Dos;ππFunction clustsize (drive : Byte) : Word;πVarπ regs : Registers;πbeginπ regs.cx := 0; {set For error-checking just to be sure}π regs.ax := $3600; {get free space}π regs.dx := drive; {0=current, 1=a:, 2=b:, etc.}π msDos (regs);π clustsize := regs.ax * regs.cx; {cluster size!}πend;ππbeginπ Writeln(ClustSize(0));πend. 4 05-28-9313:48ALL SWAG SUPPORT TEAM CPU-ID.PAS IMPORT 12 └╫m╔ {π> How do i get info about witch CPU it is in the current computer??π}ππ{$F+}ππConstπ CPU_Type : Array[1..4] of String[5] = ('8086', '80286', '80386', '80486');π Cpu8086 = 1;π Cpu80286 = 2;π Cpu80386 = 3;π Cpu80486 = 4;πVarπ Result : Byte;πππFunction GetCPU_Type: Byte; Assembler;ππAsmπ MOV DX,Cpu8086π PUSH SPπ POP AXπ CMP SP,AXπ JNE @OUTπ MOV DX, Cpu80286π PUSHFπ POP AXπ or AX,4000hπ PUSH AXπ POPFπ PUSHFπ POP AXπ TEST AX,4000hπ JE @OUTπ MOV DX, Cpu80386π {"DB 66h" indicates '386 extended instruction}π DB 66h; MOV BX, SP {MOV EBX, ESP}π DB 66h, 83h, 0E4h, 0FCh {AND ESP, FFFC}π DB 66h; PUSHF {PUSHFD}π DB 66h; POP AX {POP EAX}π DB 66h; MOV CX, AX {MOV ECX, EAX}π DB 66h, 35h, 00hπ DB 00h, 04h, 00 {XOR EAX, 00040000}π DB 66h; PUSH AX {PUSH EAX}π DB 66h; POPF {POPFD}π DB 66h; PUSHF {PUSHFD}π DB 66h; POP AX {POP EAX}π DB 66h, 25h, 00hπ DB 00h, 04h, 00h {AND EAX, 00040000}π DB 66h, 81h, 0E1h, 00hπ DB 00h, 04h, 00h {AND ECX, 00040000}π DB 66h; CMP AX, CX {CMP EAX, ECX}π JE @Not486π MOV DX, Cpu80486π@Not486:π DB 66h; PUSH CX {PUSH EXC}π DB 66h; POPF {POPFD}π DB 66h; MOV SP, BX {MOV ESP, EBX}π@Out:π MOV AX, DXπend;ππbeginπ Result := GetCPU_Type;π Writeln(Result);πend.π 5 05-28-9313:48ALL SWAG SUPPORT TEAM Determine CPU Speed IMPORT 13 └╫Z {π· Subject: How to determine mhz using TP6.0...ππIt seems to work pretty well, but on a 486/33DX it gave inacurate results...π}ππProgram CpuSpeed;πUsesπ Crt;πVarπ Speed, DelayCalibrate : Word;πConstπ Offset = 9; { For TP 4.0, it should be 16 }πππProcedure WaitForFloppy;πVarπ tickTil : LongInt;π TimerTicks : LongInt Absolute $40 : $6C;π motorStatus : Byte Absolute $40 : $3F;πbeginπ if MotorStatus and $F > 0 thenπ beginπ WriteLn('Loading...');π TickTil := TimerTicks + 91;π {There are $17FE80 ticks in a day}π if TickTil > $17FE80 thenπ Dec(TickTil, $17FE80);π Repeat Until (MotorStatus and $F = 0) or (TimerTicks >= TickTil);π end;πend;ππbeginπ WaitForFloppy;π DelayCalibrate := MemW[Seg(CheckSnow): Ofs(CheckSnow)+Offset];π WriteLn('Delay calibration value is ', DelayCalibrate);π Speed := ((LongInt(1000) * DelayCalibrate) + 110970) div 438;π Write('Calculated speed: ', Speed div 100,'.');π WriteLn((speed div 10) MOD 10, speed MOD 10);π Write('CPU speed is probably ');π Case Speed OFπ 0..499 : WriteLn('4.77MHz or below');π 500..699 : WriteLn('6MHz');π 700..899 : WriteLn('8MHz');π 900..1099 : WriteLn('10MHz');π 1100..1399 : WriteLn('12MHz');π 1400..1799 : WriteLn('16MHz');π 1800..2199 : WriteLn('20MHz');π 2200..2699 : WriteLn('25MHz');π 2700..3599 : WriteLn('30MHz');π ELSEπ WriteLn('30MHz or MORE!');π end;πend.π 6 05-28-9313:48ALL SWAG SUPPORT TEAM FLOPSIZE.PAS IMPORT 10 └╫1 {π>Does anybody know how to determine the size of a disk drive. I meanπ>whether it is a 360 K drive or 720 K, 1.4 M or 1.2 M drive. I'mπ>working on a Program which has the ability to Format diskettes andπ>I want it to be able to come up With the size of a disk drive as aπ>default. I have looked at the equipment flag in the BIOS and theπ>only thing I can get out of that is the Type of a disk drive not theπ>size.π}πFunction VarCMOS(i : Byte) : Byte ;πbeginπ port[$70]:=i;π VarCMOS:=port[$71]πend;ππVar b : Byte ;ππbeginπ b:=VarCMOS($10);π if b and $f0<>0 thenπ beginπ Write('Drive A: = ');π Case (b and $f0) shr 4 ofπ 1 : Write('5" 360 Ko');π 2 : Write('5" 1,2 Mo');π 3 : Write('3" 720 Ko');π 4 : Write('3" 1,44 Mo')π end;π end;π if b and $f<>0 thenπ beginπ Write(', B: = ');π Case b and $f ofπ 1 : Writeln('5" 360 Ko');π 2 : Writeln('5" 1,2 Mo');π 3 : Writeln('3" 720 Ko');π 4 : Writeln('3" 1,44 Mo')π end;π end else WriteLn ;πend.π 7 05-28-9313:48ALL SWAG SUPPORT TEAM LPT-ADDR.PAS IMPORT 5 └╫└' {πOr better yet, the BIOS stores the addresses of the parallel Interfacesπon the system at memory location $0040:$0008. There are four Wordsπhere, allowing up to 4 parallel devices.π-Brian Papeπ}πVarπ i : Byte;π par : Array[1..4] of Word;πbeginπ For i := 1 to 4 doπ beginπ par[i] := Word(ptr($0040, $0008 + (i - 1) * 2)^);π If Par[i] = 0 thenπ Writeln('Not Found')π elseπ Writeln(Par[i]);π end;πend.πππ 8 05-28-9313:48ALL SWAG SUPPORT TEAM SCSICODE.PAS IMPORT 30 └╫Hv {π > I am trying to issue an SCSI START/StoP Unit via Adaptec's ASPI SCSIπ > manager and an 1542B host adaptor. This is For an application I amπ > writing in BP. Adaptec is of no help. if anyone here has anyπ > commentsπ > or suggestions please respond in this Forum.π}ππUnit Aspi;ππ{ I/O Error reporting:ππ AspiSenseKey is the primary source of error inFormation.ππ 0: I/O Complete.π Warnings (Filemark, Short block, etc) may be posted in Sense.ππ 1-E: Error occured.π Examine SRBStat, HostStat, TargStat, Sense For details.ππ F: Severe error detected, no SCSI info available.ππ -------------------------------------------------------------------- }ππInterfaceππConstπ SrbIn = $08;π SRBOut = $10;π SRBNone = $18;π AspiPtr: Pointer = Nil;πππTypeπ AspiSrb = Recordπ SrbCmd: Byte;π SrbStat: Byte;π SrbHost: Byte;π SrbReqFlags: Byte;π SrbHdrFill: LongInt;π Case Integer ofπ 2: (Srb2TargetID: Byte;π Srb2LUN: Byte;π Srb2DataLen: LongInt;π Srb2SenseLen: Byte;π Srb2DataPtr: Pointer;π Srb2LinkPtr: Pointer;π Srb2CDBLen: Byte;π Srb2HAStat: Byte;π Srb2TargStat: Byte;π Srb2PostAddr: Pointer;π Srb2Filler: Array [1..34] of Byte;π { Sense data follows CDB }π Srb2CDB: Array [0..50] of Byte);π 1: (Srb1TargetID: Byte;π Srb1LUN: Byte;π Srb1DevType: Byte);π 0: (Srb0Cnt: Byte;π Srb0TargetID: Byte;π Srb0MgrID: Array [1..16] of Char;π Srb0HostID: Array [1..16] of Char;π Srb0HostParm: Array [1..16] of Char);π end;ππVarπ AspiSRBStat: Byte;π AspiHostStat: Byte;π AspiTargStat: Byte;π AspiSenseKey: Byte;π AspiSense: Array [0..17] of Byte;π AspiSenseCode: Word;ππFunction AspiOpen: Integer;ππProcedure AspiCall (Var SRB: AspiSrb);π{ Call ASPI Handler With SRB }πInline ($FF/$1E/>AspiPtr/π $58/$58);ππProcedure AspiWait (Var SRB: AspiSrb);ππFunction AspiClose: Integer;ππImplementationππUses Dos;ππProcedure AspiWait (Var SRB: AspiSRB);π{ Call ASPI Handler With SRB and wait For Completion }πbeginπ if AspiPtr = Nilπ then beginπ AspiSenseKey := $0F;π Exit;π end;π With Srb do beginπ SrbStat := 0;π AspiCall (Srb);π While SrbStat = 0 do ;π AspiSrbStat := SrbStat;π AspiHostStat := Srb2HAStat;π AspiTargStat := Srb2TargStat;π AspiSenseKey := 0;π FillChar (AspiSense, Sizeof (AspiSense), #0);π Move (Srb2CDB [Srb2CDBLen], AspiSense, Sizeof (AspiSense));π AspiSenseKey := AspiSense[2] and $0F;π AspiSenseCode := (AspiSense [12] SHL 8) or AspiSense [13];π end;π end;ππFunction AspiOpen: Integer;πConstπ AspiName: Array [1..9] of Char = 'SCSIMGR$'#0;πVarπ R: Registers;π AspiHan: Word;πbeginπ With R do beginπ { Assume failure }π AspiOpen := -1;π AspiPtr := Nil;ππ { Open ASPI device driver }π AX := $3D00;π DS := Seg (AspiName[1]);π DX := ofs (AspiName[1]);π MSDos (R);π if odd (Flags)π then Exit;π AspiHan := AX;ππ { Do IOCtl Read to get Pointer to ASPI handler }π AX := $4402;π BX := AspiHan;π CX := 4;π DS := Seg (AspiPtr);π DX := ofs (AspiPtr);π MSDos (R);π if Odd (flags)π then Exit;ππ { Close device driver }π AX := $3E00;π BX := AspiHan;π MsDos (R);π if Odd (Flags)π then Exit;π end;ππ { Indicate success and Exit }π AspiOpen := 0;π end { AspiOpen };ππFunction AspiClose: Integer;πbeginπ AspiClose := 0;πend { AspiClose };ππend.π 9 05-28-9313:48ALL SWAG SUPPORT TEAM SECTORIO.PAS IMPORT 65 └╫x {... so there I was, sitting in a bar when a known C Programmer }π{comes up to me and sniggers "still doing it in Pascal eh?" }π{"Yup" I replied, and tossed the bartender another hundred. }π{"Yeah well, when you're ready For a Real language, only C has }π{all the aces." }π{I'm a Pascal Programmer. I don't have to take that. "Such as?"}π{I hoped he'd bite and he did. }π{"Such as disk sector reading and writing For starters." }π{"Well I hope you're not bluffin', 'cause here's a trick that }π{I'll bet you ain't covered." }π{I pulled it out With a swish and laid it on the table. "Even }π{provides support For >32M volumes, which the C run-time library }π{manual Forgets to tell you it won't do." }π{"Huh? Where?" }π{"Right here" I said. "Just where it says... }ππProgram AbsReadTest;ππ{This Program demonstrates a C-style absread and absWrite For TP.}π{As is, it reads the boot sector off drive A:, and optionally }π{Writes it out to the very last sector on drive A: (assumes 1.2Meg}π{This Program IS dangerous, and is released to the public domain.}π{I take no responsibility For use or misuse, deliberate or }π{accidental, of this Program or any Program which Uses the }π{techniques described herein. }ππ{Author: Mitch Davis 3:634/384.6 +61-3-890-2062 v1.0 28-Jun-92. }ππVar bp:Pointer; {Will point to the buffer For the sector data}ππFunction absread (drive:Char; nsects:Word; lsect:Word; buffer:Pointer):Boolean;ππ{Works just like the C runtime one- including being restricted to 32M volumes!}ππ{drive is a Character, nsects is the number of sectors, and lsect is the first}π{sector. buffer points to the buffer you'd like filled from disk. Function }π{returns True if there was an error, or False if all went well. }ππVar kludgebuff:Array [0..$1f] of Byte; {Read Ralf Brown's interrupt listing}π kludgePtr:Pointer; {Int 25h - ES:[BP+1E] may change }ππbeginπ kludgePtr := @kludgebuff;π absread := True;π if drive < 'A' then Exit;π if drive > 'Z' then Exit;π Asmπ push esπ push bpπ push diπ les di, kludgePtrπ mov al, drive { Gets the passed parameter. }π and al, 1fh { Cvt from ASCII to drive num }π dec al { Adjust because A: is drive 0 }π mov cx, nsects { number of sectors to read }π mov dx, lsect { starting at sector.. }π push dsπ lds bx, buffer { Get the address of the buffer }π mov bp, diπ push siπ int 25h { Do the drive read. }π pop si { Remove the flags int 25h leaves on stack}π pop siπ pop dsπ pop diπ pop bpπ pop esπ jc @1π mov ah, 0 { No errors, so set Function to False }π @1:π mov @result, ahπ end;πend;ππFunction absWriteπ (drive:Char; nsects:Word; lsect:Word; buffer:Pointer):Boolean;ππ{Works just like the C one - including being restricted to 32M volumes!}ππ{drive is a Character, nsects is the number of sectors, and lsect is the first}π{sector. buffer points to the buffer you'd like filled from disk. Function }π{returns True if there was an error, or False if all went well. }ππVar kludgebuff:Array [0..$1f] of Byte;π kludgePtr:Pointer;ππbeginπ kludgePtr := @kludgebuff;π absWrite := True;π if drive < 'A' then Exit;π if drive > 'Z' then Exit;π Asmπ push esπ push bpπ push diπ les di, kludgePtrπ mov al, drive { Gets the passed parameter. }π and al, 1fh { Cvt from ASCII to drive num }π dec al { Adjust because A: is drive 0 }π mov cx, nsects { number of sectors to Write }π mov dx, lsect { starting at sector.. }π push dsπ lds bx, buffer { Get the address of the buffer }π mov bp, diπ push siπ int 26h { Do the drive Write. }π pop si { Remove the flags int 26h leaves on stack}π pop siπ pop dsπ pop diπ pop bpπ pop esπ jc @1π mov ah, 0π @1:π mov @result, ahπ end;πend;ππFunction absLread (drive:Char; nsects:Word; lsect:LongInt;πbuffer:Pointer):Boolean;ππ{This Function reads sectors on disks which have the >32M style made popular}π{by Compaq Dos 3.31, MS-Dos 4+ and DR-Dos 5+. }ππVar packet:Array [0..9] of Byte; {disk request packet - see Ralf Brown's ints}ππbeginπ absLread := True;π if drive < 'A' then Exit;π if drive > 'Z' then Exit;π Asmπ mov ax, Word ptr lsect {Get the LSB of the start sector}π mov Word ptr packet[0], ax {Store it in the packet }π mov ax, Word ptr lsect + 2 {Get the MSB of the start sector}π mov Word ptr packet[2], ax {Store this one too. }π mov ax, nsects {How many sectors to read }π mov Word ptr packet[4], axπ {Insert the Pointer to the data buffer into the packet}π push bp ; push dsπ lds dx, buffer { Get the address of the buffer }π mov Word ptr packet[6], dxπ mov dx, dsπ mov Word ptr packet[8], dxπ mov al, drive { Gets the passed parameter. }π and al, 1fh { Cvt from ASCII to drive num }π dec al { Adjust because A: is drive 0 }π int 25h { Do the drive read. }π pop si { Remove the flags int 25h leaves on stack}π pop dsπ pop bpπ jc @1π mov ah, 0π @1:π mov @result, ahπ end;πend;ππFunction absLWrite (drive:Char; nsects:Word; lsect:LongInt;πbuffer:Pointer):Boolean;ππ{This Function Writes sectors on disks which have the >32M style made popular}π{by Compaq Dos 3.31, MS-Dos 4+ and DR-Dos 5+. }ππVar packet:Array [0..9] of Byte;ππbeginπ absLWrite := True;π if drive < 'A' then Exit;π if drive > 'Z' then Exit;π Asmπ mov ax, Word ptr lsectπ mov Word ptr packet[0], axπ mov ax, Word ptr lsect + 2π mov Word ptr packet[2], axπ mov ax, nsectsπ mov Word ptr packet[4], axπ push bp ; push dsπ lds dx, bufferπ mov Word ptr packet[6], dxπ mov dx, dsπ mov Word ptr packet[8], dxπ mov al, drive { Gets the passed parameter. }π and al, 1fh { Cvt from ASCII to drive num }π dec al { Adjust because A: is drive 0 }π int 26h { Do the drive Write. }π pop si { Remove the flags int 26h leaves on stack}π pop dsπ pop bpπ jc @1π mov ah, 0π @1:π mov @result, ahπ end;πend;ππFunction LongNeeded (drive:Char):Boolean;ππ{This Function returns True or False depending on whether the long versions}π{of absread/absWrite needed to be invoked; that is, it's a drive Formatted }π{in the Dos 4+ >32M style. }π{I strongly suggest you see Ralf Brown's interrupt listing For int21h subfs}π{440d and 53 - they'll tell you all you know to understand the guts of this}π{Function. }ππLabel Escape;ππVar drivestats:Array [0..31] of Byte;ππbeginπ LongNeeded := False;π if drive < 'A' then Exit;π if drive > 'Z' then Exit;π Asmπ push dsπ mov dx, ssπ mov ds, dxπ lea dx, drivestatsπ mov bl, drive { Gets the passed parameter. }π and bl, 1fh { Cvt from ASCII to drive num }π mov ax, 440Dhπ mov cx, 0860hπ int 21hπ jc Escapeπ mov ax, Word ptr drivestats[0Fh]π or ax, axπ jnz Escapeπ mov @Result, 1π Escape:π pop dsπ end;πend;ππbeginπ getmem (bp,2048);π Writeln (LongNeeded ('A'));π Writeln (LongNeeded ('C'));π Writeln (absread ('A',1,0,bp));π(* Writeln (absWrite ('A',1,2399,bp)); *) {remove the comments at your own}π {risk!!!}π freemem (bp,2048);πend.ππ{So I bought him a drink. The poor guy looked like he needed one....}π 10 05-28-9313:48ALL SWAG SUPPORT TEAM Activate TURBO Speed IMPORT 9 └╫}v { Does anyone out there know how to set the Software Turbo Speed on Motherπ boards without hitting the Turbo Switch or the <Ctrl> <Alt> <-> key toπ slow the system and or Speed it up again? Thanks...π}ππProgram speed;πUses Dos,Crt;ππProcedure do_speed(mode : String);πVarπ reg : Registers;π oldmem : Byte;ππbeginπ oldmem := mem[$40:$17];π if UpCase(mode[1]) = 'N' thenπ beginπ reg.al := 74;π Writeln('Speed set to NorMAL MODE');π end elseπ beginπ reg.al := 78;π Writeln('Speed set to TURBO MODE');π end;π mem[$40:$17] := 140;π reg.ah := $4F;π intr($15,reg);π mem[$40:$17] := oldmem;πend;ππbeginπ if paramcount < 1 thenπ beginπ Writeln(' Speed.exe (c) by Werner Schlagnitweit 2:310/3.0');π Writeln(' This Program should work on all machines which ');π Writeln(' use the CTRL-ALT-+ key to toggle the speed ');π Writeln;π Writeln(' Usage : Speed N For normal NON TURBO mode');π Writeln(' Speed T For normal TURBO mode ');π halt;π end else do_speed(paramstr(1));πend.π 11 08-27-9322:08ALL SWAG SUPPORT TEAM Set the TURBO speed IMPORT 6 └╫ {π Does anyone out there know how to set the Software Turbo Speed on Motherπ boards without hitting the Turbo Switch or the <Ctrl> <Alt> <-> key toπ slow the system and or Speed it up again? Thanks...π}ππUsesπ Dos;ππProcedure SetSpeed(Turbo : Boolean);πVarπ Regs : Registers;π OldMem : Byte;ππbeginπ {OldMem := Mem[$40 : $17];}π If Turbo thenπ Regs.AL := 78π elseπ Regs.AL := 74;ππ {Mem[$40 : $17] := 140;}π Regs.AH := $4F;π Intr($15, Regs);π {Mem[$40 : $17] := OldMem;}πend;ππbeginπ SetSpeed(False);πend.π 12 10-28-9311:29ALL BRUCE LACKLORE CPU Info SWAG9311 87 └╫ Unit CPUInfo;ππ{ Version 1.1.0.Pππ Requires Borland Turbo Pascal version 6.0 or later to compile.π Author: Bruce J. Lackore. Created Saturday, October 9, 1993.π}ππ{$IFDEF Test}π {$A+,B-,D+,F-,G-,I+,L+,O-,R+,S+,V-,X+}π{$ELSE}π {$A+,B-,D-,F-,G-,I-,L-,O-,R-,S-,V-,X+}π{$ENDIF}ππ{ This unit contains a handy gadget for determining the CPU speed. It is NOTπ coded for the Pentium family (if anyone wants to take a shot at it, pleaseπ let me know the results)!π}ππInterfaceππConstπ Cpu8086 = 1;π Cpu80286 = 2;π Cpu80386 = 3;π Cpu80486 = 4;ππFunction WhatCPU: Word;ππ{ This function examines the CPU and returns a number corresponding to theπ CPU type; 1 for 8086, 3 for 80386, etc. This procedure came right out ofπ Neil Rubenking's Turbo Pascal 6.0 Techniques and Utilities (thanx Neil!).π}ππProcedure CPUSpd(Var MHz, KHz: Word);ππ{ This procedure is a ROUGH estimation of how fast the CPU is running inπ MegaHertz. It was adapted from a C program found in the Intel forum ofπ CIS written by Glenn Dill. I had to do some finagling of the original codeπ because C allows for a 32-bit UNSIGNED integer, whereas Pascal allows for aπ 32-bit SIGNED integer (the LongInt), therefore, I was forced to reduce allπ calculations by 10 in order to get it to fit properly.π}ππ{ ************************************************************************** }ππImplementationππFunction WhatCPU; Assembler;ππ Asm { Function WhatCPU }π MOV DX,Cpu8086π PUSH SPπ POP AXπ CMP SP,AXπ JNE @OUTπ MOV DX,Cpu80286π PUSHFπ POP AXπ OR AX,4000hπ PUSH AXπ POPFπ PUSHFπ POP AXπ TEST AX,4000hπ JE @OUTπ MOV DX,Cpu80386 { "DB 66h" makes '386 extended instruction }π DB 66h; MOV BX,SP { MOV EBX,ESP }π DB 66h, 83h, 0E4h, 0FCh { AND ESP,FFFC }π DB 66h; PUSHF { PUSHFD }π DB 66h; POP AX { POP EAX }π DB 66h; MOV CX, AX { MOV ECX,EAX }π DB 66h, 35h, 00hπ DB 00h, 04h, 00 { XOR EAX,00040000 }π DB 66h; PUSH AX { PUSH EAX }π DB 66h; POPF { POPFD }π DB 66h; PUSHF { PUSHFD }π DB 66h; POP AX { POP EAX }π DB 66h, 25h,00hπ DB 00h, 04h,00h { AND EAX,00040000 }π DB 66h, 81h,0E1h,00hπ DB 00h, 04h,00h { AND ECX,00040000 }π DB 66h; CMP AX,CX { CMP EAX,ECX }π JE @Not486π MOV DX, Cpu80486π @Not486:π DB 66h; PUSH CX { PUSH ECX }π DB 66h; POPF { POPFD }π DB 66h; MOV SP, BX { MOV ESP,EBX }π @Out:π MOV AX, DXπ End; { Function WhatCPU }ππProcedure CPUSpd;ππ Constπ Processor_cycles: Array[0..4] of Byte = (165, 165, 25, 103, 42);π { Cycle times of 8086, 80186, 80286, 80386, 80486}ππ { Notice that here I have defined the 8086 as a Processor type of 0 viceπ the returned value of 1 from WhatCPU. Since the original code did notπ distinguish between the 8086 and the 80186, I can get away with this.π }ππ Varπ Ticks,π Cycles,π CPS: LongInt;π Which_CPU: Word;ππ Function i86_to_i286: Word; Assembler;ππ Asm { Function i86_to_i286 }π CLIπ MOV CX,1234π XOR DX,DXπ XOR AX,AXπ MOV AL,$B8π OUT $43,ALπ IN AL,$61π OR AL,1π OUT $61,ALπ XOR AL,ALπ OUT $42,ALπ OUT $42,ALπ XOR AX,AXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IDIV CXπ IN AL,$42π MOV AH,ALπ IN AL,$42π XCHG AL,AHπ NEG AXπ STIπ End; { Function i86_to_i286 }ππ Function i386_to_i486: Word; Assembler;ππ Asm { Function i386_to_i486 }π CLIπ MOV AL,$B8π OUT $43,ALπ IN AL,$61π OR AL,1π OUT $61,ALπ XOR AL,ALπ OUT $42,ALπ OUT $42,ALπ DB 66H,$B8,00h,00h,00h,80h;π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π DB 66H,0FH,$BC,$C8; { BSF ECX,EAX }π IN AL,42Hπ MOV AH,ALπ IN AL,42Hπ XCHG AL,AHπ NEG AXπ STIπ End; { Function i386_to_486 }ππ Begin { Procedure CPUSpd }π Which_CPU := WhatCPU;π If Which_cpu < 3 Thenπ Ticks := i86_to_i286π Elseπ Ticks := i386_to_i486;π Cycles := 20 * Processor_cycles[Which_CPU];π CPS := (Cycles * 119318) Div Ticks;π MHz := CPS Div 100000;π KHz := (CPS Mod 100000 + 500) Div 1000π End; { Procedure CPUSpd }ππEnd. { Unit CPUInfo }ππ{ --------------------- TEST PROGRAM --------------------------}ππProgram CPUSpeed;ππ{ Version 1.0.0.T.ππ Requires Borland Turbo Pascal version 6.0 or later to compile.ππ Author: Bruce J. Lackore. Created Saturday, October 9, 1993.π}ππ{$IFDEF Test}π {$A+,B-,D+,E+,F-,G-,I+,L+,N-,R+,S+,V-,X+}π{$ELSE}π {$A+,B-,D-,E+,F-,G-,I-,L-,N-,R-,S-,V-,X+}π{$ENDIF}ππ{$M 1024, 0, 0}ππUses CPUInfo;ππVarπ MHz,π KHz: Word;ππBegin { Program: Cpuspeed }π CpuSpd(MHz, KHz);π Writeln('The CPU speed is ', MHz, '.', KHz, ' MHz.')πEnd. { Program: Cpuspeed }π 13 11-02-9310:33ALL ERIC SCHILKE PORTS Info SWAG9311 15 └╫ {πERIC SCHILKEππ> I need help in obtaining all pertinent information aboutπ> AuxInPtr and AuxOutPtr, as pertaining to TP 3.0 reservedπ> Words. These Pointers are referencing BIOS entry points.ππThis is from memory, since I don't have the references here, andπit has been a While.... AuxInPtr and AuxOutPtr are Pointersπcontaining the addresses of the respective AuxIn Function andπAuxOut Procedure, which are used (and not available as a standardπFunction/Procedure) by the standard TP3 I/O drivers.ππEach of the I/O possibilities has a corresponding Procedure/Function,πaddress Pointer, and BIOS entry point as follows:ππ Device proc/funct address BIOS entryππ CON:,TRM:,KBD: ConIn:Char; ConInPtr CONINπ CON:,TRM:,KBD: ConOut(Ch:Char); ConOutPtr CONOUTπ LST: LstOut(Ch:Char); LstOutPtr LISTπ AUX: AuxIn:Char; AuxInPtr READERπ AUX: AuxOut(ch:Char); AuxOutPtr PUNCHπ USR: UsrIn:Char; UsrInPtr CONIN ?π USR: UsrOut(ch,Char); UsrOutPtr CONOUT ?ππI'm not sure about the last two entry points. Also, if memoryπserves correctly, there is another Function, ConSt:Boolean, whichπis used by the KeyPressed Function, having a corresponding addressπPointer, ConStPtr, With BIOS entry Const. if you Write your own I/Oπdrivers, you should assign the address of the corresponding driverπFunction or Procedure to the proper Pointer Variable. Your questionπis a bit vague; what specific problems have you encountered? Iπthink that my recollection is accurate; however, my old referencesπare in an attic in Pennsylvania, While I am here in Huntsville,πAlabama. Perhaps someone else could confirm and/or amplify onπthese observations.π}π 14 09-26-9308:48ALL GAYLE DAVIS Determine CPU Type SWAG9311 20 └╫ Unit CPU;ππINTERFACEππTypeπ CpuType = ( cpu8088,π cpu8086,π cpu80286,π cpu80386,π cpu80486,π cpuPentium,π cpuFutureπ );π CpuStrType = String[7];ππFunction GetCpuType : CpuType;π { Returns the currently executing CPU type }ππFunction GetCpuTypeStr : CpuStrType;π { Returns the currently executing CPU type as a string }ππIMPLEMENTATIONππConstπ CpuTypeIdentified : Boolean = False;πVarπ ConfirmedCpuType : CpuType;ππ{$L CPU.OBJ}ππ{$F+}πFunction WhichCPU : CpuType;π { Determines and returns the currently executing CPU type }πEXTERNAL;π{$F-}ππProcedure IdentifyCpuType;π { Handles initialization of CPU type }πBeginπ If Not CpuTypeIdentified Thenπ Beginπ ConfirmedCpuType := WhichCPU;π CpuTypeIdentified := True;π End;πEnd; { Procedure IdentifyCpuType }ππFunction GetCpuType : CpuType;π { Returns the currently executing CPU type }πBeginπ IdentifyCpuType;π GetCpuType := ConfirmedCpuType;πEnd; { Function GetCpuType }ππFunction GetCpuTypeStr : CpuStrType;π { Returns the currently executing CPU type as a string }πBeginπ IdentifyCpuType;π Case ConfirmedCpuType Ofπ cpu8088 : GetCpuTypeStr := '8088';π cpu8086 : GetCpuTypeStr := '8086';π cpu80286 : GetCpuTypeStr := '80286';π cpu80386 : GetCpuTypeStr := '80386';π cpu80486 : GetCpuTypeStr := '80486';π cpuPentium : GetCpuTypeStr := 'Pentium';π cpuFuture : GetCpuTypeStr := 'Future';π End; { Case }πEnd; { Function GetCpuTypeStr }ππEnd.π{ eof CPU.PAS }πππNOTE : Cut the following code to a seperate file, and thenπ USE XX34 to DECODE the block which contains CPU.OBJπ needed with this unit.ππ*XX3401-000399-290893--68--85-63424---------CPU.OBJ--1-OF--1πU+s+14BkRKZYMLBh9Y3HHE466++++-lIRL7WPm--QrBZPK7gNL6U63NZQbBdPqsUAmsmπaMUI+21dBaTF4UlXQ5JdN43nPGt-Iop0W+A+ECZAZU6++4W6+k-+cNGK-U+2Eox2FIKMπ-k-6wk+0+E2WY+w+++26JoV7EoV1I3I+++1xW+E+E86-YO1r++2++-uAm6vMu-k+D+7xπ-SUk+CgFu2Y+D+Bw0iVV+1k2T+DcV++TmtmQKs5XzkxHbNlPUSA+w1D+UTg+w5E0g+8RπkkOAm6v+zPc-+9xM+90EiEA+wufwY70EGd0EWw65ktkD+S1Fq5A3i+A+ul0s+5-EbNlMπUCFki+6+R+3+bQC9y6jQNdlab4NMNUo+++E+NZ-abKOQNZVaeE++-+-o+t0EFqORWyC9πlwBab4NMNcjMNXI++0++NZ-abKOQNZVaIqORNWI++0++Nc5X+++U+4MvkrESY7-ai+2+π+++Dch5coSXFuB5coSXFuB5coSUZ1k11i+E+kumQ-E12GJE-zMc0++-oπ***** END OF XX-BLOCK *****πππ 15 11-02-9305:41ALL KAI ROHRBACHER AT Extended BIOS ?? SWAG9311 16 └╫ {πKAI ROHRBACHERππ As promised, here is some TP-code to check whether your machineπ supports the extended timing services of the AT's-BIOS: if all worksπ fine, the Program should give two beeps, the 2nd exactly 5secs afterπ the 1st one -and then terminate.ππ (To all others reading this: this timing scheme normally worksπ _asynchrone_ to whatever you are doing in the "foreground" Program andπ thus is great For timing events. What's more: the clock has aπ resolution of some microseconds!)π}ππConstπ WaitTime = 5000;πVarπ IsAT,π TimeFlag : Byte;π CycleTime : LongInt;ππFunction AT : Boolean;π{ in: - }π{out: True/False, if the machine is (at least) an AT}πbeginπ AT := MEM[$F000 : $FFFE] = $FC;πend;ππProcedure SetWaitingTime(milliseconds : Word);π{ in: milliseconds = time to wait in ms}π{out: CycleTime := that same value in microseconds}π{ TimeFlag := $80}π{rem: won't work With PC's}πbeginπ TimeFlag := $80;π CycleTime := LongInt(milliseconds) * LongInt(1000);π if (milliseconds <> 0) and AT thenπ IsAT := 0 {yes, use timing mechanism}π elseπ IsAT := $80; {no, don't use that extended service}πend;ππProcedure Wait;πbeginπ Asmπ MOV AL, IsATπ or AL, ALπ JNE @L11π MOV TimeFlag,ALπ MOV DX, Word PTR CycleTimeπ MOV CX, Word PTR CycleTime+2π MOV BX, OFFSET TimeFlagπ MOV AX, DSπ MOV ES, AXπ MOV AX, 8300hπ INT 15hπ @L11:ππ @L10:π MOV AL, TimeFlag {look at bit 7: 1/0 = time over/not over}π and AL, $80π JE @L10π end;πend;ππbeginπ if not AT thenπ beginπ WriteLN('Sorry, this Program requires the extended BIOS-' +π 'services, available on AT''s only!');π Halt(1);π end;π WriteLN('The time between the two beeps should be exactly ', WaitTime,π ' milliseconds!');π Write(#7);π SetWaitingTime(5000);π Wait;π Write(#7);πend.π 16 11-02-9304:59ALL KAI ROHRBACHER Which BIOS SWAG9311 9 └╫ {πKAI ROHRBACHERππ> What bios are you using?πIt's an AMI-BIOS, dated 03-06-1992; but I ran the same code on an oldπTandon-AT (with BIOS from 1987) w/o problems, too!ππ> Do you have any other timing code?πNot at hand; one could reProgram the trigger rate of timer 0 to beπfaster than 1/18.2 sec, but in my experience, this results in evenπmore incompatibilities when interfacing the Unit to others.π}ππFunction BIOScompatible : Boolean;πVarπ Flag : Byte;π p : Pointer;πbeginπ Flag := 0;π p := @Flag;π if AT thenπ Asmπ STIπ xor CX, CXπ MOV DX, 1π LES BX, pπ MOV AX, 8300h {trigger 1 microsecond}π INT 15hπ @L11:π end;π Delay(1); {wait 1 ms:}π BIOScompatible := Flag = $80; {has flag been set?}πend;ππ{π ...results in False For you, I can't do much! However, I'll add theπ above routine to disable the timing mechanism in that Case to preventπ the endless loop, at least.π}π 17 11-02-9316:11ALL LAURENT M. CHARTINIER Quick Reset and BOOT SWAG9311 3 └╫ {Laurent M. CHARTINIER}π{computer do a RESET using a small Pascal routine?}ππProcedure Reboot;πBeginπ Asmπ JMP FFFF:0000π End;πEnd;ππ 18 01-27-9411:55ALL RANDALL WOODMAN CMOS Data SWAG9402 64 └╫ {π» Does anyone know how to get the hard drive type(s) from CMOS ?π» I can't seem to find this information documented anywhere.ππThis is probably a lot more than you are asking for but. . .πNOTE: one function (Long2Str) is not defined in this because it comes fromπa commercial unit. Basically all it does is convert a number to a stringπand return the string.π This code comes from a unit I wrote to get all kinds of nifftyπinformation about your system. I think I included everything you will needπto get it up and running. If you get any strange problems or ones youπcan't seem to resolve, let me know and I'll see if I can pass you the rightπinformation.π}ππUsesπ KMath,π Dos;ππtypeπ String80 = String[80]; { some general purpose string types }π String40 = String[40];π String30 = String[30];π String20 = String[20];π String12 = String[12];π String10 = String[10];π String5 = String[5];ππ CMOSRec = Recordπ Found : Boolean; { was a CMOS found to exist }π CmosDate : String30; { the date found in CMOS }π CmosTime : String30; { the time found in CMOS }π VideoType : String10; { Type of video found in CMOS }π Coproc : Boolean; { does CMOS report a math coprocessor }π FloppyA : String12; { type of floppy drive for A }π FloppyB : String12; { Type of floppy drive for B }π Hard0 : Byte; { Type of hard drive for drive 0 }π Hard1 : Byte; { Type of hard drive for Drive 1 }π ConvenRam : Word; { amount of conventional ram indicated }π ExtendRam : Word; { amount of extended Ram indicated }π checkSum : Boolean; { Did checksum pass }π end; { CMOS Rec }ππconstπ { values of constants for CMOS }π DayName: array[0..7] of string[9] = ('Sunday', 'Monday', 'Tuesday',π 'Wednesday', 'Thursday', 'Friday',π 'Saturday', 'Sunday');π MonthName: array[0..12] of string[9] = ('???', 'January', 'February', 'March',π 'April', 'May', 'June', 'July',π 'August', 'September', 'October',π 'November', 'December');π ScreenName: array[0..3] of string[10] = ('EGA/VGA', 'CGA 40col',π 'CGA 80col', 'Monochrome');π FloppyName: array[0..5] of string[11] = ('none', '5.25" 360K',π '5.25" 1.2M', '3.5" 720K',π '3.5" 1.44M', '3.5" 2.88M');π CMOSport : Byte = $70; { port to access the CMOS }ππ{===========================================================================}πππVARπ Regs : Registers; { General purpose variable to access registers }π CMOS : CMOSRec; { variable to hold CMOS data }ππfunction nocarry : boolean;π{ returns the status of the carry flag }πbeginπ nocarry:=regs.flags and fcarry = $0000πend; {nocarry}ππ{---------------------------------------------------------------------------}ππFunction ByteToWord(ByteA, ByteB : byte) : word;πbeginπ ByteToWord := Word(ByteB) shl 8 + ByteAπend; {cbw}ππ{---------------------------------------------------------------------------}ππFunction BitIsSet(CheckWord : Word; AndValue : Word) : Boolean;π{ returns true if the bit(s) indicated in AndValue are set in CheckByte }πBEGINπ BitIsSet := CheckWord AND AndValue = AndValue;πend;ππ{---------------------------------------------------------------------------}ππFunction ReadCMOS(addr: byte): byte;π{ read a value from the CMOS }πBeginπ if CMOSport = $70 thenπ beginπ inline($FA);π Port[CMOSport] := addr;π readCMOS := Port[CMOSport + 1];π inline($FB)π endπend; {readCMOS}ππ{---------------------------------------------------------------------------}ππfunction addzero(b: byte): string5;πvarπ c2: string[2];πbeginπ Str(b:0, c2);π if b < 10 thenπ c2:='0' + c2;π addzero:=c2πend; {addzero}ππ{---------------------------------------------------------------------------}ππFunction ChangeBCD(b: byte): byte;π{ change a BCD into a byte structure }πBeginπ ChangeBCD:=(b and $0F) + ((b shr 4) * 10)πend; {ChangeBCD}ππ{---------------------------------------------------------------------------}ππFunction GetCMOSDate : String30;π{ gets the date found in the CMOS and returns it in string format }πVARπ Date,π Century,π Year,π Month : Byte;π WorkStr : String30;πBEGINπ WorkStr := '';π date := ChangeBCD(readCMOS(7));π century := ChangeBCD(readCMOS($32));π year := ChangeBCD(readCMOS(9));π month := ChangeBCD(readCMOS(8));π WorkStr := DayName[readCMOS(6)]+', ';π {case country.DateFormat ofπ 0, 3..255 :}π WorkStr := WorkStr + Monthname[month]+' '+IntToStr(date)+', '+IntToStr(century)+addzero(year);π { 1 :π WorkStr := WorkStr + Long2Str(date)+', '+Monthname[month]+' '+Long2Str(century)+addzero(Year);π 2 :π WorkStr := WorkStr + Long2Str(century)+addzero(Year)+', '+Monthname[month]+' '+Long2Str(date);π end; {case}π GetCMosDate := workStr;πend; { GetCMOSDate }ππ{---------------------------------------------------------------------------}ππFunction GetCmosTime : String30;π{ returns the time as found in the CMOS }πVARπ CH : Char;π Hour,π Min,π Sec : Byte;π WorkStr : String30;π IsPM : Boolean;πBEGINπ workStr := '';π hour := ChangeBCD(readCMOS(4));π min := ChangeBCD(readCMOS(2));π sec := ChangeBCD(readCMOS(0));π IsPm := false;π case hour ofπ 0: hour := 12;π 1..11: hour := hour;π 12: IsPM := true;π 13..23: beginπ IsPM := true;π hour := hour - 12π end;π end; {case}π WorkStr := WorkStr + AddZero(hour)+':'+addzero(min)+':'+addzero(sec);π if IsPM thenπ workStr := WorkStr + ' PM'π Elseπ WorkStr := WorkStr + ' AM';π GetCMOSTime := WorkStr;πend; { GetCmosTime }ππ{---------------------------------------------------------------------------}ππFunction GetCmosCheckSum : Boolean;π{ performs checksum on CMOS and returns true if ok }πVARπ CheckSum1,π CheckSum2 : word;π Count : Byte;πBEGINπ checksum1 := 0;π for count := $10 to $2D doπ Inc(checksum1, readCMOS(count));π checksum2 := (word(256) * readCMOS($2E)) + readCMOS($2F);π if checksum1 = checksum2 thenπ GetCmosCheckSum := trueπ elseπ GetCmosCheckSum := false;πend; { GetCmosCheckSum }ππ{---------------------------------------------------------------------------}ππProcedure GetCMos;π{ gets the cmos record if it exist }πVARπ Floppy : Byte;πBEGINπ FillChar(CMOS, SizeOf(CMos), 0);π regs.AH:=$C0;π Intr($15, regs);π if nocarry or (Mem[$F000:$FFFE] <= $FC) thenπ With CMOS DOπ beginπ Found := true;π CMOSDate := GetCMOSDate;π CMOSTime := GetCmosTime;π VideoType := ScreenName[(readCMOS($14) shr 4) and 3];π CoProc := BitIsSet(readCMOS($14), 2);π Floppy := readCMOS($10);π if (Floppy shr 4) < 5 thenπ FloppyA := FloppyName[floppy shr 4]π elseπ FloppyA := 'Unknown '+ Byte2Hex(floppy shr 4);π if (floppy and $0F) < 5 thenπ FloppyB := FloppyName[floppy and $0F]π elseπ FloppyB := 'Unknown '+ Byte2Hex(floppy and $0F);ππ Hard0 := readCMOS($12);π Hard0 := Hard0 shr 4;π Hard1 := ReadCmos($12);π Hard1 := Hard1 and $0F;π if Hard0 = $F thenπ Hard0 := readCMOS($19)π Else Hard0 := $FF; { error }π if Hard1 = $F thenπ Hard1 := readCMOS($1A)π Else Hard1 := $FF;π ConvenRam := word(256) * readCMOS($16) + readCMOS($15); { value in K }π ExtendRam := word(256) * readCMOS($18) + readCMOS($17); { value in K }π CheckSum := GetCmosCheckSum;π endπ elseπ CMOS.Found := false;πend;ππbeginπ GetCmos;π Writeln(CMOS.Found);π Writeln(CMOS.CmosDate);π Writeln(CMOS.CmosTime);π Writeln(CMOS.VideoType);π Writeln(CMOS.Coproc);π Writeln(CMOS.FloppyA);π Writeln(CMOS.FloppyB);π Writeln(CMOS.Hard0);π Writeln(CMOS.Hard1);π Writeln(CMOS.ConvenRam);π Writeln(CMOS.ExtendRam);π Writeln(CMOS.checkSum);πend.π 19 01-27-9411:56ALL ANDREW KEY Color Monitor SWAG9402 7 └╫ {π> I have always addressed $B800 as the screen segment for direct videoπ> writes in text.... Err, umm, does anyone have the code to detect whetherπ> it is $B000 or $B800 (for Herc.'s and the like)...π}ππFunction ColorAdaptor: Boolean; Assembler; {returns TRUE for color monitor}πasmπ int 11 {BIOS call - get equipment list}π and ax, $0030 {mask off all but bits 4 & 5}π xor ax, $0030 {flip bits 4 & 5 - return val is in ax}πend;ππ{πThis function uses a BIOS interrupt to get the equipment list(at $0000:$0410)πas determined at time of power-up. The only problem I can see here is thatπa TRUE(non-zero value in al) will also be returned if no video card wasπdetected at power-up.π} 20 01-27-9411:56ALL DUSTIN NULF CPU Speed SWAG9402 14 └╫ {π>>> How can i determine the machine's CPU clock speed from a TPπ>>> program? An 100% accurate result is not required.ππ>> Use a counter and continually increase it. Check the clock and see howππ> There's a big problem : Newer CPUs are faster in executingπ> this commands and caching really speed's up the timer.π}ππCONSTπ Cpu8086 = 1;π Cpu80286 = 2;π Cpu80386 = 3;π Cpu80486 = 4;ππVARπ CPU : BYTE;πππFUNCTION CPUSpeed : BYTE; Assembler;πAsmπ MOV DX,Cpu8086π PUSH SPπ POP AXπ CMP SP,AXπ JNE @OUTπ MOV DX, Cpu80286π PUSHFππ POP AXπ OR AX,4000hπ PUSH AXπ POPFπ PUSHFπ POP AXπ TEST AX,4000hπ JE @OUTπ MOV DX, Cpu80386π {"DB 66h" indicates '386 extended instruction}π DB 66h; MOV BX, SP {MOV EBX, ESP}π DB 66h, 83h, 0E4h, 0FCh {AND ESP, FFFC}π DB 66h; PUSHF {PUSHFD}π DB 66h; POP AX {POP EAX}π DB 66h; MOV CX, AX {MOV ECX, EAX}π DB 66h, 35h, 00hπ DB 00h, 04h, 00 {XOR EAX, 00040000}π DB 66h; PUSH AX {PUSH EAX}ππ DB 66h; POPF {POPFD}π DB 66h; PUSHF {PUSHFD}π DB 66h; POP AX {POP EAX}π DB 66h, 25h, 00hπ DB 00h, 04h, 00h {AND EAX, 00040000}π DB 66h, 81h, 0E1h, 00hπ DB 00h, 04h, 00h {AND ECX, 00040000}π DB 66h; CMP AX, CX {CMP EAX, ECX}π JE @Not486π MOV DX, Cpu80486π@Not486:π DB 66h; PUSH CX {PUSH EXC}π DB 66h; POPF {POPFD}π DB 66h; MOV SP, BX {MOV ESP, EBX}π@Out:π MOV AX, DXπend;πππbegin { main }πππ Writeln(CPUSpeed); { 1, 2, 3, or 4 is returned; see above consts }πππend.ππ 21 01-27-9411:57ALL WILLIAM PLANKE device Driver Lists SWAG9402 46 └╫ {πI've posted a working util that lists the Device Drivers that are resident inπmemory. It uses the header record to point to the next driver in the chainπand "walks" the memory chain until an offset end flag is reached. Hope youπenjoy it and that it isn't too sloppy. At the end, I have a question thatπneeds to be answered if you're interested....π}ππprogram DevList;ππ{ this program walks the device driver memory chain. Each deviceπ driver points to the next until the ENDFLAG is reached. I useπ the popular undocumented DOS function $52 to jump to the DOSπ "List of Lists" then $22 bytes beyond that, the first device inπ the chain (NUL) can be found.ππ Thanks to Ralf Brown and his valuable MS DOS Interrupts List,π to Timo Salmi, and to the person(?) who wrote the coolπ hex-to-string conversion functions that I use all the time.π}ππ{$M 8192,0,0}ππusesπ DOS;ππtypeπ pstrg = string[9]; { pointer conversion format }ππ Array8C = array [1..8] of char; { for device and file names }ππ DevRec = recordπ NextDev_ofs : word; {pointer to next device header, offset value}π NextDev_seg : word; {pointer to next device header, segment value}π Attributes : word; {Attributes: block or char, IOCTL, etc.}π Strategy : word; {pointer to device strategy routine, offset}π Interrupt : word; {pointer to device interrupt routine, offset}π NameDev : Array8C; {Name if char, or units if block}π end;π DevPtr = ^DevRec;ππ DevFileRec = recordπ FileName : Array8C;π end;π DevFilePtr = ^DevFileRec;ππconstπ LOL_HEADDEV_NUL = $22; { offset from "List of Lists"π to NUL device header }π FNAME = $8;π ENDFLAG = $FFFF;π STDDEVS : array [1..12] of Array8C =π ('NUL ', 'CON ', 'AUX ', 'PRN ',π 'CLOCK$ ', 'COM1 ', 'COM2 ', 'COM3 ',π 'COM4 ', 'LPT1 ', 'LPT2 ', 'LPT3 ');ππvarπ r : registers;π i, { index }π Adjust : byte;π Header : DevPtr;π DevFile : DevFilePtr;π Valid,π Done : boolean;πππfunction BinW(Decimal : word) : string;πconstπ BINDIGIT : array [0..1] of char = '01';πvarπ i : byte;π Binar : string;πbeginπ fillchar (binar, sizeof(Binar), ' ');π Binar [0] := chr(16);π for i := 0 to 15 doπ Binar[16-i] := BINDIGIT[(Decimal shr i) and 1];π BinW := Binar;πend;πππfunction HexN (b : byte) : char; { convert nibble to char }πbeginπ b := b and 15; { forces to only 4 bits }π if b > 9 thenπ inc(b,7); { adjust for hex digits };π HexN := chr(b+48); { convert to character }πend;πππfunction HexB(b : byte) : string;πbeginπ HexB := HexN (b shr 4) + HexN (b); { assemble the nibbles }πend;πππfunction HexW(w : word) : string;πbeginπ{$R-}π hexw := HexB(w shr 8) + HexB(w); { assemble the bytes }π{$R+}πend;πππfunction HexL(l : longint) : string;πbeginπ HexL := HexW(l shr 16) + HexW(l); { assemble the words }πend;πππfunction XP(p : pointer) : pstrg; { display pointer P }πbeginπ XP := HexW(seg(p^)) + ':' + HexW(ofs(p^));πend;ππbeginπ assign(output, '');π rewrite(output); { allow command line redirection }π writeln('Device':0, 'Address':12, 'Strat':10, 'Intrpt':8,π 'Attrib':10, 'File Name':23);π for i := 1 to 69 doπ write('-');π writeln;ππ with r doπ beginπ es := 0;π bx := 0;π ah := $52;π { this is an undocumented DOS function call:π Get pointer to DOS "List of Lists" }π msdos (r);π { es and bx now have values }π if (es = 0) and (bx = 0) thenπ halt(0);ππ Header := ptr(es, bx + LOL_HEADDEV_NUL); { we get NUL dev from this }π end; {with}ππ Done := FALSE; { dummy variable to keep the repeat loop going,π otherwise would have to duplicate the outputπ routines one more time for the final device. }π repeatπ with Header^ doπ beginπ Adjust := 0;π { adjust keeps display columns aligned, bit 15 set is a Characterπ device, if clear it is a Block device and 1st byte is # of blockπ devs supported}ππ if boolean ((Attributes shr 15) and 1) = TRUE thenπ write (NameDev)π elseπ beginπ write ('BLKdev=', byte (NameDev[1]));π Adjust := byte (NameDev[1]) div 10;π end;ππ write(XP(Header) : 12 - Adjust);π write(HexW(Strategy) : 7);π write(HexW(Interrupt) : 7);π write(HexW(Attributes) : 7, '=');π write(BinW(Attributes));ππ { this next section I can't find documented anywhere, but I observed itπ and decided to include it anyway, with MSDOS v5.0, others are unknown.π The file name's extension isn't saved and doesn't matter, either. }ππ if ofs(Header^) < FNAME thenπ { "borrow" from the segment and give it to the offset }π DevFile := ptr(seg(Header^) - $1, ofs(Header^) + $10 - FNAME)π elseπ DevFile := ptr(seg(Header^), ofs(Header^) - FNAME);ππ Valid := TRUE;π for i := 1 to 12 doπ if DevFile^.FileName = STDDEVS[i] thenπ Valid := FALSE;ππ if Valid thenπ for i := 1 to 8 doπ if not (DevFile^.Filename[i] in [' '..'z']) thenπ Valid := FALSE;ππ if {still} Valid thenπ write (' ', DevFile^.FileName);ππ writeln;π if NextDev_ofs = ENDFLAG thenπ exit; { end of the device chain }ππ Header := ptr(NextDev_seg, NextDev_ofs);ππ end; {with}π until Done;πend.π{πThe question: I have seen utils that do this actually give the size ofπthe driver in memory. MSD and PMap both do this. Does anybody knowπhow I can determine the size of the driver in memory?π} 22 01-27-9411:58ALL HELGE HELGESEN HD Type SWAG9402 4 └╫ {π> Does anyone know how to get the hard drive type(s) from CMOS ?π}ππFunction GetFixedDrive(DriveNum : Byte) : Byte; Assembler;πAsmπ mov al, DriveNumπ and al, 1π add al, $19π out $70, alπ in al, $71πend;ππ{πYou specify what drive you want (0/1) and you'll get theπdisk type as specified in CMOS.π}ππbeginπ Writeln(GetFixedDrive(3));πend. 23 01-27-9412:12ALL THORSTEN BARTH Port Info SWAG9402 18 └╫ {π> Can anybody give me any info on how to read signals from pins on sayπ> COM2: or from LPT1: or even from The joystick port? I think it hasπ> been done with the PORT command or something, but what are the valuesπ> to use to read them with? Thanks.ππYou can read in signals from different pins on LPT ports with the PORTπcommand ( =OUT/IN command in assembler). Just determine the base adress ofπthe LPT port usingπ}ππ LPTadress := MemW[$40 : 6 + LPTNr * 2];ππ{πwhere LPTNr is the number of the LPT port from 1 to 3.ππShould return 03BCh, 0378h or 0278h.πThat has to be done once at the beginning of the program.πNow you can start to read/write values on this port.πThe LPT port has:ππ- 8 data outputs (pin 2 to 9), which can be written usingπ}ππ Port[LPTAdress] := B;ππ{πwhere B is a byte consisting of the 8 bits. Voltage will be 5V for 1, and 0Vπfor 0. (but not very high power available (TTL/CMOS)ππ- 4 handshake outs which can be written byπ}ππ Port[LPTAdress + 2] := B;ππ{πwhere B is a byte with the lowest 4 bits set to the values of the pins andπthe higher 4 bits always set to zero.ππ PIN 1: Strobe --> bit 0π PIN 14: AutoFD --> bit 1π PIN 16: Init --> bit 2π PIN 17: SelIN --> bit 3ππ Attention! bit 2/pin 16 is 0V when set to zero, all othersπ are INVERTED! (0 --> 5V and vice versa)ππ- 5 handshake inputs which can be read byπ}ππ B := Port[LPTAdress + 1];ππ{π After the command, B contains the signals that are connected to theπ input pins of the LPT port:π Bit 0-2: no functionπ Bit 3 --> PIN 15/Errorπ Bit 4 --> PIN 13/Selectπ Bit 5 --> PIN 12/PaperEmptyπ Bit 6 --> PIN 10/Acknowledgeπ Bit 7 --> PIN 11/Busy ===> Attention! This input is INVERSE!ππ For information: The pins 18 to 25 are Signal Ground pins.π To use the inputs, connect TTL level 0V for 0, and 5V for 1 to them.π (Or just use a resistor 10kOhm against +5V (take it from the keyboardπ connector or so, don't know what pin that is :-( and a switch against GND:π then you can read in the status of the swith: CLOSED: 0, OPEN: 1...)π} 24 01-27-9412:18ALL MARK LEWIS Port Addresses SWAG9402 18 └╫ {π> does anybody knows the address for serial/parallel ports?ππyou can find them by reading the 7 (seven) WORDs starting at address 0040:0000π<smile>...π}ππCONSTπ BIOSBASE : word = $0040;π PORTADDR : word = $0000;ππVARπ COM1, COM2,π COM3, COM4,π LPT1, LPT2, LPT3 : word;ππBEGINπ COM1 := memw[BIOSBASE:PORTADDR+0];π COM2 := memw[BIOSBASE:PORTADDR+2];π COM3 := memw[BIOSBASE:PORTADDR+4];π COM4 := memw[BIOSBASE:PORTADDR+6];π LPT1 := memw[BIOSBASE:PORTADDR+8];π LPT2 := memw[BIOSBASE:PORTADDR+10];π LPT3 := memw[BIOSBASE:PORTADDR+12];πEND.ππ{πRICHARD BROWNEππ>I guess I can declare an absolute variable at $40:$0000 and use offset to fiπ>the addresses. Just a guess - haven't tried it yet. Thanks for your help.ππDo this, it works. When you WRITELN the variables to theπscreen, they will be in decimal. If you convert them to hex,πyou'll see that they are the old, familiar addresses. If anyπvariable is zero, there is no port present in your computer.ππAnother thing you'll notice, if you have com4, for instance, butπno com3. The normal com4 address will show up in the com3πmemory location, and the com4 adderess will be 0. Whichπexplains why funny things happen when you are using ports 1, 2πand 4 with no 3, or 1 and 3 with no 2, etc., and why we are toldπto always have consecutive com ports, with no "missing" numbers.π}πprogram testadr;πvarπ com1adr : Word Absolute $0040:$0000; { Get COM1 Port address }π com2adr : Word Absolute $0040:$0002; { Get COM2 Port address }π com3adr : Word Absolute $0040:$0004; { Get COM3 Port address }π com4adr : Word Absolute $0040:$0006; { Get COM4 Port address }π lpt1adr : Word Absolute $0040:$0008; { Get LPT1 Port address }π lpt2adr : Word Absolute $0040:$000A; { Get LPT2 Port address }π lpt3adr : Word Absolute $0040:$000C; { Get LPT3 Port address }ππbeginπ writeln('com1 address: ',com1adr);π writeln('com2 address: ',com2adr);π writeln('com3 address: ',com3adr);π writeln('com4 address: ',com4adr);π writeln('lpt1 address: ',lpt1adr);π writeln('lpt2 address: ',lpt2adr);π writeln('lpt3 address: ',lpt3adr);π readln;πend.π 25 01-27-9413:31ALL GREG VIGNEAULT CPU/FPU processor type SWAG9402 20 └╫ (*-------------------------------------------------------------------*)π UNIT CPUID; {CPUID.PAS} { determine CPU and FPU processor types }π Interface { Copyright 1992 Gregory S. Vigneault }ππ Const CpuType :Array[0..10] of String[7] = ('8088','8086','NEC V20',π 'NEC V30','80186','80188','80286','386DX','386SX','486DX','486SX');ππ FpuType :Array[0..4] of String[5] = ('None','8087','80287','80387',π '80487');ππ FUNCTION GetCPU( VAR FPUtype :BYTE ) :BYTE;π { GetCPU codes:π 0 = 8088 | 6 = 80286π 1 = 8086 | 7 = 386DX or older/undetected 386SXπ 2 = NEC V20 | 8 = 386SX * not always detected in all modesπ 3 = NEC V30 | 9 = 486DX or (486SX with 487SX)π 4 = 80186 | 10= 486SXπ 5 = 80188 |π FPUtype codes: 0 = noneπ 1 = 8087π 2 = 80287π 3 = 80387 * 387DX or 387SXπ 4 = 80487 * 487SX or 486DXπ 17= undetermined copro reported by BIOS }π Implementation { Mar.9.92 }π {$L GETCPU.OBJ}π FUNCTION GetCPU( VAR FPUtype :BYTE ) :BYTE; EXTERNAL;π END. { Unit CPUID }π(*-------------------------------------------------------------------*)π(*-------------------------------------------------------------------*)π PROGRAM ProcessorID; {PID.PAS determine CPU & FPU (NDP) types }π USES CPUID;π VAR FPUtype, CPUtype :BYTE;π BEGINπ WriteLn( #10,' PID v0.2, 1992 G.S.Vigneault',#10);π Write(' CPU type: ');π CASE GetCPU( FPUtype ) OFπ 0 : WriteLn('8088');π 1 : WriteLn('8086');π 2 : WriteLn('NEC V20');π 3 : WriteLn('NEC V30');π 4 : WriteLn('80188');π 5 : WriteLn('80186');π 6 : WriteLn('80286');π 7 : WriteLn('386DX');π 8 : WriteLn('386SX');π 9 : WriteLn('486DX');π 10 : WriteLn('486SX')π END; {case GetCPU}π Write(' FPU type: ');π CASE FPUtype OFπ 0 : WriteLn('none');π 1 : WriteLn('8087');π 2 : WriteLn('80287');π 3 : WriteLn('80387');π 4 : WriteLn('80487');π 17 : WriteLn('in equipment byte');π END; {case FPUtype}π END. {ProcessorID}π(*-------------------------------------------------------------------*)π 26 02-03-9409:19ALL DAVID GWILLIM Complete BIOS Table SWAG9402 36 └╫ {π This is a complete map of PC, XT, AT, PS/2 and EGA-installed dataπ areas between 0400h and 0500h in the low memory segment put into theπ form of a Turbo Pascal 4/5/5.5 compatible unit.ππ I found myself needing one or two of these absolute addresses from timeπ to time and got tired of looking them up. Using a record structureπ declared as absolute variable relieves you of specifying theπ individual addresses for each variable, providing that all the Resrvedπ areas are included too.ππ I hope this saves all those Turbo Pascal programmers out there some timeπ and lets them get on with the creative side of the business. Enjoy!ππ David Gwillimπ 159 Woodbury Roadπ Hicksville, NY 11801-3030π (516) 942-8697ππ 6 August 1989ππ CREDITS:ππ The absolute addresses for this unit came from "The Programmer's PCπ Sourcebook" by Thom Hogan, published by Microsoft Press.π ISBN 1-55615-118-7. List price $24.95 USA.ππ This book is very helpful (apart from a few inevitable) typos). Iπ consider it an essential purchase for any programmer who has to dealπ with a PC at the hardware level.ππ}ππunit Bios;ππinterfaceππvarπ BiosSeg : recordπ ComBase : array[1..4] of word;π LptBase : array[1..4] of word;π InstalledHardware : array[1..2] of byte;π POST_Status : byte; { Convertible only }π MemorySize : word;π _RESERVED1 : word;π KeyboardControl : array[1..2] of byte;π AlternateKeypadEntry : byte;π KeyboardBufferHeadPtr : word; { points to first char in type-ahead buffer }π KeyboardBufferTailPtr : word; { points to last char in type-ahead buffer }π KeyboardBuffer : array[1..16] of word;π FloppyRecalStatus : byte;π FloppyMotorStatus : byte;π FloppyMotorOffCounter : byte;π FloppyPrevOpStatus : byte;π FloppyControllerStatus : array[1..7] of byte;π DisplayMode : byte;π NumberOfColumns : word;π RegenBufferLength : word;π RegenBufferAddress : word;π CursorPosition : array[1..8] of word;π CursorType : word;π CurrentDisplayPage : byte;π VideoControllerBaseAddress : word;π Current3x8Register : byte;π Current3x9Register : byte;π PointerToResetCode : pointer; { PS/2 only - except model 30 }π _RESERVED2 : byte;π TimerCounter : longint;π TimerOverflowFlag : byte; { non-zero means timer passed 24 hours }π BreakKeyState : byte;π ResetFlag : word; { $1234=bypass mem test; $4321=preserve mem (PS/2) }π { $5678=system supended (Convertible) }π { $9ABC=manufacturing test (Convertible) }π { $ABCD=system POST loop (Convertible only) }π FixedDiskPrevOpStatus : byte;π NumberOfFixedDrives : byte;π FixedDiskDriveControl : byte; {XT only}π FixedDiskControllerPort : byte; {XT only}π LptTimeOut : array[1..4] of byte; { [4] valid for PC, XT and AT only }π ComTimeOut : array[1..4] of byte;π KeyboardBufferStartOffsetPtr :word;π KeyboardBufferEndOffsetPtr :word;π VideoRows : byte;π CharacterHeight : word; { bytes per character }π VideoControlStates : array[1..2] of byte;ππ _RESERVED3 : word;π MediaControl : byte;π FixedDiskControllerStatus : byte; { AT, XT after 1/10/85, PS/2 only }π FixedDiskControllerErrorStatus : byte; { AT, XT after 1/10/85, PS/2 only }π FixedDiskInterruptControl : byte; { AT, XT after 1/10/85, PS/2 only }π _RESERVED4 : byte;π DriveMediaState : array[0..1] of byte;π _RESERVED5 : word;π DriveCurrentCylinder : array[0..1] of byte;π KeyboardModeState : byte;π KeyboardLEDflags : byte;π UserWaitCompleteFlagAddress : pointer;π UserWaitCount : longint; { micro-seconds }π WaitActiveFlag : byte;π _RESERVED6 : array[1..7] of byte;π VideoParameterTable : pointer; { EGA and PS/2 only }π DynamicSaveArea : pointer; { EGA and PS/2 only }π AlphaModeAuxCharGenerator : pointer; { EGA and PS/2 only }π GraphicsModeAuxCharGenerator : pointer; { EGA and PS/2 only }π SecondarySaveArea : pointer; { PS/2 only (not Model 30) }π _RESERVED7 : array[1..4] of byte;π _RESERVED8 : array[1..64] of byte;π PrintScreenStatus : byte;π end absolute $0040:$0000;ππimplementationππend.ππππ 27 02-03-9416:18ALL STEVE ROGERS Disabling PrtScr SWAG9402 5 └╫ π{ Anyone have any idea why this won't disable PrtScr? }ππusesπ crt,dos;ππvarπ i : word;π old_status : byte;π prt_status : byte absolute $0040:$0100; { PrtScr status byte }ππbeginπ old_status:= prt_status;π prt_status:= 1;π for i:= 1 to 20 do writeln(' This is line ',i);π writeln;π writeln('Press PrtScr to test, any other key to exit');π readkey;π prt_status:= old_status;πend.π