232 lines
7.9 KiB
Plaintext
232 lines
7.9 KiB
Plaintext
/*
|
|
* 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: <output_port> to <node>
|
|
* 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])/*;*/
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|