/* * Lexical conventions: * * identifiers -> ([a-z] | [A-Z]){[a-z] | [A-Z] | [0-9] | '_'} * numbers -> decimal | hexadecimal * arithmetic_op -> '+' | '-' | '*' | '[]' | '++' * boolean_op -> '!' | '&&' | '||' */ module CortexA9_Core((0 to 0xFFFFE000) core_periphbase) { // Module parameters are natural numbers and have a range /* * Node domains: {memory, intr, power, clock} * Node types have arbitrary dimension, meaning is hardware dependent * E.g. here: 1st dimension: address, 2nd dimension data word */ output memory (0 bits 8; 0 bits 32) SCU output memory (0 bits 8; 0 bits 32) Global_Timer output memory (0 bits 8; 0 bits 32) GIC_PROC // 0 bits 8 == 0 to 2^8-1 output memory (0 bits 12; 0 bits 32/*;*/) GIC_DISTR // Trailing ';' should be allowed but optional (Parser does not yet allow it) output memory (0 bits 32; 0 bits 32) L2 /* * Node declaration and definition is separate * Convention: keep together whenever possible */ input intr (0 to 1023) CPU_INTR CPU_INTR accepts [ (0, 2, 8 to 1023) // Specify sparse ranges ] memory (0 bits 8; 0 bits 32) Private_Timers Private_Timers accepts [ (0 bits 8; *) ] memory (0 bits 13; 0 bits 32) PRIVATE_PERIPH PRIVATE_PERIPH maps [ /* All dimensions of origin and target need to be specified */ (0x0000 to 0x00FC; 0 bits 32) to SCU at (0x0 to 0xFC; 0 bits 32); /* * Wildcards map whole range of dimension * The following are equivalent */ (0x0100 bits 8; *) to GIC_PROC at (*; *); (0x0100 bits 8; 0 bits 32) to GIC_PROC at (0 bits 8; 0 bits 32); /* Mapped ranges must have same size or target must be constant */ (0x0200 bits 8; *) to Global_Timer at (*; *); // OK, one-to-one mapping (0x0200 bits 8; *) to Global_Timer at (*; 0); // OK, 2nd dimension collapsed to 0 (0x0200 bits 9; *) to Global_Timer at (*; *); // Error (0x0600 bits 8; *) to Private_Timers at (*; *); (0x1000 bits 12; *) to GIC_DISTR at (*; *)/*;*/ // Trailing ';' should be allowed but optional (Parser does not yet allow it) ] memory (0 bits 32, 0 bits 32) CPU_PHYS CPU_PHYS maps [ (core_periphbase bits 13; *) to PRIVATE_PERIPH at (*; *) ] CPU_PHYS overlays L2 // overlay node's type must be the same as node's type } module CortexA9_MPCore((1 to 4) num_cores, (0 to 0xFFFFE000) periphbase) { input intr (32 to 1019) GIC input intr (0 to 1023) CPU_INTR[0 to num_cores-1] output memory (0 bits 32, 0 bits 32) L2 /* * Module instances must be declared */ instance Core[0 to num_cores-1] of CortexA9_Core Core[0 to num_cores-1] instantiates CortexA9_Core(perhiphbase) memory (0 bits 8; 0 bits 32) SCU SCU accepts [(0x0 to 0xFC; *)] memory (0 bits 8; 0 bits 32) Global_Timer Global_Timer accepts [(0 bits 8; *)] memory (0 bits 8; 0 bits 32) GIC_PROC GIC_PROC accepts [(0 bits 8; *)] memory (0 bits 12; 0 bits 32) GIC_DISTR GIC_DISTR accepts [(0 bits 12; *)] forall c in (0 to num_cores-1) { /* * Instantiate module and bind output ports * Format: to * All output ports must be bound, types of port and node must match exactly */ Core[c] binds [ SCU to Cluster_SCU; Global_Timer to Global_Timer; GIC_PROC to GIC_PROC; GIC_DISTR to GIC_DISTR; L2 to L2 ] /* * Reference input ports with dot notation */ GIC maps [ (*) to Core[c].CPU_INTR at (0 to 1019-32) ] /* * Input port pass-through, for the moment introduces proxy node */ CPU_INTR[c] overlays Core[c].CPU_INTR } } /* * Named types * Only possible at file scope * If we have a use case, we might introduce module scope types */ type L2_Bus (0 bits 32; 0 bits 32) module OMAP44xx { /* * Named constants * Only possible at module scope, use parameters to pass to other modules * Only natural number constants are possible. * If we have a use case we might introduce tuple constants */ const PERIPHBASE 0x48240000 const NUM_CORES 2 /* * Multidimensional arrays through tuple indices */ instance MPU[1 to 2; 1 to 2] of CortexA9_MPCore MPU[*; *] instantiates CortexA9_MPCore(NUM_CORES, PERIPHBASE) // Use constants MPU[*; *] binds [ L2 to L2 ] intr (0 to 1023) INTR_CTRL forall s in (1 to 2) { INTR_CTRL maps [ /* Multicast interrupt vector 1 to all 1st cores of MPU[1; 1] and MPU[2; 1] */ (1) to MPU[s; 1].CPU_INTR[1] at (0); /* Same for vector 2 to 2nd cores */ (2) to MPU[s; 1].CPU_INTR[2] at (0); /* Same for vector 3 to 1st cores of MPI[1; 2] and MPU[2; 2] */ (3) to MPU[s; 2].CPU_INTR[1] at (0); /* And for vector 4 to 2nd cores */ (4) to MPU[s; 2].CPU_INTR[2] at (0)/*;*/ ] } /* * Node definitions can be split over several statements */ INTR_CTRL maps [ (5) to MPU[1; 1].CPU_INTR[1] at (1) ] memory (0 bits 30, 0 bits 32) SDRAM SDRAM accepts [ /* * Specify 1st order logic formula for properties that has to be true for the block to match */ (0x00000000 bits 28; *) read && !write; // read-only (0x10000000 bits 28; *) read && write; // read-write (0x20000000 bits 28; *) read; // read, don't care about write (0x30000000 bits 28; *) // don't care about properties ] memory (L2_Bus) L2 // Reference named type L2 maps [ /* * Specify 1st order logic formulas for incoming and outgoing properties */ (0x80000000 bits 28; *) !write to SDRAM at (0 bits 28; *) read && !write; // map all non writeable to 1st quarter of RAM as read-only (0x80000000 bits 28; *) write to SDRAM at (0 bits 28; *) read && write; // map all writeable to 2nd quarter of RAM as read-write (0x90000000 bits 28; *) to SDRAM at (0x10000000 bits 28; *) read && write; (0xA0000000 bits 28; *) to SDRAM at (0x20000000 bits 28; *) read, SDRAM at (0x30000000, 0); // Multicast (0xB0000000 bits 28; *) to SDRAM at (0x30000000 bits 28; *)/*;*/ ] /* * Converting from one namespace to another * * Destination type is optional, if specified, all target ranges have to match */ memory (0 bits 32, 0 bits 32) to intr (32 to 1019) CHIPSET CHIPSET converts [ // (0; 0 to 1019-32) !read to MPU[1; 1].GIC at (*) edge_trig; (0; 1) to MPU[1;1].CPU_INTR[1] at (0); // Error, type does not match (0; 2) to MPU[1;1].CPU_INTR[1] at (1)/*;*/ // Error, type does not match ] intr (0 to 1023) to memory MSI_CTRL MSI_CTRL converts [ /* ... */ ] /* * Changing the dimensionality through a mapping */ memory (0 bits 7; 0 to 1) RAM_2D RAM_2D accepts [(*; *)] memory (0 bits 3; 0 bits 3; 0 bits 2) BUS_3D forall a in (0 bits 3) { forall b in (0 bits 3) { forall c in (0 bits 2) { BUS_3D maps [ /* Split address parts with slice operator: */ (0; 0; c) to RAM_2D at (c[1]; c[0]); /* Concatenate address parts with concat/slice operator :*/ (a; b; 0) to RAM_2D at (a ++ b[0 to 2]; 0); (a; b; 1) to RAM_2D at (a ++ b[0 to 2]; 1); /* * ++[] is left associative * The following are equal: */ (a; b; c) to RAM_2D at ( a ++ b[0 to 2] ++ c[1]; c[0]); (a; b; c) to RAM_2D at ((a ++ b[0 to 2]) ++ c[1]; c[0])/*;*/ ] } } } }