Skip to content

Commit

Permalink
address issues and typos
Browse files Browse the repository at this point in the history
  • Loading branch information
renau committed Feb 8, 2024
1 parent 3811cfd commit 29adf58
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 43 deletions.
6 changes: 3 additions & 3 deletions docs/pyrope/00-hwdesign.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ iterate in loops, and the program finishes execution when the main finishes.

In contrast, most HDLs differ from software languages in that they specify an
instantiation tree hierarchy of modules, and then provide some syntax on how
each module executes independently of the other modules.
each module executes independently of the other modules.


In HDLs, the execution never ends, and the modules run independently. It
Expand Down Expand Up @@ -330,7 +330,7 @@ be expected in a software API.
If actors execution resembles concurrent module instantiation execution,
async/await resembles pipelining. In async/await, the results of a function are
not available at the function return. In HDLs, there is no await, and the
results from previous cycles are output by the module instance.
results from previous cycles are output by the module instance.



Expand Down Expand Up @@ -604,7 +604,7 @@ not be recycled. As a result, the destructor may not make sense in hardware.

Most software languages support passing function arguments either by value or
reference. This is done to avoid copying the object that may reside in memory.
Again, HLS has no memory. Therefore it is not as problematic.
Again, HLS has no memory. Therefore it is not as problematic.

Most HDLs only support passing by value. This is not a drawback but avoid
another source of bugs without the cost overhead that it will represent in a
Expand Down
2 changes: 1 addition & 1 deletion docs/pyrope/02-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ can have side effects. Pyrope constrains the expressions so that no matter the
evaluation order, the synthesis result is the same.


As a reference, languages like C++11 do not have a defined order of evaluation for
Languages like C++11 do not have a defined order of evaluation for
all types of expressions. Calling `call1() + call2()` is not defined. Either
`call1()` first or `call2()` first.

Expand Down
27 changes: 20 additions & 7 deletions docs/pyrope/03-bundle.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ cassert a!=b
cassert b == c == d
```

A tuple with a single entry element is called a scalar.
A tuple with a single entry element is called a scalar.

Tuples are used in many places:

Expand Down Expand Up @@ -173,7 +173,7 @@ can be used for name or default value during the tuple declaration.

```
var b = 100
var a = (b:u8, b, b:u8 = _, let c=4) // a.0 and a.1 are unnamed, a.2==a.b
var a = (b:u8, b, b:u8 = _, let c=4) // a.0 and a.1 are unnamed, a.2==a.b
a.b = 200
assert a == (100, 100, 200, 4)
Expand Down Expand Up @@ -233,7 +233,7 @@ the same entry already exists.
## Field access

Since everything is a tuple, any variable can do `variable.0.0.0.0` because it
literaly means, return the tuple first entry for four times.
literaly means, return the tuple first entry for four times.


