Skip to content

Language Reference

Vedant Paranjape edited this page Oct 23, 2020 · 5 revisions

Language Syntax

  • simpPRU is a procedural programming language.
  • It is a statically typed language. Variables and functions must be assigned data types during compilation.
  • It is typesafe, and data types of variables are decided during compilation.
  • simPRU codes have a .sim extension.

Datatypes

  • int - Integer datatype
  • bool - Boolean datatype
  • void - Void datatype, can only be used a return type for functions

Constants

  • <any_integer> - Integer constant
  • true - Boolean constant (True)
  • false - Boolean constant (False)
  • Px_yz - Pin mapping constants are Integer constant, where x is 1,2 or 8,9 and yz are the header pin numbers. For further details refer to this

Operators

  • {,} - Braces
  • (,) - Parenthesis
  • /,*,+,- - Arithmetic operators
  • >,<,==,!=,>=,<= - Comparison operators
  • ~,&,| - Bitwise operators: not, and, or
  • not,and,or - Logical operators: not, and, or
  • := - Assignment operator

Bitwise operators and Logical operators cannot be interchangeably used.

Correct: bool test := true & false | (false and true);
Wrong:   bool test := true & false | false and true;
  • Result of Arithmetic operator is Integer constant.
  • Result of Comparison, Bitwise and Logical operators is Boolean constant.
  • Only Integer constants can be used with Arithmetic operators.
  • Only Integer constants can be used with Comparison operators.
  • Only Boolean constants can be used with Bitwise and Logical operators.
Correct: bool out := 5 > 6;
Wrong:   int yy := 5 > 6;

Variable declaration

  • Datatype of variable needs to be specified during compile time.
  • Variables can be assigned values after declarations.
  • If variable is not assigned a value after declaration, it is set to 0 for integer and to false for boolean by default.
  • Variables can be assigned other variables of same datatype.
  • Variables can be assigned expressions whose output is of same datatype.

Declaration

int var;
bool test_var;

Assignment during Declaration

int var := 99;
bool test_var := false;

Assignment

var := 45;
test_var := true;
  • Variables to be assigned must be declared earlier.
  • Datatype of the variables cannot change. Only appropriate expressions/constants of their respective datatypes can be assigned to the variables.
  • Integer variable can be assigned only Integer expression/constant.
  • Boolean variable can be assigned only Boolean expression/constant.

Comments

  • TBD

Keyword and Identifiers

Reserved keywords

true read_counter stop_counter
false start_counter pwm
int delay digital_write
bool digital_read def
void return or
if and not
elif continue break
else while in
for init_message_channel send_message
receive_message

Valid identifier naming

  • An identifier/variable name must be start with an alphabet or underscore (_) only, no other special characters, digits are allowed as first character of the identifier/variable name.

    product_name, age, _gender

  • Any space cannot be used between two words of an identifier/variable; you can use underscore (_) instead of space.

    product_name, my_age, gross_salary

  • An identifier/variable may contain only characters, digits and underscores only. No other special characters are allowed, and we cannot use digit as first character of an identifier/variable name (as written in the first point).

    length1, length2, _City_1

Detailed info: https://www.includehelp.com/c/identifier-variable-naming-conventions.aspx

Expressions

Arithmetic expressions

=> ((3+3)/2)
=> 3

Boolean expressions

=> (false & true) | ~false
=> true

=> (true and true) & (not false)
=> true

=> (3 > 4) and false
=> false

=> (4 != 3) & (false and true)
=> false

=> true
=> true

=> false
=> false

!!! Note Expressions are evaluated following the operator precedence

If-else statement

Statements in the if-block are executed only if the if-expression evaluates to true. If the value of expression is true, statement1 and any other statements in the block are executed and the else-block, if present, is skipped. If the value of expression is false, then the if-block is skipped and the else-block, if present, is executed. If elif-block are present, they are evaluated, if they become true, the statement is executed, otherwise, it goes on to eval next set of statements

Syntax

if : boolean_expression {
    statement 1
    ...
    ...
}
elif : boolean_expression {
    statement 2
    ...
    ...
    ...
}
else {
    statement 3
    ...
    ...
}

Examples

int a := 3;

