fpc/rtl/embedded/arm/raspi2.pp
2023-07-27 19:04:03 +02:00

212 lines
4.4 KiB
ObjectPascal

{$IFNDEF FPC_DOTTEDUNITS}
unit raspi2;
{$ENDIF FPC_DOTTEDUNITS}
{$goto on}
{$INLINE ON}
interface
type
TBitvector32 = bitpacked array[0..31] of 0..1;
const
PeripheralBase = $3F000000;
GPFSEL1 = PeripheralBase + $00200004;
GPSET0 = PeripheralBase + $0020001C;
GPCLR0 = PeripheralBase + $00200028;
GPPUD = PeripheralBase + $00200094;
GPPUDCLK0 = PeripheralBase + $00200098;
AUX_ENABLES = PeripheralBase + $00215004;
AUX_MU_IO_REG = PeripheralBase + $00215040;
AUX_MU_IER_REG = PeripheralBase + $00215044;
AUX_MU_IIR_REG = PeripheralBase + $00215048;
AUX_MU_LCR_REG = PeripheralBase + $0021504C;
AUX_MU_MCR_REG = PeripheralBase + $00215050;
AUX_MU_LSR_REG = PeripheralBase + $00215054;
AUX_MU_MSR_REG = PeripheralBase + $00215058;
AUX_MU_SCRATCH = PeripheralBase + $0021505C;
AUX_MU_CNTL_REG = PeripheralBase + $00215060;
AUX_MU_STAT_REG = PeripheralBase + $00215064;
AUX_MU_BAUD_REG = PeripheralBase + $00215068;
implementation
{$IFDEF FPC_DOTTEDUNITS}
uses
EmbeddedApi.ConsoleIO;
{$ELSE FPC_DOTTEDUNITS}
uses
consoleio;
{$ENDIF FPC_DOTTEDUNITS}
procedure _FPC_haltproc; assembler; nostackframe; public name '_haltproc';
asm
.Lhalt:
wfi
b .Lhalt
end;
procedure DUMMY(Count: DWord);
var
i : DWord;
begin
for i := 0 to Count do
begin
asm
nop
end;
end;
end;
procedure PUT32(Address: DWord; Value: DWord); inline;
VAR
p: ^DWord;
begin
p := POINTER (Address);
p^ := Value;
end;
function GET32(Address: DWord) : DWord; inline;
VAR
p: ^DWord;
begin
p := POINTER (Address);
GET32 := p^;
end;
function UARTLCR(): DWord;
begin
UARTLCR := GET32(AUX_MU_LCR_REG);
end;
procedure UARTPuts(C: AnsiChar);
begin
while True do
begin
if (GET32(AUX_MU_LSR_REG) and $20) > 0 then break;
end;
PUT32(AUX_MU_IO_REG, DWord(C));
end;
function UARTGet(): AnsiChar;
begin
while True do
begin
if (GET32(AUX_MU_LSR_REG) and $01) > 0 then break;
end;
UARTGet := AnsiChar(GET32(AUX_MU_IO_REG) and $FF);
end;
procedure UARTFlush();
begin
while True do
begin
if (GET32(AUX_MU_LSR_REG) and $100) > 0 then break;
end;
end;
function RaspiWrite(ACh: AnsiChar; AUserData: pointer): boolean;
begin
UARTPuts(ACh);
RaspiWrite := true;
end;
function RaspiRead(var ACh: AnsiChar; AUserData: pointer): boolean;
begin
if (GET32(AUX_MU_LSR_REG) and $01) > 0 then
begin
ACh := UARTGet();
end else
begin
ACh := #0;
end;
RaspiRead := true;
end;
procedure UARTInit; public name 'UARTInit';
var
ra: dword;
begin
PUT32(AUX_ENABLES, 1);
PUT32(AUX_MU_IER_REG, 0);
PUT32(AUX_MU_CNTL_REG, 0);
PUT32(AUX_MU_LCR_REG, 3);
PUT32(AUX_MU_MCR_REG, 0);
PUT32(AUX_MU_IER_REG, 0);
PUT32(AUX_MU_IIR_REG, $C6);
PUT32(AUX_MU_BAUD_REG, 270);
ra := GET32(GPFSEL1);
ra := ra AND (not (7 shl 12)); // gpio14
ra := ra OR (2 shl 12); // alt5
ra := ra AND (not (7 shl 15)); // gpio15
ra := ra OR (2 shl 15); // alt5
PUT32(GPFSEL1, ra);
PUT32(GPPUD, 0);
Dummy(500);
PUT32(GPPUDCLK0, ((1 shl 14) OR (1 shl 15)));
Dummy(500);
PUT32(GPPUDCLK0, 0);
PUT32(AUX_MU_CNTL_REG, 3);
end;
{$ifndef CUSTOM_ENTRY}
procedure PASCALMAIN; external name 'PASCALMAIN';
var
_stack_top: record end; external name '_stack_top';
{ This start makes sure we only execute on core 0 - the others will halt }
procedure _FPC_start; assembler; nostackframe;
label
_start;
asm
.init
.align 16
.globl _start
_start:
// enable fpu
.long 0xee110f50 // mrc p15, 0, r0, c1, c0, 2
orr r0, r0, #0x300000 // single precision
orr r0, r0, #0xC00000 // double precision
.long 0xee010f50 // mcr p15, 0, r0, c1, c0, 2
mov r0, #0x40000000
.long 0xeee80a10 // fmxr fpexc, r0
.long 0xee100fb0 // mrc p15,0,r0,c0,c0,5 - find the core ID
mov r1, #0xFF
ands r1, r1, r0
bne _FPC_haltproc
ldr r0, .L_stack_top
mov sp, r0
bl UARTInit
bl PASCALMAIN
bl _FPC_haltproc
.L_stack_top:
.long _stack_top
.text
end;
{$endif CUSTOM_ENTRY}
begin
OpenIO(Input, @RaspiWrite, @RaspiRead, fmInput, nil);
OpenIO(Output, @RaspiWrite, @RaspiRead, fmOutput, nil);
OpenIO(ErrOutput, @RaspiWrite, @RaspiRead, fmOutput, nil);
OpenIO(StdOut, @RaspiWrite, @RaspiRead, fmOutput, nil);
OpenIO(StdErr, @RaspiWrite, @RaspiRead, fmOutput, nil);
end.