Просмотр исходного кода

Added basic support for cooperative kernel on Zynq devices
(missing support for identity mapped memory and interrupt controller)

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@6566 8c9fc860-2736-0410-a75d-ab315db34111

eth.negelef 9 лет назад
Родитель
Сommit
58a166d0c8
5 измененных файлов с 721 добавлено и 1 удалено
  1. 20 1
      source/Release.Tool
  2. 471 0
      source/Zynq.CPU.Mod
  3. 142 0
      source/Zynq.Environment.Mod
  4. 70 0
      source/Zynq.Processors.Mod
  5. 18 0
      source/Zynq.Timer.Mod

+ 20 - 1
source/Release.Tool

@@ -23,6 +23,11 @@
 #	Release.Build --build --path="./" A2RPiCooperative ~
 #	StaticLinker.Link --fileName=kernel.img --extension=Gof --displacement=8000H --path="./" Trace CPU Runtime Counters Processors Queues BaseTypes Timer Activities ExclusiveBlocks HeapManager Interrupts Environment Mutexes Machine Heaps Modules GarbageCollector Objects Kernel ~
 #
+# A2 Zynq Cooperative
+#
+#	Release.Build --build --path="./" A2ZynqCooperative ~
+#	StaticLinker.Link --fileName=kernel.bin --extension=Gof --displacement=100000H --path="./" Trace CPU Runtime Counters Processors Queues BaseTypes Timer Activities ExclusiveBlocks HeapManager Interrupts Environment Mutexes Machine Heaps Modules GarbageCollector Objects Kernel ~
+#
 # WINAOS
 #
 # There are two different variants of WinAOS:
@@ -139,6 +144,17 @@ BUILDS
 		EXCLUDEPACKAGES "System Drivers Compiler ApplicationsMini Applications GuiApplicationsMini GuiApplications Fun Testing Education Build EFI Contributions Oberon OberonGadgets OberonApplications OberonDocumentation OberonVoyager OberonAnts"
 		DISABLED "FALSE"
 	}