if : a != 4 {
    a := 4;
}
elif : a > 4 {
    a := 10;
}
else {
    a := 0;
}
  • This will evaluate as follows, since a = 3, if-block (3!=4) will evaluate to true, and value of a will be set to 4, and program execution will stop.

For-loop statement

For loop is a range based for loop. Range variable is a local variable with scope only inside the for loop.

Syntax

for : var in range_1:range_2 {
    statement 1
    ....
    ....
}
  • Here, for loop is a range based loop, value of integer variable var will vary from range_1 to range_2 - 1. Value of var doesnot equal range_2. As of now range can't be reversed,i.e., range_1 < range_2

📔 var is a integer, and range_1, range_2 can be arithmetic expression, integer variable or integer constant.

Examples

int sum := 0;

for : i in 1:4 {
    sum = sum + i;
}
int mx := 32;
int nt;

for : j in 2:mx-10 {
    nt := nt + j;
}

While-loop statement

While loop statement repeatedly executes a target statement as long as a given condition is true.

Syntax

while : boolean_expression {
    statement 1
    ...
    ...
}

Examples

  • Infinite loop
while true {
    do_something..
    ...
}
  • Normal loop, will repeat 30 times, before exiting
int tag := 0;

while : tag < 30 {
    tag := tag + 1;
}

Control statements

⚠️ break and continue should only be used inside looping statements

break

break is used to break execution in a loop statement, either for loop or while loop. It exits the loop upon calling.

Syntax

break;

Examples

for : i in 0:9 {
    if : i == 3 {
        break;
    }
}

continue

continue is used to continue execution in a loop statement, either for loop or while loop.

Syntax

continue;

Examples

for : j in 9:19 {
    if : i == 12 {
        continue;
    }
    else {
        break;
    }
}

Functions

Function definition

A function is a group of statements that together perform a task. You can divide up your code into separate functions. How you divide up your code among different functions is up to you, but logically the division usually is such that each function performs a specific task. A function declaration tells the compiler about a function's name, return type, and parameters. A function definition provides the actual body of the function.

⚠️ Function must be defined before calling it.

Syntax

def <function_name> : <data_type> : <data_type> <param_name>, <data_type> <param_name>, ... {
    statement 1;
    ...
    ...

    return <data_type>;
}

📔 If return data type is void, then return statement is not needed, and if still it is added, it must be return nothing, i.e., something like this return ;

⚠️ return can only be present in the body of the function only once, that too at the end of the function, not inside any compound statements.

return inside a compound statement, this syntax is not allowed.

def test : int : int a {
    if : a < 4 {
        return a;
    }
}

return is not inside compound statments, It should be placed only at the end of function definition

def test : int : int a {
    int gf := 8;
    if : a < 4 {
        gf := 4;
    }

    return gf;
}

Examples

Examples according to return types

  • integer
def test_func : int : int a, int b {
    int aa := a + 5;

    if : aa < 3 {
        aa : = 0;
    }

    return aa + b;
}
  • boolean
def compare : bool : int val {
    bool ret := false;

    if : val < 0 {
        ret := true;
    }

    return ret;
}
  • void
def example_func : void : bool qu {
    if : qu and true {
        ...
        do something
        ...
    }
}

def example_func_v : void : {
    int temp := 90;

    return;
}

Function call

Functions can be called only if, they have been defined earlier. They return data types according to their definition. Parameters are passed by value. Only pass by value is supported as of now.

Syntax

function_name(var1, var2, ..);

Examples

We will consider functions defined in earlier subsection

  • integer
int a := 55;
int ret_val := test_func(4, a);
  • boolean
bool val := compare(22);
compare(-2);
  • void
example_func(false);
example_func_v();

IO Functions

