program PSX_DMA_GPU;
{$mode objfpc}{$H+}
uses
ctypes;
const
IO_BASE = $BF801000;
DMA_GPU = 2;
// CHCR flags (ipotizzati come in PSX SDK, da adattare se hai header precisi)
DMA_CHCR_ENABLE = $01000000;
DMA_CHCR_WRITE = $00000200;
DMA_CHCR_MODE_LIST = $00000400;
CHAIN_BUFFER_SIZE = 1024;
type
PDWORD = ^UInt32;
function _ADDR32(addr: PtrUInt): PDWORD; inline;
begin
Result := PDWORD(addr);
end;
function _MMIO32(addr: PtrUInt): UInt32; inline;
begin
Result := _ADDR32(addr)^;
end;
procedure _MMIO32_Set(addr: PtrUInt; value: UInt32); inline;
begin
_ADDR32(addr)^ := value;
end;
// Macros DMA register
function DMA_MADR(N: Integer): PtrUInt; inline;
begin
Result := (IO_BASE or $080) + (16 * N);
end;
function DMA_BCR(N: Integer): PtrUInt; inline;
begin
Result := (IO_BASE or $084) + (16 * N);
end;
function DMA_CHCR(N: Integer): PtrUInt; inline;
begin
Result := (IO_BASE or $088) + (16 * N);
end;
// Funzioni DMA
procedure sendLinkedList(data: Pointer);
begin
// attende che DMA non sia busy
while (_MMIO32(DMA_CHCR(DMA_GPU)) and DMA_CHCR_ENABLE) <> 0 do
begin
asm nop end;
end;
_MMIO32_Set(DMA_MADR(DMA_GPU), PtrUInt(data));
_MMIO32_Set(DMA_CHCR(DMA_GPU), DMA_CHCR_WRITE or DMA_CHCR_MODE_LIST or DMA_CHCR_ENABLE);
end;
function gp0_tag(length: SizeUInt; next: Pointer): UInt32;
begin
Result :=
((UInt32(PtrUInt(next)) and $FFFFFF) shl 0) or
((UInt32(length) and $FF) shl 24);
end;
function gp0_endTag(length: SizeUInt): UInt32;
begin
Result := gp0_tag(length, Pointer($FFFFFF));
end;
type
PDMAChain = ^TDMAChain;
TDMAChain = record
data: array[0..CHAIN_BUFFER_SIZE-1] of UInt32;
nextPacket: ^UInt32;
end;
function allocatePacket(chain: PDMAChain; numCommands: Integer): PUInt32;
var
ptr: PUInt32;
begin
ptr := chain^.nextPacket;
Inc(chain^.nextPacket, numCommands + 1);
ptr^ := gp0_tag(numCommands, chain^.nextPacket);
Result := @ptr[1];
end;
var
dmaChains: array[0..1] of TDMAChain;
usingSecondFrame: Integer = 0;
var
chain: PDMAChain;
ptr: PUInt32;
begin
while True do
begin
chain := @dmaChains[usingSecondFrame];
// reset buffer
chain^.nextPacket := @chain^.data[0];
ptr := allocatePacket(chain, 4);
ptr[0] := 1;
ptr[1] := 2;
ptr[2] := 3;
ptr[3] := 4;
chain^.nextPacket^ := gp0_endTag(0);
sendLinkedList(@chain^.data[0]);
end;
end.