+	A2ZynqCooperative {
+		INCLUDE "NATIVE ARM ZYNQ COOP ZYNQCOOP"
+		COMPILER "Compiler.Compile"
+		COMPILEOPTIONS "--cooperative --objectFile=Generic --newObjectFile --traceModule=Trace --mergeSections"
+		TARGET "ARM"
+		EXTENSION "Gof"
+		SYMBOLEXTENSION "Sym"
+		PATH "AOS:"
+		EXCLUDEPACKAGES "System Drivers Compiler ApplicationsMini Applications GuiApplicationsMini GuiApplications Fun Testing Education Build EFI Contributions Oberon OberonGadgets OberonApplications OberonDocumentation OberonVoyager OberonAnts"
+		DISABLED "FALSE"
+	}
 	A2NewObjectFile
 	{
 		INCLUDE "NATIVE NATIVEGEN I386 I386GEN UNCOOP"
@@ -280,6 +296,7 @@ PACKAGE Kernel ARCHIVE "Kernel.zip" SOURCE "KernelSrc.zip" DESCRIPTION "A2 Kerne
 	UNCOOP { Runtime.Mod }
 	I386COOP { I386.CPU.Mod }
 	RPICOOP { RPI.CPU.Mod }
+	ZYNQCOOP { Zynq.CPU.Mod }
 
 	# Low-level trace output
 	Trace.Mod
@@ -289,9 +306,11 @@ PACKAGE Kernel ARCHIVE "Kernel.zip" SOURCE "KernelSrc.zip" DESCRIPTION "A2 Kerne
 	NATIVEI386COOP { I386.APIC.Mod APIC.Processors.Mod BIOS.ACPI.Mod ACPI.Timer.Mod}
 	WINCOOP { Coop.Win32.Kernel32.Mod Win32.Processors.Mod  Win32.Timer.Mod}
 	RPICOOP { RPI.Processors.Mod RPI.Timer.Mod }
+	ZYNQCOOP { Zynq.Processors.Mod Zynq.Timer.Mod }
 	COOP { Queues.Mod BaseTypes.Mod Activities.Mod ExclusiveBlocks.Mod Interrupts.Mod Coop.Runtime.Mod }
 	NATIVECOOP { HeapManager.Mod BIOS.Environment.Mod }
 	RPICOOP { HeapManager.Mod RPI.Environment.Mod }
+	ZYNQCOOP { HeapManager.Mod Zynq.Environment.Mod }
 	WINCOOP { Win32.Environment.Mod }
 
 	UNIX { Unix.Glue.Mod }
@@ -306,7 +325,7 @@ PACKAGE Kernel ARCHIVE "Kernel.zip" SOURCE "KernelSrc.zip" DESCRIPTION "A2 Kerne
 	WINORIG, WINGEN {Win32.Machine.Mod }
 	COOP { Mutexes.Mod }
 	I386COOP { Coop.I386.Machine.Mod }
-	RPICOOP { Coop.ARM.Machine.Mod }
+	RPICOOP, ZYNQCOOP { Coop.ARM.Machine.Mod }
 
 	UNIX { Unix.I386.Machine.Mod }
 

+ 471 - 0
source/Zynq.CPU.Mod

@@ -0,0 +1,471 @@
+(* Runtime support for CPU internals *)
+(* Copyright (C) Florian Negele *)
+
+MODULE CPU;
+
+IMPORT SYSTEM;
+
+CONST StackSize* = 4096;
+CONST Quantum* = 100000;
+CONST CacheLineSize* = 32;
+CONST StackDisplacement* = 0;
+
+PROCEDURE Backoff-;
+CODE
+	MOV	R2, #0x100
+loop:
+	SUBS	R2, R2, #1
+	BNE	loop
+END Backoff;
+
+(* cpu control *)
+PROCEDURE Delay- (cycles: SIZE);
+CODE
+	LDR	R2, [FP, #cycles]
+delay:
+	SUBS	R2, R2, #1
+	BNE	delay
+END Delay;
+
+PROCEDURE {NORETURN} Reset-;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	WriteWord (WDOG_CONTROL, LSH (0, CLKSEL) + LSH (0, CRV) + LSH (0248H, CKEY));
+	WriteWord (WDOG_MODE, LSH (1, WDEN) + LSH (1, RSTEN) + LSH (0ABCH, ZKEY));
+	Halt;
+END Reset;
+
+PROCEDURE {NORETURN} Halt-;
+CODE
+	MRS	R2, CPSR
+	ORR	R2, R2, #0b1100000
+	MSR	CPSR_c, r2
+	WFI
+END Halt;
+
+PROCEDURE -SaveResult-;
+CODE
+	STMDB	SP!, {R0, R1}
+END SaveResult;
+
+PROCEDURE -RestoreResultAndReturn-;
+CODE
+	LDMIA	SP!, {R0, R1}
+	ADD	SP, FP, #4
+	LDMIA	SP!, {FP, PC}
+END RestoreResultAndReturn;
+
+(* hardware registers *)
+CONST PSS_RST_CTRL* = 0F8000200H; SOFT_RST* = 0;
+
+CONST UART_RST_CTRL* = 0F8000228H; UART0_CPU1X_RST* = 0; UART1_CPU1X_RST* = 1; UART0_REF_RST* = 2; UART1_REF_RST* = 3;
+
+CONST UART_REF_CLK* = 50000000;
+CONST UART0* = 0E0000000H; UART1* = 0E0001000H;
+CONST Control_reg0* = 000H; RXRST* = 0; TXRST* = 1; RXEN* = 2; RXDIS* = 3; TXEN* = 4; TXDIS* = 5;
+CONST mode_reg0* = 004H; CHMOD* = 8; NBSTOP* = 6; PAR* = 3; CHRL* = 1; CLKS* = 0;
+CONST Intrpt_dis_reg0* = 00CH;
+CONST Baud_rate_gen_reg0* = 018H; CD* = 0;
+CONST Channel_sts_reg0* = 02CH; TXEMPTY* = 3; TXFULL* = 4;
+CONST Baud_rate_divider_reg0* = 034H; BDIV* = 0;
+CONST TX_RX_FIFO0* = 030H; FIFO* = 0;
+
+CONST 	Global_Timer_Counter_Register0* = 0F8F00200H;
+CONST 	Global_Timer_Counter_Register1* = 0F8F00204H;
+
+CONST WDOG_MODE* = 0F8005000H; WDEN* = 0; RSTEN* = 1; ZKEY* = 12;
+CONST WDOG_CONTROL* = 0F8005004H; CLKSEL* = 0; CRV* = 2; CKEY* = 14;
+
+PROCEDURE ReadWord- (register: ADDRESS): WORD;
+CODE
+	LDR	R2, [FP, #register]
+	LDR	R0, [R2, #0]
+END ReadWord;
+
+PROCEDURE ReadMask- (register: ADDRESS): SET;
+CODE
+	LDR	R2, [FP, #register]
+	LDR	R0, [R2, #0]
+END ReadMask;
+
+PROCEDURE WriteWord- (register: ADDRESS; value: ADDRESS);
+CODE
+	LDR	R2, [FP, #register]
+	LDR	R3, [FP, #value]
+	STR	R3, [R2, #0]
+END WriteWord;
+
+PROCEDURE WriteMask- (register: ADDRESS; value: SET);
+CODE
+	LDR	R2, [FP, #register]
+	LDR	R3, [FP, #value]
+	STR	R3, [R2, #0]
+END WriteMask;
+
+PROCEDURE Mask- (register: ADDRESS; value: SET);
+CODE
+	LDR	R2, [FP, #register]
+	LDR	R3, [FP, #value]
+	LDR	R4, [R2, #0]
+	ORR	R4, R4, R3
+	STR	R4, [R2, #0]
+END Mask;
+
+PROCEDURE Unmask- (register: ADDRESS; value: SET);
+CODE
+	LDR	R2, [FP, #register]
+	LDR	R3, [FP, #value]
+	LDR	R4, [R2, #0]
+	BIC	R4, R4, R3
+	STR	R4, [R2, #0]
+END Unmask;
+
+(* combined mask / unmask: clear mask and set value *)
+PROCEDURE MaskIn-(register: ADDRESS; mask, value: SET);
+CODE
+	LDR	R2, [FP, #register]
+	LDR	R3, [FP, #mask]
+	LDR	R4, [FP, #value]
+	LDR	R5, [R2, #0]
+	BIC	R5, R5, R3
+	ORR R5, R5, R4 
+	STR	R5, [R2, #0]
+END MaskIn;
+	
+(* interrupt handling *)
+CONST Interrupts* = 7;
+CONST UndefinedInstruction* = 1; SoftwareInterrupt* = 2; PrefetchAbort* = 3; DataAbort* = 4; IRQ* = 5; FIQ* = 6;
+
+TYPE InterruptHandler* = PROCEDURE (index: SIZE);
+
+VAR handlers: ARRAY Interrupts OF InterruptHandler;
+
+PROCEDURE InstallInterrupt- (handler: InterruptHandler; index: SIZE): InterruptHandler;
+VAR previous: InterruptHandler;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	ASSERT (handler # NIL); ASSERT (index < Interrupts);
+	REPEAT previous := CAS (handlers[index], NIL, NIL) UNTIL CAS (handlers[index], previous, handler) = previous;
+	RETURN previous;
+END InstallInterrupt;
+
+PROCEDURE HandleInterrupt (index: SIZE);
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	SYSTEM.SetActivity (NIL);
+	IF handlers[index] # NIL THEN handlers[index] (index) ELSE HALT (1234) END;
+END HandleInterrupt;
+
+PROCEDURE DisableInterrupt- (index: SIZE);
+VAR previous: InterruptHandler;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	ASSERT (index < Interrupts);
+	REPEAT previous := CAS (handlers[index], NIL, NIL) UNTIL CAS (handlers[index], previous, NIL) = previous;
+END DisableInterrupt;
+
+PROCEDURE Initialize-;
+CODE
+	ADD	R2, PC, #vector-$-8
+	MOV	R3, #0
+	ADD	R4, R3, #vector_end - vector
+copy:
+	CMP	R3, R4
+	BEQ	vector_end
+	LDR	r5, [R2], #4
+	STR	r5, [R3], #4
+	B	copy
+vector:
+	LDR	PC, [PC, #header-$-8]
+	LDR	PC, [PC, #undefined_instruction-$-8]
+	LDR	PC, [PC, #software_interrupt-$-8]
+	LDR	PC, [PC, #prefetch_abort-$-8]
+	LDR	PC, [PC, #data_abort-$-8]
+	MOV	R0, R0
+	LDR	PC, [PC, #irq-$-8]
+fiq:
+	STMDB	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, LR}
+	MOV	R2, #UndefinedInstruction
+	STR	R2, [SP, #-4]!
+	LDR	R2, [PC, #handle-$-8]
+	BLX	R2
+	ADD	SP, SP, #4
+	LDMIA	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, LR}
+	SUBS	PC, LR, #4
+header:
+	d32	0x8000
+undefined_instruction:
+	d32	UndefinedInstructionHandler
+software_interrupt:
+	d32	SoftwareInterruptHandler
+prefetch_abort:
+	d32	PrefetchAbortHandler
+data_abort:
+	d32	DataAbortHandler
+irq:
+	d32	IRQHandler
+handle:
+	d32	HandleInterrupt
+vector_end:
+	MOV	R2, #0b10001
+	MSR	CPSR_c, R2
+	MOV	SP, #0x7000
+	MOV	R2, #0b10010
+	MSR	CPSR_c, R2
+	MOV	SP, #0x6000
+	MOV	R2, #0b10111
+	MSR	CPSR_c, R2
+	MOV	SP, #0x5000
+	MOV	R2, #0b11011
+	MSR	CPSR_c, R2
+	MOV	SP, #0x4000
+	MOV	R2, #0b10011
+	MSR	CPSR_c, R2
+END Initialize;
+
+PROCEDURE {NOPAF} UndefinedInstructionHandler;
+CODE
+	STMDB	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
+	MOV	R2, #UndefinedInstruction
+	STR	R2, [SP, #-4]!
+	LDR	R2, [PC, #handle-$-8]
+	BLX	R2
+	ADD	SP, SP, #4
+	LDMIA	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
+	MOVS	PC, LR
+handle:
+	d32	HandleInterrupt
+END UndefinedInstructionHandler;
+
+PROCEDURE {NOPAF} SoftwareInterruptHandler;
+CODE
+	STMDB	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
+	MOV	R2, #SoftwareInterrupt
+	STR	R2, [SP, #-4]!
+	LDR	R2, [PC, #handle-$-8]
+	BLX	R2
+	ADD	SP, SP, #4
+	LDMIA	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
+	MOVS	PC, LR
+handle:
+	d32	HandleInterrupt
+END SoftwareInterruptHandler;
+
+PROCEDURE {NOPAF} PrefetchAbortHandler;
+CODE
+	STMDB	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
+	MOV	R2, #PrefetchAbort
+	STR	R2, [SP, #-4]!
+	LDR	R2, [PC, #handle-$-8]
+	BLX	R2
+	ADD	SP, SP, #4
+	LDMIA	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
+	SUBS	PC, LR, #4
+handle:
+	d32	HandleInterrupt
+END PrefetchAbortHandler;
+
+PROCEDURE {NOPAF} DataAbortHandler;
+CODE
+	STMDB	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
+	MOV	R2, #DataAbort
+	STR	R2, [SP, #-4]!
+	LDR	R2, [PC, #handle-$-8]
+	BLX	R2
+	ADD	SP, SP, #4
+	LDMIA	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
+	SUBS	PC, LR, #4
+handle:
+	d32	HandleInterrupt
+END DataAbortHandler;
+
+PROCEDURE {NOPAF} IRQHandler;
+CODE
+	STMDB	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
+	MOV	R2, #IRQ
+	STR	R2, [SP, #-4]!
+	LDR	R2, [PC, #handle-$-8]
+	BLX	R2
+	ADD	SP, SP, #4
+	LDMIA	SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR}
+	SUBS	PC, LR, #4
+handle:
+	d32	HandleInterrupt
+END IRQHandler;
+
+(* compiler intrinsics *)
+TYPE ULONGINT = LONGINT; (* alias to make distinction between signed and unsigned more clear *)
+TYPE UHUGEINT = HUGEINT;
+
+PROCEDURE DivS8*(left, right: SHORTINT): SHORTINT;
+VAR result, dummy: LONGINT;
+BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN SHORTINT(result)
+END DivS8;
+
+PROCEDURE DivS16*(left, right: INTEGER): INTEGER;
+VAR result, dummy: LONGINT;
+BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN INTEGER(result)
+END DivS16;
+
+PROCEDURE DivS32*(left, right: LONGINT): LONGINT;
+VAR result, dummy: LONGINT;
+BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, result, dummy); RETURN result
+END DivS32;
+
+PROCEDURE DivU32*(left, right: ULONGINT): ULONGINT;
+VAR result, dummy: LONGINT;
+BEGIN {UNCOOPERATIVE, UNCHECKED} DivModU32(left, right, result, dummy); RETURN result
+END DivU32;
+
+PROCEDURE DivS64*(left, right: HUGEINT): HUGEINT;
+VAR result, dummy: HUGEINT;
+BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS64(left, right, result, dummy); RETURN result
+END DivS64;
+
+PROCEDURE ModS8*(left, right: SHORTINT): SHORTINT;
+VAR result, dummy: LONGINT;
+BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN SHORTINT(result)
+END ModS8;
+
+PROCEDURE ModS16*(left, right: INTEGER): INTEGER;
+VAR result, dummy: LONGINT;
+BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN INTEGER(result)
+END ModS16;
+
+PROCEDURE ModS32*(left, right: LONGINT): LONGINT;
+VAR result, dummy: LONGINT;
+BEGIN {UNCOOPERATIVE, UNCHECKED} DivModS32(left, right, dummy, result); RETURN result
+END ModS32;
+
+PROCEDURE ModU32*(left, right: ULONGINT): ULONGINT;
+VAR result, dummy: LONGINT;
+BEGIN {UNCOOPERATIVE, UNCHECKED} DivModU32(left, right, dummy, result); RETURN result
+END ModU32;
+
+PROCEDURE ModS64*(left, right: HUGEINT): HUGEINT;
+VAR result, dummy: HUGEINT;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	DivModS64(left, right, dummy, result); RETURN result
+END ModS64;
+
+(* signed division and modulus
+- note: this implements the mathematical definition of DIV and MOD in contrast to the symmetric one
+*)
+PROCEDURE DivModS32(dividend, divisor: LONGINT; VAR quotient, remainder: LONGINT);
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	ASSERT(divisor > 0);
+	IF dividend >= 0 THEN
+		DivModU32(dividend, divisor, quotient, remainder)
+	ELSE
+		dividend := -dividend;
+		DivModU32(dividend, divisor, quotient, remainder);
+		quotient := -quotient;
+		IF remainder # 0 THEN
+			DEC(quotient);
+			remainder := divisor - remainder
+		END
+	END
+END DivModS32;
+
+(*
+	Fast 32-bit unsigned integer division/modulo (author Alexey Morozov)
+*)
+PROCEDURE DivModU32(dividend, divisor: ULONGINT; VAR quotient, remainder: ULONGINT);
+CODE
+	MOV R2, #0 ; quotient will be stored in R2
+
+	LDR R0, [FP,#dividend] ; R0 := dividend
+	LDR R1, [FP,#divisor] ; R1 := divisor
+
+	; check for the case dividend < divisor
+	CMP R0, R1
+	BLT Exit ; nothing to do than setting quotient to 0 and remainder to dividend (R0)
+
+	CLZ R3, R0 ; R3 := clz(dividend)
+	CLZ R4, R1 ; R4 := clz(divisor)
+
+	SUB R3, R4, R3 ; R2 := clz(divisor) - clz(dividend) , R2 >= 0
+	LSL R1, R1, R3 ; scale divisor: divisor := LSH(divisor,clz(divisor)-clz(dividend))
+
+Loop:
+	CMP R0, R1
+	ADC R2, R2, R2
+	SUBCS R0, R0, R1
+	LSR R1, R1, #1
+	SUBS R3, R3, #1
+	BPL Loop
+
+	; R0 holds the remainder
+
+Exit:
+	LDR R1, [FP,#quotient] ; R1 := address of quotient
+	LDR R3, [FP,#remainder] ; R3 := address of remainder
+
+	STR R2, [R1,#0] ; quotient := R1
+	STR R0, [R3,#0] ; remainder := R0
+END DivModU32;
+
+(* signed division and modulus
+- note: this implements the mathematical definition of DIV and MOD in contrast to the symmetric one
+*)
+PROCEDURE DivModS64*(dividend, divisor: HUGEINT; VAR quotient, remainder: HUGEINT);
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	ASSERT(divisor > 0);
+	IF dividend >= 0 THEN
+		DivModU64(dividend, divisor, quotient, remainder)
+	ELSE
+		dividend := -dividend;
+		DivModU64(dividend, divisor, quotient, remainder);
+		quotient := -quotient;
+		IF remainder # 0 THEN
+			DEC(quotient);
+			remainder := divisor - remainder
+		END
+	END
+END DivModS64;
+
+(* Count leading zeros in a binary representation of a given 64-bit integer number *)
+PROCEDURE Clz64*(x: UHUGEINT): LONGINT;
+CODE
+	; high-half
+	LDR R1, [FP,#x+4]
+	CMP R1, #0 ; if high-half is zero count leading zeros of the low-half
+	BEQ LowHalf
+
+	CLZ R0, R1
+	B Exit
+
+	; low-half
+LowHalf:
+	LDR R1, [FP,#x]
+	CLZ R0, R1
+	ADD R0, R0, #32 ; add 32 zeros from the high-half
+
+Exit:
+END Clz64;
+
+(*
+	Fast 64-bit unsigned integer division/modulo (Alexey Morozov)
+*)
+PROCEDURE DivModU64*(dividend, divisor: UHUGEINT; VAR quotient, remainder: UHUGEINT);
+VAR m: LONGINT;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	quotient := 0;
+
+	IF dividend = 0 THEN remainder := 0; RETURN; END;
+	IF dividend < divisor THEN remainder := dividend; RETURN; END;
+
+	m := Clz64(divisor) - Clz64(dividend);
+	ASSERT(m >= 0);
+
+	divisor := LSH(divisor,m);
+	WHILE m >= 0 DO
+		quotient := LSH(quotient,1);
+		IF dividend >= divisor THEN
+			INC(quotient);
+			DEC(dividend,divisor);
+		END;
+		divisor := LSH(divisor,-1);
+		DEC(m);
+	END;
+
+	remainder := dividend;
+END DivModU64;
+
+END CPU.

+ 142 - 0
source/Zynq.Environment.Mod

@@ -0,0 +1,142 @@
+(* Zynq environment *)
+(* Copyright (C) Florian Negele *)
+
+MODULE Environment;
+
+IMPORT SYSTEM, Activities, CPU, HeapManager, Interrupts, Trace, Processors, Timer;
+
+CONST Running* = 0; ShuttingDown* = 1; Rebooting* = 2;
+
+VAR memory: SIZE;
+VAR heap: HeapManager.Heap;
+VAR frequency: Timer.Counter;
+VAR status* := Running: WORD;
+
+PROCEDURE {NORETURN} Abort-;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	IF SYSTEM.GetActivity () # NIL THEN Activities.TerminateCurrentActivity END;
+	Activities.TerminateCurrentActivity;
+END Abort;
+
+PROCEDURE Allocate- (size: SIZE): ADDRESS;
+VAR result, address: ADDRESS;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	result := HeapManager.Allocate (size, heap);
+	IF result = NIL THEN RETURN NIL END;
+	FOR address := result TO result + size - 1 DO SYSTEM.PUT8 (address, 0) END;
+	RETURN result;
+END Allocate;
+
+PROCEDURE Deallocate- (address: ADDRESS);
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	HeapManager.Deallocate (address, heap);
+END Deallocate;
+
+PROCEDURE Write- (character: CHAR);
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	WHILE CPU.TXFULL IN CPU.ReadMask (CPU.UART1 + CPU.Channel_sts_reg0) DO END;
+	CPU.WriteWord (CPU.UART1 + CPU.TX_RX_FIFO0, LSH (ORD (character), CPU.FIFO));
+END Write;
+
+PROCEDURE Flush-;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	REPEAT UNTIL CPU.TXEMPTY IN CPU.ReadMask (CPU.UART1 + CPU.Channel_sts_reg0);
+END Flush;
+
+PROCEDURE GetString- (CONST name: ARRAY OF CHAR; VAR result: ARRAY OF CHAR);
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	result[0] := 0X
+END GetString;
+
+PROCEDURE Clock- (): LONGINT;
+BEGIN RETURN Timer.GetCounter () DIV frequency;
+END Clock;
+
+PROCEDURE Sleep- (milliseconds: LONGINT);
+VAR clock: Timer.Counter;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	ASSERT (milliseconds >= 0);
+	clock := Timer.GetCounter () + milliseconds * frequency;
+	WHILE Timer.GetCounter () - clock < 0 DO Activities.Switch END;
+END Sleep;
+
+PROCEDURE Shutdown*;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	IF CAS (status, Running, ShuttingDown) # Running THEN RETURN END;
+	Trace.StringLn ("system: shutting down...");
+END Shutdown;
+
+PROCEDURE Reboot*;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	Shutdown;
+	ASSERT (CAS (status, ShuttingDown, Rebooting) = ShuttingDown);
+END Reboot;
+
+PROCEDURE {NORETURN} Exit- (status: WORD);
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	Trace.String ("system: ");
+	IF status = Rebooting THEN Trace.StringLn ("rebooting..."); CPU.Reset END;
+	Trace.StringLn ("ready for power off or restart"); Flush; CPU.Halt;
+END Exit;
+
+PROCEDURE InitTrace;
+CONST BaudRate = 115200;
+CONST BDIV = 6; CD = CPU.UART_REF_CLK DIV BaudRate DIV (BDIV + 1);
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	CPU.WriteMask (CPU.UART_RST_CTRL, {CPU.UART1_REF_RST, CPU.UART1_CPU1X_RST});
+	CPU.WriteMask (CPU.UART1 + CPU.mode_reg0, {CPU.PAR + 2});
+	CPU.WriteMask (CPU.UART1 + CPU.Intrpt_dis_reg0, {0..12});
+(*	commented out to reuse UART settings from bootloader
+	CPU.WriteMask (CPU.UART1 + CPU.Control_reg0, {CPU.RXDIS, CPU.TXDIS});
+	CPU.WriteWord (CPU.UART1 + CPU.Baud_rate_gen_reg0, LSH (CD, CPU.CD));
+	CPU.WriteWord (CPU.UART1 + CPU.Baud_rate_divider_reg0, LSH (BDIV, CPU.BDIV));
+	CPU.WriteMask (CPU.UART1 + CPU.Control_reg0, {CPU.RXRST, CPU.TXRST});
+	CPU.WriteMask (CPU.UART1 + CPU.Control_reg0, {CPU.RXEN, CPU.TXEN});
+*)
+	Trace.Init; Trace.Char := Write;
+END InitTrace;
+
+PROCEDURE InitMemory;
+CONST MemorySize = 512 * 1024 * 1024;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	HeapManager.Initialize (heap, ADDRESS OF KernelEnd, MemorySize);
+	memory := MemorySize - ADDRESS OF KernelEnd;
+END InitMemory;
+
+PROCEDURE Initialize-;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	CPU.Initialize; InitTrace; InitMemory;
+	frequency := Timer.GetFrequency () DIV 1000;
+END Initialize;
+
+PROCEDURE Terminate-;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	Interrupts.Terminate;
+END Terminate;
+
+PROCEDURE {NOPAF, INITIAL, FIXED(100000H)} KernelBegin;
+CODE
+	; initialize SP
+	MOV	SP, #0x8000
+	MRC	P15, 0, R0, C0, C0, 5
+	AND	R0, R0, #0x1
+	SUB	SP, SP, R0, LSL #13
+
+	; filter CPU
+	CMP	R0, #0
+	BEQ	skip
+	WFE
+	B		@Processors.Boot
+skip:
+END KernelBegin;
+
+PROCEDURE {NOPAF, FINAL, ALIGNED(32)} KernelEnd;
+CODE
+END KernelEnd;
+
+BEGIN {UNCHECKED}
+	Trace.String ("Version "); Trace.String (SYSTEM.Date); Trace.String (" (");
+	Trace.Int (memory DIV (1024 * 1024), 0); Trace.String (" MB RAM, GC, ");
+	Trace.Int (Processors.count, 0); Trace.String (" CPU");
+	IF Processors.count > 1 THEN Trace.Char ('s') END; Trace.Char (')'); Trace.Ln;
+END Environment.

+ 70 - 0
source/Zynq.Processors.Mod

@@ -0,0 +1,70 @@
+(* Runtime support for Zynq *)
+(* Copyright (C) Florian Negele *)
+
+(** The Processors module represents all logical processors of the system. *)
+MODULE Processors;
+
+IMPORT SYSTEM, Counters, CPU;
+
+(** Indicates the maximal number of logical processors that are supported by the system. *)
+CONST Maximum* = 2 + CPU.Interrupts;
+
+(** Holds the actual number of processors in the system. *)
+VAR count-: SIZE;
+
+VAR running: Counters.AlignedCounter; (* counts the number of application processors currently running *)
+
+(** Returns the unique index of the processor executing this procedure call. *)
+PROCEDURE GetCurrentIndex- EXTERN "Activities.GetCurrentProcessorIndex" (): SIZE;
+
+(** Suspends the execution of the current processor. *)
+(** A suspended processor must be resumed by a call to the Processors.ResumeAnyProcessor procedure. *)
+(** @topic Scheduling *)
+PROCEDURE SuspendCurrentProcessor-;
+CODE
+	WFE
+END SuspendCurrentProcessor;
+
+(** Resumes the execution of a single suspended processor. *)
+(** @topic Scheduling *)
+PROCEDURE ResumeAllProcessors-;
+CODE
+	SEV
+END ResumeAllProcessors;
+
+(** Starts the execution of all available processors. *)
+(** @topic Scheduling *)
+PROCEDURE StartAll-;
+CODE
+	SEV
+END StartAll;
+
+PROCEDURE {NORETURN, NOPAF} Boot;
+PROCEDURE Idle EXTERN "Activities.Idle";
+PROCEDURE Execute EXTERN "Activities.Execute" (procedure: PROCEDURE);
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	Counters.Inc (running);
+	SuspendCurrentProcessor;
+	SuspendCurrentProcessor;
+	Execute (Idle);
+	Counters.Dec (running);
+	CPU.Halt;
+END Boot;
+
+(** Initializes the module by enumerating all available processors. *)
+(** @topic Runtime Call *)
+PROCEDURE Initialize-;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	ResumeAllProcessors;
+	REPEAT UNTIL Counters.Read (running) = 1;
+	count := 2;
+END Initialize;
+
+(** Terminates the module and waits for all other processors to stop their execution. *)
+(** @topic Runtime Call *)
+PROCEDURE Terminate-;
+BEGIN {UNCOOPERATIVE, UNCHECKED}
+	REPEAT UNTIL Counters.Read (running) = 0;
+END Terminate;
+
+END Processors.

+ 18 - 0
source/Zynq.Timer.Mod

@@ -0,0 +1,18 @@
+(* Runtime support for high precision timer *)
+(* Copyright (C) Florian Negele *)
+
+MODULE Timer;
+
+IMPORT CPU;
+
+TYPE Counter* = LONGINT;
+
+PROCEDURE GetCounter- (): Counter;
+BEGIN {UNCOOPERATIVE, UNCHECKED} RETURN CPU.ReadWord (CPU.Global_Timer_Counter_Register0);
+END GetCounter;
+
+PROCEDURE GetFrequency- (): Counter;
+BEGIN {UNCOOPERATIVE, UNCHECKED} RETURN 400000000;
+END GetFrequency;
+
+END Timer.