PRU<-->Header pin mappings

  • PocketBeagle

    • PRU0

      R30 Register bit (Output) R31 Register bit (Input) Header pin
      - 16 P1_20
      7 7 P1_29
      4 4 P1_31
      1 1 P1_33
      0 0 P1_36
      - 15 P2_18
      15 - P2_33
      - 14 P2_22
      14 - P2_24
      6 6 P2_28
      3 3 P2_30
      2 2 P2_32
      5 5 P2_34
    • PRU1

      R30 Register bit (Output) R31 Register bit (Input) Header pin
      9 9 P1_02
      11 11 P1_04
      15 15 P1_30
      14 14 P1_32
      10 10 P1_35
      - 16 P2_31
      8 8 P2_35
  • BeagleBone Black

    • PRU0

      R30 Register bit (Output) R31 Register bit (Input) Header pin
      - 15 P8_15
      15 - P8_11
      - 14 P8_16
      14 - P8_12
      7 7 P9_25
      5 5 P9_27
      3 3 P9_28
      1 1 P9_29
      2 2 P9_30
      0 0 P9_31
      6 6 P9_41
      4 4 P9_42
    • PRU1

      R30 Register bit (Output) R31 Register bit (Input) Header pin
      13 13 P8_20
      12 12 P8_21
      8 8 P8_27
      10 10 P8_28
      9 9 P8_29
      6 6 P8_39
      7 7 P8_40
      4 4 P8_41
      5 5 P8_42
      2 2 P8_43
      3 3 P8_44
      0 0 P8_45
      1 1 P8_46

      ** Before using these pins, you need to disable HDMI functionality.
      You can read how to do this here

  • BeagleBone Black Wireless

    • PRU0

      R30 Register bit (Output) R31 Register bit (Input) Header pin
      - 15 P8_15
      15 - P8_11
      - 14 P8_16
      14 - P8_12
      7 7 P9_25
      5 5 P9_27
      3 3 P9_28
      1 1 P9_29
      2 2 P9_30
      0 0 P9_31
      6 6 P9_41
      4 4 P9_42
    • PRU1

      R30 Register bit (Output) R31 Register bit (Input) Header pin
      13 13 P8_20
      12 12 P8_21
      8 8 **P8_27
      10 10 **P8_28
      9 9 **P8_29
      6 6 **P8_39
      7 7 **P8_40
      4 4 **P8_41
      5 5 **P8_42
      2 2 **P8_43
      3 3 **P8_44
      0 0 **P8_45
      1 1 **P8_46

      ** Before using these pins, you need to disable HDMI functionality.
      You can read how to do this here

  • BeagleBone AI

    • PRU0

      R30 Register bit (Output) R31 Register bit (Input) Header pin
      3 3 P8_12
      4 4 P8_11
      5 5 P9_15
      17 17 P9_26
    • PRU1

      R30 Register bit (Output) R31 Register bit (Input) Header pin
      1 1 P9_20
      2 2 P9_19
      3 3 P9_41
      5 5 P8_18
      6 6 P8_19
      7 7 P8_13
      9 9 P8_14
      10 10 P9_42
      11 11 P9_27
      14 14 P9_14
      15 15 P9_16
      16 16 P8_15
      17 17 P8_26
      18 18 P8_16
    • PRU2

      R30 Register bit (Output) R31 Register bit (Input) Header pin
      10 10 P8_33
      11 11 P8_31
      6 6 P8_38
      7 7 P8_36
      20 20 P8_08
      15 15 P9_13
      3 3 P8_39
      2 2 P8_42
      9 9 P8_35
      8 8 P8_34
      5 5 P8_37
      4 4 P8_40
      17 17 P8_28
      18 18 P8_29
      19 19 P8_30
      1 1 P8_41
      0 0 P8_44
      14 14 P9_11
    • PRU3

      R30 Register bit (Output) R31 Register bit (Input) Header pin
      0 0 P8_32
      5 5 P9_25
      6 6 P8_09
      10 10 P9_31
      8 8 P9_18
      16 16 P8_07
      15 15 P8_10
      17 17 P8_27
      20 20 P8_43
      18 18 P8_45
      19 19 P8_46
      9 9 P9_17
      13 13 P9_28
      11 11 P9_29
      12 12 P9_30

      ** Before using these pins, you need to disable HDMI functionality.
      You can read how to do this here

  • All Header pins are constant integer variable by default, with its value equal to respective R30/R31 register bit

    • Example: P1_20 is an constant integer variable with value 16, similary P1_02 is an constant integer variable with value 9

Digital Write

digital_write is a function which enables PRU to write given logic level at specified output pin. It is a function with void return type and it's parameters are integer and boolean, first parameter is the pin number to write to or PRU R30 register bit and second parameter is boolean value to be written. true for HIGH and false for LOW.

Syntax

digital_write(pin_number, value);

