WinPicoGUS/Picogus.pas
2025-06-22 01:35:09 -04:00

146 lines
2.9 KiB
ObjectPascal
Executable file

unit Picogus;
interface
uses classes, windows;
const
MODE_MAGIC = $00;
MODE_PROTOCOL = $01;
MODE_FWSTRING = $02;
MODE_BOOTMODE = $03;
MODE_CDPORT = $60;
MODE_CDSTATUS = $61;
MODE_CDERROR = $62;
MODE_CDLIST = $63;
MODE_CDLOAD = $64;
MODE_CDNAME = $65;
MODE_CDAUTOADV = $66;
function DetectPicoGUS: Boolean;
function ReadModeString(mode: byte): string;
function ReadCDList: TStringList;
function SelectedCD: Byte;
procedure SelectCD(index: Byte);
implementation
const
CONTROL_PORT = $1d0;
DATA_PORT_LOW = $1d1;
DATA_PORT_HIGH = $1d2;
PICOGUS_PROTOCOL_VER = 4;
CDSTATUS_ERROR = $ff;
CDSTATUS_READY = 2;
procedure outb(port: Integer; val: byte);
begin
asm
MOV EDX, port
MOV AL, val
OUT DX, AL
end;
end;
function inb(port: Integer): byte;
var
b: byte;
begin
asm
MOV EDX, port
IN AL, DX
MOV b, AL
end;
Result := b;
end;
procedure SetMode(mode: byte);
begin
outb(CONTROL_PORT, $cc);
outb(CONTROL_PORT, mode);
end;
function DetectPicoGUS: Boolean;
begin
SetMode(MODE_MAGIC);
Result := (inb(DATA_PORT_HIGH) = $dd)
end;
function ReadDataPortString: string;
var
b: byte;
begin
Result := '';
b := inb(DATA_PORT_HIGH);
while b <> 0 do
begin
Result := Result + Chr(b);
if b = 4 then Break;
b := inb(DATA_PORT_HIGH);
end;
end;
function ReadModeString(mode: byte): string;
begin
SetMode(mode);
Result := ReadDataPortString;
end;
function ReadModeStrings(mode: byte): TStringList;
var
str: string;
begin
Result := TStringList.Create;
SetMode(mode);
repeat
str := ReadDataPortString;
if str = #4 then Break;
Result.Add(str);
until False;
end;
function AwaitCDStatus: byte;
var
i: Integer;
begin
Sleep(10);
SetMode(MODE_CDSTATUS);
for i := 0 to 100 do
begin
Result := inb(DATA_PORT_HIGH);
if (Result = CDSTATUS_READY) or (Result = CDSTATUS_ERROR) then Break;
Sleep(1);
end;
end;
function ReadCDList: TStringList;
var
status: Byte;
begin
SetMode(MODE_CDLIST);
status := AwaitCDStatus;
if status = CDSTATUS_READY then
Result := ReadModeStrings(MODE_CDLIST)
else
begin
Result := TStringList.Create;
if status = CDSTATUS_ERROR then
begin;
Result.Add('Error reading list:');
Result.Add(ReadModeString(MODE_CDERROR));
end
else
Result.Add('Timed out reading list');
end;
end;
function SelectedCD: Byte;
begin
SetMode(MODE_CDLOAD);
Result := inb(DATA_PORT_HIGH);
end;
procedure SelectCD(index: Byte);
begin
SetMode(MODE_CDLOAD);
outb(DATA_PORT_HIGH, index);
end;
end.