Another useful shortcut is when a tuple has a single field or entry, the tuple
Expand All @@ -253,6 +253,17 @@ assert x.0 == 3
```


Tuples can also use structural binding to unpack a tuple multiple fields into separate variables.

```
let x = (f1=(f1a=1,f1b=3), f2=4)
let (y,z) = x
assert y == (1,3) and z == 4
assert y.f1a == 1 and y.f1b == 3
assert y == (f1a=1,f1b=3)
```

## Tuples vs arrays

Tuples are ordered, as such, it is possible to use them as arrays. Tuples and
Expand All @@ -262,6 +273,8 @@ unnamed with the same type for all the entries.
```
var bund1 = (0,1,2,3,4) // ordered and can be used as an array
var array1 = [0,1,2,3,4] // [] force array, so all the entries have same type
var bund2 = (bund1,bund1,((10,20),30))
assert bund2[0][1] == 1
assert bund2[1][1] == 1
Expand Down Expand Up @@ -290,7 +303,7 @@ if runtime {
}
// Index can be 2 or 4
var res1 = array[index] // compile error, out of bounds access
var res1 = array[index] // compile error, out of bounds access
var res2 = 0sb? // Possible code to be compatible with Verilog
if index<3 {
Expand Down Expand Up @@ -347,15 +360,15 @@ b = xx[1,2] // same as: xx[(1,2)]
for a in 1,2,3 { // same as: for a in (1,2,3) {
x = a
}
y = match z {
y = match z {
in 1,2 { 4 } // same as: in (1,2) { 4 }
else { 5 }
}
y2 = match var one=1 ; one ++ z { // same as: y2 = match (1,z) {
== (1,2) { 4 }
}
let addb = fun(a,b:u32)-> a:u32 { // same as: letaddb = fun(a,b:u32)->(a:u32)
let addb = fun(a,b:u32)-> a:u32 { // same as: letaddb = fun(a,b:u32)->(a:u32)
a = a + b
}
```
Expand Down Expand Up @@ -387,7 +400,7 @@ let c = 4
let (x,b) = (true, c:u3) // assign x=true, b=4 AND check that c is type u3
cassert x == true
cassert b == 4
cassert b == 4
```

## Enumerate (`enum`)
Expand Down
59 changes: 46 additions & 13 deletions docs/pyrope/04-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,13 +257,13 @@ assert b@[0] == false
```


A range is a separate tuple. As such it can not directly compare with
A range is a separate tuple. As such it can not directly compare with
tupes. It requires an explicit conversion. If the range does not contain
negative values, it can be converted to an integer back and forth which
corresponds to a one-hot encoding.

Range type cast from integers use the same one-hot encoding. It is not possible
to type cast from tuple to range, but it is possible from range to tuple.
to type cast from tuple to range, but it is possible from range to tuple.

```
let c = 1..=3
Expand Down Expand Up @@ -340,7 +340,7 @@ assert "h" ++ "ell" == ('h','e','l','l') == "hell"
## Type declarations

Each variable has a type, either implicit or explicit, and as such, it can be
used to declare a new type.
used to declare a new type.

Pyrope does not have a `type` keyword. Instead it leverages the tuples for type
creation. The difference is that a type should be an immutable variable, and
Expand Down Expand Up @@ -371,7 +371,7 @@ assert x equals z // same type structure
assert y is typ
assert typ is typ
assert z !is bund3
assert z !is bund3
assert z !is typ
assert z !is bund1
```
Expand Down Expand Up @@ -405,11 +405,17 @@ number of bits in an assertion, or placement hints, or even interact with the
synthesis flow to read timing delays.


Pyrope does not specify the attributes, the compiler flow specifies them.
A key difference from attribute and tuple fields is that attributes are always
compile time and the compiler flow has special meaning functionality for them.


Pyrope does not specify all the attributes, the compiler flow specifies them.
There are some built-in required attributes like checking the number of bits.

Reading attributes should not affect a logical equivalence check. Writing
attributes can have a side-effect because it can change bits use for
wrap/saturate or change pins like reset/clock in registers. Additionally,
attributes can affect assertions, so they can stop/abort the compilation.
attributes can affect assertions, so they can stop/abort the compilation.


The are three operations that can be done with attributes: set, check, read.
Expand All @@ -418,7 +424,7 @@ The are three operations that can be done with attributes: set, check, read.
assignment or directly accessed. If a variable definition, this binds the
attribute with all the use cases of the variable. If the variable just
changes attribute value, a direct assignment is possible E.g: `foo::[max=300]
= 4` or `baz.[attr] = 10`
= 4` or `baz.[attr] = 10`

* Check: when associated to a type property in the right-hand-side of an
assignment. The attribute is a comma separated list of boolean expression
Expand All @@ -430,7 +436,7 @@ The are three operations that can be done with attributes: set, check, read.

The attribute set, writes a value to the attribute. If no value is given a
boolean `true` is set. The attribute checks are expressions that must evaluate
true.
true.


Since conditional code can depend on an attribute, which results in executing a
Expand Down Expand Up @@ -764,8 +770,8 @@ tuple or file the `private` attribute must be set.

The private has different meaning depending on when it is applied:

* When applied to a tuple entry (`(field::[private] = 3)`), it means that the
entry can not be accessed outside the tuple.
* When applied to a tuple entry (`(field::[private] = 3)`), it means that the
entry can not be accessed outside the tuple.

* When applied to a `pipestage` variable (`var foo::[private] = 3`), it means that the
variable is not pipelined to the next type stage. Section
Expand Down Expand Up @@ -833,7 +839,7 @@ cassert 1<<(1,4,3) == 0b01_1010
string, or already a tuple

Most operations behave as expected when applied to signed unlimited precision
integers.
integers.

The `a in b` checks if values of `a` are in `b`. Notice that both can be
tuples. If `a` is a named tuple, the entries in `b` match by name, and then
Expand Down Expand Up @@ -1091,11 +1097,14 @@ i = a == 3 <= b == d
assert i == (a==3 and 3<=b and b == d)
```

Comparators can be chained, but only when they follow the same type.
Comparators can be chained, but only when they follow the same type or the
direction is the same.

```
assert a <= b <= c // same as a<=b and b<=c
assert a < b <= c // same as a< b and b<=c
assert a == b <= c // compile error, chained only allowed with same comparator
assert a <= b > c // compile error, not same direction
```

## Optional
Expand Down Expand Up @@ -1315,7 +1324,7 @@ The same rules apply when a tuple or a type is declared.
let a = "foo"
var at1 = (
,a:string
,a:string
)
cassert at1[0] == "foo"
cassert at1 !has "a" // at1.a undefined
Expand Down Expand Up @@ -1364,3 +1373,27 @@ assert rand implies z == 5
assert !rand implies z == 6
```

It is also possible to assign to an underscore, it behaves like a sink. It may be useful when dealing
with structured bindings ()multiple return values) with unused arguments.


```
let weird_pick_bits = fun(b:u32) -> (x:u1, _:u4) {
return (x=n@[2..<3], b@[5])
}
fun fcall_returns_2_values()->(xx,yy) {
xx = 3
yy = 7
}
let (a,_) = fcall_returns_2_values()
assert a == 3
var b:u8 = 3
_ = a // legal, but it is just a "read" to 'a'
_ = 3
b = _
assert b == 0 and not b.[valid]
```

30 changes: 16 additions & 14 deletions docs/pyrope/06-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,14 @@ The lambda definition has the following fields:

```
var add:fun(...x) = _
add = fun (...x) { x.0+x.1+x.2 } // no IO specified
add = fun (a,b,c){ a+b+c } // constrain inputs to a,b,c
add = fun (a,b,c){ a+b+c } // same
add = fun (a:u32,b:s3,c){ a+b+c } // constrain some input types
add = fun (a,b,c) -> (x:u32){ a+b+c } // constrain result to u32
add = fun (a,b,c) -> (res){ a+b+c } // constrain result to be named res
add = fun (a,b:a,c:a){ a+b+c } // constrain inputs to have same type
add = fun <T>(a:T,b:T,c:T){ a+b+c } // same
add = fun(...x) { x.0+x.1+x.2 } // no IO specified
add = fun(a,b,c){ a+b+c } // constrain inputs to a,b,c
add = fun(a,b,c){ a+b+c } // same
add = fun(a:u32,b:s3,c){ a+b+c } // constrain some input types
add = fun(a,b,c) -> (x:u32){ a+b+c } // constrain result to u32
add = fun(a,b,c) -> (res){ a+b+c } // constrain result to be named res
add = fun(a,b:a,c:a){ a+b+c } // constrain inputs to have same type
add = fun<T>(a:T,b:T,c:T){ a+b+c } // same
x = 2
var add2:fun2(a) = _
Expand Down Expand Up @@ -201,8 +201,7 @@ There are several rules on how to handle arguments.
* Function calls with arguments do not need parenthesis after newline or a
variable assignment: `a = f(x,y)` is the same as `a = f x,y`

* Functions explicitly declared without arguments, do not need parenthesis in
function call.
* Functions without arguments, need explicit parenthesis in function call.

Pyrope uses a Uniform Function Call Syntax (UFCS) when the first argument is
`self`. It resembles Nim or D UFCS but it can be different from the order in
Expand All @@ -215,9 +214,9 @@ let div2 = fun (...x){ x.0 / x.1 } // unnamed input tuple
let noarg = fun () { 33 } // explicit no args
assert 33 == noarg()
assert 33 == noarg() // () needed to call
assert noarg == 33 // compile error, `noarg()` needed for calls without arguments
assert noarg // compile error, `noarg()` needed for calls without arguments
a=div(3 , 4 , 3) // compile error, div has 2 inputs
b=div(self=8, b=4) // OK, 2
Expand Down Expand Up @@ -252,7 +251,7 @@ var tup = (
)
let f1 = fun (self){ 2 } // compile error, f1 shadows tup.f1
let f2 = fun (self){ 3 }
let f1 = fun (){ 3 } // OK, no
assert f1() != 0 // compile error, missing argument
assert f1(tup) != 0 // compile error, f1 shadowing (tup.f1 and f1)
Expand Down Expand Up @@ -340,13 +339,16 @@ inc1(ref y)
assert y == 4
let banner = fun() { puts "hello" }
let execute_method = fun(fn) {
let execute_method = fun(fn:fun()->()) { // example with explicit type for fn
fn() // prints hello when banner passed as argument
}
execute_method(banner) // OK
```

In Pyrope, to call a method, parenthesis are needed only when the method has arguments.
This is needed to distinguish for higher order functions that need to distinguish between
a function call and a pass of the lambda.

## Output tuple

Expand Down
Loading

0 comments on commit 29adf58

Please sign in to comment.