Parameters

  • pin_number is an integer. It must be a header pin name which supports output, or PRU R30 Register bit.
  • value is a boolean. It is used to set logic level of the output pin, true for HIGH and false for LOW.

Return Type

  • void - returns nothing.

Example

int a := 32;

if : a < 32 {
    digital_write(P1_29, true);
}
else {
    digital_write(P1_29, false);
}

If the value of a < 32, then pin P1_29 is set to HIGH or else it is set to LOW.

Digital Read

digital_read is a function which enables PRU to read logic level at specified input pin. It is a function with return type boolean and it's parameter is a integer whose value must be the pin number to be read or PRU R31 register bit.

Syntax

digital_read(pin_number);

Parameters

  • pin_number is an integer. It must be a header pin name which supports input, or PRU R31 Register bit.

Return Type

  • boolean - returns the logic level of the pin number passed to it. It returns true for HIGH and false for LOW.

Example

if digital_read(P1_20) {
    digital_write(P1_29, false);
}
else {
    digital_write(P1_29, true);
}

Logic level of pin P1_20 is read. If it is HIGH, then pin P1_29 is set to LOW, or else it is set to HIGH.

Delay

delay is a function which makes PRU wait for specified milliseconds. When this is called PRU does absolutely nothing, it just sits there waiting.

Syntax

delay(time_in_ms);

Parameters

  • time_in_ms is an integer. It is the amount of time PRU should wait in milliseconds. (1000 milliseconds = 1 second).

Return Type

  • void - returns nothing.

Example

digital_write(P1_29, true);
delay(2000);
digital_write(P1_29, false);

Logic level of pin P1_29 is set to HIGH, PRU waits for 2000 ms = 2 seconds, and then sets the logic level of pin P1_29 to LOW.

Start counter

start_counter is a function which starts PRU's internal counter. It counts number of CPU cycles. So it can be used to count time elapsed, as it is known that each cycle takes 5 nanoseconds.

Syntax

start_counter()

Paramters

  • n/a

Return Type

  • void - returns nothing.

Example

start_counter();

Stop counter

stop_counter is a function which stops PRU's internal counter.

Syntax

stop_counter()

Paramters

  • n/a

Return Type

  • void - returns nothing.

Example

stop_counter();

Read counter

read_counter is a function which reads PRU's internal counter and returns the value. It counts number of CPU cycles. So it can be used to count time elapsed, as it is known that each cycle takes 5 nanoseconds.

Syntax

read_counter()

Parameters

  • n/a

Return Type

  • integer - returns the number of cycles elapsed since calling start_counter.

Example

start_counter();

while : read_counter < 200000000 {
    digital_write(P1_29, true);
}

digital_write(P1_29, false);
stop_counter();

while the value of hardware counter is less than 200000000, it will set logic level of pin P1_29 to HIGH, after that it will set it to LOW. Here, 200000000 cpu cycles means 1 second of time, as CPU clock is 200 MHz. So, LED will turn on for 1 second, and turn off after.

Init message channel

init_message_channel is a function which is used to initialise communication channel between PRU and the ARM core. It is sets up necessary structures to use RPMSG to communicate, it expects a init message from the ARM core to initialise. It is a necessary to call this function before using any of the message functions.

Syntax

init_message_channel()

Parameters

  • n/a

Return Type

  • void - returns nothing

Example

init_message_channel();

Receive message

receive_message is a function which is used to receive messages from ARM to the PRU, messages can only be integers, as only they are supported as of now. It uses RPMSG channel setup by init_message_channel to receive messages from ARM core.

Syntax

receive_message()

Parameters

  • n/a

Return Type

  • integer - returns integer data received from PRU

Example

init_message_channel();

int emp := receive_message();

if : emp >= 0 {
    digital_write(P1_29, true);
}
else {
    digital_write(P1_29, false);
}

Send message

send_message is a function which is used to send messages to ARM core from PRU, messages can only be integers. It uses RPMSG channel setup by init_message_channel to send messages from PRU to the ARM core.

Syntax

send_message(message)

Parameters

  • message is an integer, number passed to it is sent to the ARM core, through RPMSG.

Example

init_message_channel();

if : digital_read(P1_29) {
    send_message(1);
}
else {
    send_message(0);
}