Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save rkrishnasanka/5176206 to your computer and use it in GitHub Desktop.
Save rkrishnasanka/5176206 to your computer and use it in GitHub Desktop.
Solutions for Udacity Course CS348 - Functional Hardware Verification
Solutions for Udacity Course CS348 - Functional Hardware Verification
STEPS
1 Start with pre-populated code
2 Guidance on exercise
3 Implement/edit code
4 (optional) Run code to assess results
5 Submit code for automatic assessment
6 Solution discussion
----------------------------------------
GUIDANCE
Field name: sender, receiver
Type: uint
Value: 212_555_0123, 408_555_0199
Field name: message
Type: string
Value: "This is a test!"
----------------------------------------
----------------------------------------
SYNTAX: field declaration
(statement, can only be done in structs)
FIELD_NAME : TYPE;
----------------------------------------
----------------------------------------
SYNTAX: assignment
(action, can only be done in methods)
FIELD_NAME = VALUE;
----------------------------------------
<'
struct txt {
// fields of data model for txt
sender : uint;
receiver: uint;
message : string;
// this is a method with no parameters
fill() is {
// assignments
sender = 212_555_0123;
receiver = 408_555_0199;
message = "This is a test!";
};
};
'>
GUIDANCE
Delete assingment for sender and receiver in fill method
<'
struct txt {
// fields of data model for txt
sender : uint;
receiver : uint;
message : string;
fill() is {
//sender = 212_555_0123;
//receiver = 408_555_0199;
message = "This is a test!";
};
};
'>
GUIDANCE
Add constraints to limit phone number values
max_number : 999_999_9999
min_number : 100_000_0000
constraint name : user choice
SYNTAX
keep CONSTRAINT_NAME is BOOLEAN_EXPRESSION;
<'
struct txt {
sender : uint;
receiver : uint;
// constraints
keep user_choice1 is sender<=999_999_9999;
keep user_choice2 is sender>=100_000_0000;
keep user_choice3 is receiver<=999_999_9999;
keep user_choice4 is receiver>=100_000_0000;
message : string;
fill() is {
message = "This is a test!";
};
};
'>
GUIDANCE
Problem: 32 bit integer too small to model 10 digit phone numbers
Solution: increase size of data type
<'
struct txt {
// increase size of data type
sender : uint(bits:34);
receiver : uint(bits:34);
keep max_sender is sender <= 999_999_9999;
keep min_sender is sender >= 100_000_0000;
keep max_receiver is receiver <= 999_999_9999;
keep min_receiver is receiver >= 100_000_0000;
message : string;
fill() is {
message = "This is a test!";
};
};
'>
GUIDANCE
Problem: sender, receiver use duplicate constraints
Solution: introduce new user defined data type
Using ranges on type definition removes need for explicit constraints
new data type name: phone_number
SYNTAX: type
type NAME : TYPE [FROM..TO];
<'
// insert user defined type BEFORE struct here
type phone_number : uint(bits:34)[100_000_0000..999_000_0000];
struct txt {
// replace type with new type defined above
sender : phone_number;
receiver : phone_number;
message : string;
fill() is {
message = "This is a test!";
};
};
'>
GUIDANCE
Add sender and receiver field
no method
no message
Type: phone_number
<'
struct call{
// fields
sender : phone_number;
receiver : phone_number;
};
'>
GUIDANCE
Message size 1 to 140 (like Twitter)
name : msg_size
type : uint - sized and range specified
Edit fill() method to adds single digit numbers to the message
(to make life easier for now)
CLASSIC FOR LOOP SYNTAX
for INDEX_NAME from N to M do {};
STRING APPEND
str = append(str, NEW_STRING1);
<'
type phone_number : uint(bits:34) [100_000_0000..999_999_9999];
struct txt{
sender : phone_number;
receiver : phone_number;
message : string;
msg_size: uint(bits:8)[1..140];
fill() is {
var number : byte [0..9];
for i from 1 to msg_size do {
gen number;
// Append to message
message = append(message,number)
};
};
};
'>
GUIDANCE
Introduce an enumerated type
Type name : pseudo_word_t
Words: Your choice - OMG, LOL etc.
Edit fill() method to add pseudo words
Do not make message longer than 140
(check words length before appending)
Beware: we also add a space between words
SYNTAX - Enumerated type
type ENUM_TYPE_NAME : [ENUM1, ENUM2, ENUM3];
SYNTAX - determine length of string
str_len(str)
<'
// Add enumerated type here
type phone_number : uint(bits:34) [100_000_0000..999_999_9999];
type pseudo_word_t : [OMG,LOL];
struct txt {
sender : phone_number;
receiver : phone_number;
message : string;
msg_size: uint(bits:8) [1..140];
fill() is {
var word : pseudo_word_t;
while TRUE do {
gen word;
if ((str_len(message.as_a(string)) + str_len(word.as_a(string)) + 1)<=msg_size) {
message = append(message, word.to_string(), " ");
} else {
break;
};
};
};
};
'>
GUIDANCE
Field names: address, length
Type: uint - 2 and 6 bits respectively
Field name: payload
Type: list of byte
Filed name: parity
Type: byte
SYNTAX: sized list
FIELD_NAME [SIZE] : list of TYPE;
<'
struct packet_s{
// HEADER
address : uint(bits:2);
length : uint(bits:6);
// PAYLOAD
payload [length] : list of byte;
// PARITY
parity : byte;
};
'>
GUIDANCE
Add constraint for length min value
SYNTAX
keep CONSTRAINT_NAME is BOOLEAN_EXPRESSION;
<'
struct packet_s{
// HEADER
// address
address : uint(bits:2);
// length
length : uint(bits:6);
// length constraint
keep lenght_minval is length > 0;
// PAYLOAD
// payload
payload [length] : list of byte;
// PARITY
// parity
parity : byte;
};
'>
GUIDANCE
Introduce an enumerated type that controls packet length
Type name: packet_length_t
Enumerated values: SHORT, LONG, MEDIUM, RANDOM
FYI: Upper case is a convention for enumerated type values
Add Constraints
Ranges: SHORT 1-15 , LONG >= 48, MEDIUM between SHORT and LONG
SYNTAX: conditional constraint - implications
keep CONSTRAINT_NAME is ANTECEDENT => CONSEQUENT;
ANTECEDENT, CONSEQUENT are Booolean expression
&& is logical AND
<'
type packet_length_t : [SHORT,LONG,MEDIUM,RANDOM];
struct packet_s{
// HEADER
// address
address : uint(bits:2);
// length - 6 bits - max: 64
length : uint(bits:6);
// length constraint
keep min_length is length > 0;
// packet length type constraints
packet_length : packet_length_t;
keep length_short is packet_length == SHORT => length <= 15 ;
keep length_medium is packet_length == MEDIUM => (length > 15 && length <48) ;
keep length_long is packet_length == LONG => length >=48 ;
// PAYLOAD
// payload
payload [length] : list of byte;
// PARITY
// parity
parity : byte;
};
'>
GUIDANCE
Mess around with the min_length constraints.
Introduce an expression that can not be solved.
<'
type packet_length_t : [SHORT, LONG, MEDIUM, RANDOM];
struct packet_s{
// HEADER
// address
address : uint(bits:2);
// length - 6 bits - max: 64
length : uint(bits:6);
// length constraint
keep min_length is length < 0;
packet_length : packet_length_t;
// packet length type constraints
keep short_packet is (packet_length == SHORT ) => length <= 15;
keep long_packet is (packet_length == LONG ) => length >= 48;
keep medium_packet is (packet_length == MEDIUM) => (length < 48 && length > 150);
// PAYLOAD
// payload
payload [length] : list of byte;
// PARITY
// parity
parity : byte;
};
'>
GUIDANCE
Add menthod to calculate parity.
Succesive XOR over header and payload.
Loop construct (for loop)
method name: calculate_parity()
SYNTAX
^ // bit wise XOR
for INDEX_NAME from N to M do {};
<'
type packet_length_t : [SHORT, LONG, MEDIUM, RANDOM];
struct packet_s{
// HEADER
// address
address : uint(bits:2);
// length - 6 bits - max: 64
length : uint(bits:6);
// length constraint
keep min_length is length > 0;
// packet length type constraints
packet_length : packet_length_t;
keep short_packet is (packet_length == SHORT ) => length <= 15;
keep long_packet is (packet_length == LONG ) => length >= 48;
keep medium_packet is (packet_length == MEDIUM) => (length < 48 && length > 15);
// PAYLOAD
payload [length] : list of byte;
// PARITY
parity : byte;
keep parity_proper is parity == calculate_parity(address, length, payload);
// methods
calculate_parity(address: uint(bits:2), length:uint(bits:6), payload : list of byte): byte is {
result = %{length, address};
// add for loop here and assign to result
for each (d) in payload{
result = result ^ d;
};
};
};
'>
GUIDANCE
Add a new enumerated type called packet_kind_t with values GOOD, BAD
Add a new fieild called packet_kind of packet_kind_t
Adjust constraint to calculate parity only when when packet_kind is GOOD
SYNTAX
keep CONSTRAINT_NAME is ANTECEDENT => CONSEQUENT;
<'
type packet_length_t : [SHORT, LONG, MEDIUM, RANDOM];
// add new enumerated type here
type packet_kind_t : [GOOD,BAD];
struct packet_s{
// HEADER
// address
address : uint(bits:2) [0..2];
// length - 6 bits - max: 64
length : uint(bits:6);
// length constraint
keep min_length is length > 0;
// packet length type constraints
packet_length : packet_length_t;
keep short_packet is (packet_length == SHORT ) => length <= 15;
keep long_packet is (packet_length == LONG ) => length >= 48;
keep medium_packet is (packet_length == MEDIUM) => (length < 48 && length > 15);
// PAYLOAD
payload [length] : list of byte;
// PARITY
parity : byte;
packet_kind : packet_kind_t;
keep parity_proper is (packet_kind == GOOD) => parity == calculate_parity(address, length, payload);
keep parity_proper_not is (packet_kind == BAD) => parity != calculate_parity(address, length, payload);
// methods
calculate_parity(address: byte(bits:2), length:byte(bits:6), payload: list of byte): byte is {
result = %{length, address};
for each (d) in payload do {
result = result ^ d;
};
};
};
'>
GUIDANCE
Create a list of packets (packet type is "packet_s")
List name: packets
List size between 3 and 9 (randomized)
Control list size with constraints
SYNTAX
LIST_NAME [SIZE] : list of TYPE_NAME;
<'
import packet;
extend sys{
size : uint;
keep packet_list_size is (size >= 3 && size <=9);
// declare list and control its size using constraints
packets [size]: list of packet_s;
};
'>
GUIDANCE
Generate 1 packet
Set its address to 3
Push it into the list
SYNTAX
STRUCT_NAME.FIELD_NAME = VALUE;
LIST_NAME.push0(OBJECT_NAME);
<'
import packet.e;
extend sys{
packets : list of packet_s;
keep max_packets is packets.size() < 10;
keep min_packtes is packets.size() > 2;
// define a packet instance
custompacket : packet_s;
process()is {
// set packet address
custompacket.address = 3;
// push it into list
packets.push0(custompacket);
};
};
'>
<'
// define a new struct called example_s
// - in the new struct define a simple event called example_e
// - print a statement in the log when the event is active
// - use the string "Event example_e is active in example_s"
struct example_s {
event example_e;
on example_e {
out("Event example_e is active in example_s");
};
};
extend sys {
event ev1;
// create an instance of type example_s (call it s1)
s1 : example_s;
on ev1 {
out("Event ev1 active in sys");
};
run() is {
emit ev1;
// emit the event in s1 5 times (you can use loops)
for i from 1 to 5 do{
emit s1.example_e;
};
emit ev1;
};
};
'>
<'
import unit3/e/packet;
// define additional members/functionality for an already
// defined struct
extend packet_s {
pre_generate() is {
// >> issue a message with the text
// "Test-phases: pre_generate phase of packet_s"
out("Test-phases: pre_generate phase of packet_s");
};
run() is {
// >> issue a message with the text
// "Test-phases: run phase of packet_s"
out("Test-phases: run phase of packet_s");
};
};
extend sys {
// >> create a list of packet_s (call the list pkts)
// constraint the list to have with 5 elements
pkts [5]: list of packet_s;
setup() is {
out("Test-phases: Now in setup phase (sys)");
};
run() is {
out("Test-phases: Now in run phase (sys)");
};
};
'>
<'
import unit3/e/packet;
unit packet_driver_u {
clk_p: in simple_port of bit is instance;
keep clk_p.hdl_path() == "clock";
event clock_f is fall(clk_p$)@sim;
// data port (data_p, output, byte, bound to "data_i")
data_p : out simple_port of byte is instance;
keep data_p.hdl_path() == "data_i";
// valid port (valid_p, output, bit, bound to "valid_i")
valid_p : out simple_port of bit is instance;
keep valid_p.hdl_path() == "valid_i";
// suspend port (suspend_p, input, bit, bound to "suspend_o")
suspend_p : in simple_port of bit is instance;
keep suspend_p.hdl_path() == "suspend_o";
// list of packet_s called packets_to_send
// should be 10 packets by default
packets_to_send [10] : list of packet_s;
};
'>
GUIDANCE
- scroll down to the send_pkt() TCM and complete packing the
relevant packet fields into a list of byte
<'
import unit3/e/packet;
unit packet_driver_u {
clk_p: in simple_port of bit is instance;
keep clk_p.hdl_path() == "clock";
event clock_f is fall(clk_p$)@sim;
data_p: out simple_port of byte is instance;
keep data_p.hdl_path() == "data_i";
valid_p: out simple_port of bit is instance;
keep valid_p.hdl_path() == "valid_i";
suspend_p: in simple_port of bit is instance;
keep suspend_p.hdl_path() == "suspend_o";
packets_to_send: list of packet_s;
keep soft packets_to_send.size() == 10;
// pack bits of packet into list of bytes
// send all bytes according to the interface protocol
send_pkt(in_pkt: packet_s):list of byte is {
var lob: list of byte;
// first byte is concatenation of
// length and address
lob.add(%{in_pkt.length,in_pkt.address});
// next add all data bytes
lob.add(payload);
// finally add parity
lob.add(in_pkt.parity);
result = lob;
};
};
'>
GUIDANCE
- constrain the packet_driver and packet_receiver to
achieve a specific traffic scenario (details below)
<'
import unit3/e/router_import;
extend sys {
tb1: router_env_u is instance;
};
extend packet_driver_u {
// packet constraints
// send 1 packet to output port 0 (address field)
// packet should have payload of 5 items
keep packets_to_send.size() == 1;
keep for each (packet) in packets_to_send{
packet.address == 0;
packet.length == 5;
};
};
extend packet_receiver_u {
// there should be no pushback
// the output port (constrain response_delay)
keep response_delay == 0;
};
'>
GUIDANCE
Add coverage sampling event
event name: packet_sent_e
Add coverage items for address and packet_kind
SYNTAX
event EVENT_NAME_e;
cover EVENT_NAME_e is {};
item FIELD_NAME;
<'
extend packet_s{
// coverage
// sampling event
// cover group and items
event packet_sent_e;
cover packet_sent_e is
{
item address;
item packet_kind;
};
};
'>
GUIDANCE
Add cross coverage for address x packet_length
SYNTAX
cross ITEM_NAME1, ITEM_NAME2;
<'
extend packet_s {
cover packet_sent_e is also {
// add coverage here
cross address, packet_length;
};
};
'>
GUIDANCE
Add a constraint to hit goal of length 63 and address 1
SYNTAX
keep CONSTRAINT_NAME is BOOL_EXPRESSION;
<'
extend packet_s {
cover packet_sent_e is also{
item coverage_lenght_63_1 : bool = (length==63 && address==1);
};
keep length > 50;
};
'>
GUIDANCE
Add buckets to length scoring
Min 1
Max 63
Small 2 to 31
Big 32 to 62
SYNTAX
range ([N], "RANGE_NAME1");
range ([K..L], "RANGE_NAME2");
<'
extend packet_s {
cover packet_sent_e is also {
item length using ranges = {
range ([1], "Min");
range ([63] , "Max");
range ([2..31] , "Small");
range ([32..62] , "Big");
};
};
};
'>
GUIDANCE
Ignore coverage for address 3
SYNTAX
item ITEM_NAME using also ignore = BOOLEAN_EXPLRESSION;
<'
extend packet_s {
cover packet_sent_e is also {
item address using also ignore = (address == 3);
};
};
'>
GUIDANCE
Add transition coverage for address
SYNTAX
transition ITEM_NAME;
<'
extend packet_s {
cover packet_sent_e is also {
// add coverage here
transition address;
};
};
'>
@orayen
Copy link

orayen commented May 30, 2013

thanks brother that gives big help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment