Tuesday, February 25, 2014

testbench for VHDL serial port "http://scott2595.blogspot.com/2014/02/vhdl-code-for-serial-interface.html"

--testbench for http://scott2595.blogspot.com/2014/02/vhdl-code-for-serial-interface.html

library ieee;
use ieee.std_logic_1164.all;
use std.env.all;
use ieee.math_real.all;
use ieee.numeric_std.all;
--library gate_work;
--use gate_work.top;

entity tb_spi is
end entity tb_spi;

architecture behavioral of tb_spi is
component top is
port (
    clk     : in std_logic;
    rst_n   : in std_logic;
    load    : in std_logic;
    slv_sel : in std_logic_vector(1 downto 0);
    din     : in std_logic_vector(4 downto 0);
    led0    : out std_logic_vector(4 downto 0);
    led1    : out std_logic_vector(4 downto 0);
    led2    : out std_logic_vector(4 downto 0)
);
end component;

signal clk     : std_logic;
signal rst_n   : std_logic;
signal load    : std_logic;
signal slv_sel : std_logic_vector(1 downto 0);
signal din     : std_logic_vector(4 downto 0);
signal led0    : std_logic_vector(4 downto 0);
signal led1    : std_logic_vector(4 downto 0);
signal led2    : std_logic_vector(4 downto 0);

begin
u_top: top port map (
    clk     => clk     ,
    rst_n   => rst_n   ,
    load    => load    ,
    slv_sel => slv_sel ,
    din     => din     ,
    led0    => led0    ,
    led1    => led1    ,
    led2    => led2    
);

process
begin
    clk <= '0';
    wait for 10 ns;
    clk <= '1';
    wait for 10 ns;
end process;

process
begin
    rst_n <= '1';
    wait for 100 ns;
    rst_n <= '0';
    wait for 100 ns;
    rst_n <= '1';
    wait;
end process;

process
variable seed1, seed2: positive;
variable int_rand: integer;
variable rand: real;                        
variable i: integer;
begin
    seed1 := 1;
    seed2 := 2;
    load <= '0';
    slv_sel <= "00";
    din <= "00000";
    wait for 300 ns;
    wait until rising_edge(clk);
    for i in 1 to 3 loop
        uniform(seed1, seed2, rand);
        int_rand := integer(trunc(rand * 31.0));
        din <= std_logic_vector(to_unsigned(int_rand, din'length));
        slv_sel <= std_logic_vector(to_unsigned(i, slv_sel'length));
        wait until rising_edge(clk);
        load <= '1';
        wait until rising_edge(clk);
        wait until rising_edge(clk);
        load <= '0';
        wait for 300 ns;
    end loop;
    finish(0);
end process;

end behavioral;

Monday, February 24, 2014

run modelsim in cmd mode

1) run script:
#!/bin/bash

if [ -e wave.wlf ]; then
    rm -rf wave.wlf
fi

if [ ! -e work ]; then
    vlib work
fi
vmap work work

vcom spi.vhd tb_spi.vhd
#vsim work.tb_spi -gui -do do.tcl -wlf wave.wlf
vsim work.tb_spi -c -do do.tcl -wlf wave.wlf

2) do.tcl:
add wave -r /*
run -all
exit

2) run script for running with coverage:
#!/bin/bash

if [ -e wave.wlf ]; then
    rm -rf wave.wlf
fi

if [ -e work ]; then
    rm -rf work
fi
vlib work
vmap work work

vcom +cover=sbceft counter.vhd tb_counter.vhd
vsim work.tb_counter -coverage -c -do do.tcl -wlf wave.wlf

some basic cpp syntax

1) simple example:
#include <iostream>
using std::cout;
using std::endl;

class basePoint {
public:
    void setPoint(int, int);
    void display();
private:
    int x;
    int y;
};

void basePoint::setPoint(int x, int y) {
    this->x = x;
    this->y = y;
}

void basePoint::display() {
    std::cout << x << " " << y << std::endl;
}

int main(int argc, char* argv[]) {
    basePoint bp0;
    basePoint *bp1 = new basePoint();

    bp0.setPoint(1, 2);
    bp1->setPoint(3, 4);
    bp0.display();
    bp1->display();
    return 0;
}

2) variable accessibility
#include <iostream>
using std::cout;
using std::endl;

class base {
public:
    base();
    void set_data(int, int, int);
    void clear_data();
    void display();
    int z;

protected:
    int y;

private:
    int x;
};

base::base() {
    x = 0;
    y = 0;
    z = 0;
}

void base::set_data(int x, int y, int z) {
    this->x = x;
    this->y = y;
    this->z = z;
}

void base::clear_data() {
    x = 0;
    y = 0;
    z = 0;
}

void base::display() {
    cout << x << " " << y << " " << z << endl;
}

class public_subclass : public base {
public:
    public_subclass();
    void set_data(int, int, int, int, int, int);
    void clear_data();
    void display();
    int a;

protected:
    int b;

private:
    int c;
};

public_subclass::public_subclass() {
    a = 0;
    b = 0;
    c = 0;
    //x of class base cannot be accessed
    //x = 0;
    y = 0;
    z = 0;
}

void public_subclass::set_data(int a, int b, int c, int x, int y, int z) {
    this->a = a;
    this->b = b;
    this->c = c;
    //x of class base cannot be accessed
    //this->x = x;
    this->y = y;
    this->z = z;
}

void public_subclass::clear_data() {
    a = 0;
    b = 0;
    c = 0;
    //x of class base cannot be accessed
    //x = 0;
    y = 0;
    z = 0;
}

void public_subclass::display() {
    //x of class base cannot be accessed
    //cout << a << " " << b << " " << c << " " << x << " " << y << " " << z << endl;
    cout << a << " " << b << " " << c << " " << y << " " << z << endl;
}

class protected_subclass : protected base {
public:
    protected_subclass();
    void set_data(int, int, int, int, int, int);
    void clear_data();
    void display();
    int a;

protected:
    int b;

private:
    int c;
};

protected_subclass::protected_subclass() {
    a = 0;
    b = 0;
    c = 0;
    //x of class base cannot be accessed
    //x = 0;
    y = 0;
    z = 0;
}

void protected_subclass::set_data(int a, int b, int c, int x, int y, int z) {
    this->a = a;
    this->b = b;
    this->c = c;
    //x of class base cannot be accessed
    //this->x = x;
    this->y = y;
    this->z = z;
}

void protected_subclass::clear_data() {
    a = 0;
    b = 0;
    c = 0;
    //x of class base cannot be accessed
    //x = 0;
    y = 0;
    z = 0;
}

void protected_subclass::display() {
    //x of class base cannot be accessed
    //cout << a << " " << b << " " << c << " " << x << " " << y << " " << z << endl;
    cout << a << " " << b << " " << c << " " << y << " " << z << endl;
}

class private_subclass : private base {
public:
    private_subclass();
    void set_data(int, int, int, int, int, int);
    void clear_data();
    void display();
    int a;

protected:
    int b;

private:
    int c;
};

private_subclass::private_subclass() {
    a = 0;
    b = 0;
    c = 0;
    //x of class base cannot be accessed
    //x = 0;
    y = 0;
    z = 0;
}

void private_subclass::set_data(int a, int b, int c, int x, int y, int z) {
    this->a = a;
    this->b = b;
    this->c = c;
    //x of class base cannot be accessed
    //this->x = x;
    this->y = y;
    this->z = z;
}

void private_subclass::clear_data() {
    a = 0;
    b = 0;
    c = 0;
    //x of class base cannot be accessed
    //x = 0;
    y = 0;
    z = 0;
}

void private_subclass::display() {
    //x of class base cannot be accessed
    //cout << a << " " << b << " " << c << " " << x << " " << y << " " << z << endl;
    cout << a << " " << b << " " << c << " " << y << " " << z << endl;
}

int main(int argc, char* argv[]) {
    base u_base;
    public_subclass u_public_subclass;
    protected_subclass u_protected_subclass;
    private_subclass u_private_subclass;

    u_base.set_data(1, 2, 3);
    u_base.display();

    /////////////////////////////////////////////////
    //x and y of class base cannot be accessed
    /////////////////////////////////////////////////
    //u_base.x = 10;
    //u_base.y = 20;
    u_base.z = 30;
    u_base.display();

    u_base.clear_data();
    u_base.display();

    /////////////////////////////////////////////////
    //public base class
    /////////////////////////////////////////////////
    u_public_subclass.z = 21;
    u_public_subclass.a = 22;
    //b and c cannot be accessed
    //u_public_subclass.b = 23;
    //u_public_subclass.c = 24;
    u_public_subclass.display();

    /////////////////////////////////////////////////
    //protected base class
    /////////////////////////////////////////////////
    //z cannot be accessed
    //u_protected_subclass.z = 31;
    u_protected_subclass.a = 37;
    u_protected_subclass.display();
    u_protected_subclass.set_data(31, 32, 33, 34, 35, 36);
    u_protected_subclass.display();

    /////////////////////////////////////////////////
    //private base class
    /////////////////////////////////////////////////
    //z cannot be accessed
    //u_private_subclass.z = 41;
    u_private_subclass.a = 47;
    u_private_subclass.display();
    u_private_subclass.set_data(41, 42, 43, 44, 45, 46);
    u_private_subclass.display();
}

3) constructor and deconstructor
//deconstructor of base class must be virtual function
#include <iostream>
using std::cout;
using std::endl;

class base {
public:
    base();
    virtual ~base();
};

base::base() {
}

base::~base() {
    cout << "Calling deconstruction of base!" << endl;
}

class subclass : public base {
public:
    subclass();
    ~subclass();
};

subclass::subclass() {
}
subclass::~subclass() {
    cout << "Calling deconstruction of subclass!" << endl;
}

int main(int argc, char* argv[]) {
    base *u_base = new subclass;
    delete u_base;

    return 0;
}

4) dynamically allocate memory
#include <iostream>
//#include <cstddef>
#include <stddef.h>
using std::cout;
using std::endl;
using std::nothrow;
//using std::nullptr;
//using std::nullptr_t;

int main(int argc, char* argv[]) {
    //will throw an error when memory cannot be allocated
    int *var1 = new int[10];
    //will not throw an error when memory cannot be allocated
    int *var2 = new (nothrow) int [10];

    //c++ 11
    //if(var2 == nullptr) {
    if(var2 == 0) {
        cout << "Cannot allocate memory" << endl;
        return 1;
    }

    for(int i=0; i<10; i++) {
        *(var1 + i) = i;
        *(var2 + i) = i + 10;
    }

    for(int i=0; i<10; i++) {
        cout << *(var1 + i) << " " << *(var2 + i) << endl;
    }

    delete [] var1;
    delete [] var2;

    return 0;
}

5) inherent
/////////////////////////////////////////////
//base.h
/////////////////////////////////////////////
#ifndef __BASE_H__
#define __BASE_H__
#include <iostream>
using std::cout;
using std::endl;

class basePoint {
public:
    basePoint();
    basePoint(int, int);
    virtual ~basePoint();
    void setPoint(int, int);
    void display();

private:
    int x;
    int y;
};

#endif

/////////////////////////////////////////////
//base.cpp
/////////////////////////////////////////////
#ifndef __BASE_CPP__
#define __BASE_CPP__
#include "base.h"

basePoint::basePoint() {
    x = 10;
    y = 10;
}

basePoint::basePoint(int x, int y) {
    this->x = x;
    this->y = y;
}

basePoint::~basePoint() {

}

void basePoint::setPoint(int x, int y) {
    this->x = x;
    this->y = y;
}

void basePoint::display() {
    std::cout << x << " " << y << " " << std::endl;
}

#endif

/////////////////////////////////////////////
//polygon.h
/////////////////////////////////////////////
#ifndef __SUBCLASS_H__
#define __SUBCLASS_H__
#include <iostream>
#include "base.h"
using std::cout;
using std::endl;

class polygon {
public:
    polygon();
    polygon(int);
    virtual ~polygon();
    void display();

protected:
    bool genPolygon();

private:
    int pointNo;
    basePoint **bp;
};

#endif

/////////////////////////////////////////////
//polygon.cpp
/////////////////////////////////////////////
#ifndef __SUBCLASS_CPP__
#define __SUBCLASS_CPP__
#include "polygon.h"

polygon::polygon() {
    pointNo = 10;
    genPolygon();
}

polygon::polygon(int number) {
    pointNo = number;
    genPolygon();
}

polygon::~polygon() {
    for(int i=0; i<pointNo; i++) {
        delete bp[i];
    }
    delete [] bp;
}

bool polygon::genPolygon() {
    bp = new basePoint*[pointNo];
    for(int i=0; i<pointNo; i++) {
        bp[i] = new basePoint();
    }

    return true;
}

void polygon::display() {
    for(int i=0; i<pointNo; i++) {
        cout << "Point: " << i << endl;
        bp[i]->display();
    }
}

#endif

/////////////////////////////////////////////
//rectangle.h
/////////////////////////////////////////////
#ifndef __RECTANGLE_H__
#define __RECTANGLE_H__
#include <iostream>
#include "polygon.h"
using std::cout;
using std::endl;

class rectangle : public polygon {
public:
    rectangle();
    virtual ~rectangle();

};

#endif

/////////////////////////////////////////////
//rectangle.cpp
/////////////////////////////////////////////
#ifndef __RECTANGLE_CPP__
#define __RECTANGLE_CPP__
#include "rectangle.h"

rectangle::rectangle() : polygon(4) {
}

rectangle::~rectangle() {
}

#endif

/////////////////////////////////////////////
//main.cpp
/////////////////////////////////////////////
#include "rectangle.h"

int main(int argc, char* argv[]) {
    polygon poly;
    poly.display();

    rectangle *rect = new rectangle();
    rect->display();

    delete rect;
    return 0;
}

#############################################
#Makefile
#############################################

.PHONY: clean all

all: clean a.out

clean:
rm -rf *.o *.out *.exe

a.out: base.o main.o  polygon.o rectangle.o
g++ -o $@ $^

6) polymorphism
/////////////////////////////////////////////
//polygon.h
/////////////////////////////////////////////
#ifndef __POLYGON_H__
#define __POLYGON_H__
#include <iostream>
#include <math.h>
using std::cout;
using std::endl;

class polygon {
public:
    polygon(int, int);
    virtual ~polygon();
    void display();
#ifdef USE_VIRTUAL
    virtual float area();
#else
    float area();
#endif

    int width;
    int height;
};

#endif

/////////////////////////////////////////////
//polygon.cpp
/////////////////////////////////////////////
#ifndef __POLYGON_CPP__
#define __POLYGON_CPP__
#include "polygon.h"

polygon::polygon(int width, int height) {
    this->width = width;
    this->height = height;
}

polygon::~polygon() {
}

float polygon::area() {
    return 0;
}

void polygon::display() {
    cout << "width: " << width << " height: " << height << endl;
}

#endif

/////////////////////////////////////////////
//rectangle.h
/////////////////////////////////////////////
#ifndef __RECTANGLE_H__
#define __RECTANGLE_H__
#include <iostream>
#include "polygon.h"
using std::cout;
using std::endl;

class rectangle : public polygon {
public:
    rectangle(int, int);
    virtual ~rectangle();

#ifdef USE_VIRTUAL
    virtual float area();
#else
    float area();
#endif

};

#endif

/////////////////////////////////////////////
//rectangle.cpp
/////////////////////////////////////////////
#ifndef __RECTANGLE_CPP__
#define __RECTANGLE_CPP__
#include "rectangle.h"

rectangle::rectangle(int width, int height) : polygon(width, height) {
}

rectangle::~rectangle() {
}

float rectangle::area() {
    return width * height;
}

#endif

/////////////////////////////////////////////
//triangle.h
/////////////////////////////////////////////
#ifndef __TRIANGLE_H__
#define __TRIANGLE_H__
#include <iostream>
#include "polygon.h"
using std::cout;
using std::endl;

class triangle : public polygon {
public:
    triangle(int, int);
    virtual ~triangle();

#ifdef USE_VIRTUAL
    virtual float area();
#else
    float area();
#endif

};

#endif

/////////////////////////////////////////////
//triangle.cpp
/////////////////////////////////////////////
#ifndef __TRIANGLE_CPP__
#define __TRIANGLE_CPP__
#include "triangle.h"

triangle::triangle(int width, int height) : polygon(width, height) {
}

triangle::~triangle() {
}

float triangle::area() {
    return float(width) * float(height) / 2;
}

#endif

/////////////////////////////////////////////
//main.cpp
/////////////////////////////////////////////
#include "polygon.h"
#include "rectangle.h"
#include "triangle.h"

int main(int argc, char* argv[]) {
    rectangle *rect = new rectangle(2, 3);
    polygon *poly1 = new rectangle(2, 3);
    cout << "Area of rectangle by calling the function area of rectangle: " << rect->area() << endl;
    //if area is not virtual function, the return data will be 0
    cout << "Area of rectangle by calling the function area of polygon: " << poly1->area() << endl;

    triangle *tri = new triangle(2, 3);
    polygon *poly2 = new triangle(2, 3);
    cout << "Area of triangle by calling the function area of triangle: " << tri->area() << endl;
    //if area is not virtual function, the return data will be 0
    cout << "Area of triangle by calling the function area of polygon: " << poly2->area() << endl;

    delete rect;
    delete tri;
    return 0;
}

#############################################
#Makefile
#############################################

.PHONY: clean all

all: clean a.out

ifeq ($(USE_VIRTUAL),1)
CPPFLAGS = -DUSE_VIRTUAL
endif

clean:
rm -rf *.o *.out *.exe

a.out: main.o  polygon.o rectangle.o triangle.o
g++ -o $@ $^

7) override
/////////////////////////////////////////////
//polygon.h
/////////////////////////////////////////////
#ifndef __POLYGON_H__
#define __POLYGON_H__
#include <iostream>
#include <math.h>
using std::cout;
using std::endl;

class polygon {
public:
    polygon(int, int);
    virtual ~polygon();
    void display();
#ifdef USE_VIRTUAL
    virtual float area();
#else
    float area();
#endif

    int width;
    int height;
};

#endif

/////////////////////////////////////////////
//polygon.cpp
/////////////////////////////////////////////
#ifndef __POLYGON_CPP__
#define __POLYGON_CPP__
#include "polygon.h"

polygon::polygon(int width, int height) {
    this->width = width;
    this->height = height;
}

polygon::~polygon() {
}

float polygon::area() {
    return 0;
}

void polygon::display() {
    cout << "width: " << width << " height: " << height << endl;
}

#endif

/////////////////////////////////////////////
//rectangle.h
/////////////////////////////////////////////
#ifndef __RECTANGLE_H__
#define __RECTANGLE_H__
#include <iostream>
#include "polygon.h"
#include "triangle.h"
using std::cout;
using std::endl;

class triangle;

class rectangle : public polygon {
public:
    rectangle(int, int);
    virtual ~rectangle();

#ifdef USE_VIRTUAL
    virtual float area();
#else
    float area();
#endif

    float operator+(rectangle&);
#ifdef RECT_PLUS_TRI
    float operator+(triangle&);
#endif

};

#endif

/////////////////////////////////////////////
//rectangle.cpp
/////////////////////////////////////////////
#ifndef __RECTANGLE_CPP__
#define __RECTANGLE_CPP__
#include "rectangle.h"

rectangle::rectangle(int width, int height) : polygon(width, height) {
}

rectangle::~rectangle() {
}

float rectangle::area() {
    return width * height;
}

float rectangle::operator+(rectangle& rect) {
    return this->area() + rect.area();
}

#ifdef RECT_PLUS_TRI
float rectangle::operator+(triangle& tri) {
    return this->area() + tri.area();
}
#endif

#endif

/////////////////////////////////////////////
//triangle.h
/////////////////////////////////////////////
#ifndef __TRIANGLE_H__
#define __TRIANGLE_H__
#include <iostream>
#include "polygon.h"
#include "rectangle.h"
using std::cout;
using std::endl;

class rectangle;

class triangle : public polygon {
public:
    triangle(int, int);
    virtual ~triangle();

#ifdef USE_VIRTUAL
    virtual float area();
#else
    float area();
#endif

    float operator+(triangle&);
#ifdef TRI_PLUS_RECT
    float operator+(rectangle&);
#endif

};

#endif

/////////////////////////////////////////////
//triangle.cpp
/////////////////////////////////////////////
#ifndef __TRIANGLE_CPP__
#define __TRIANGLE_CPP__
#include "triangle.h"

triangle::triangle(int width, int height) : polygon(width, height) {
}

triangle::~triangle() {
}

float triangle::area() {
    return float(width) * float(height) / 2;
}

float triangle::operator+(triangle& tri) {
    return this->area() + tri.area();
}

#ifdef TRI_PLUS_RECT
float triangle::operator+(rectangle& rect) {
    return this->area() + rect.area();
}
#endif

#endif

/////////////////////////////////////////////
//main.cpp
/////////////////////////////////////////////
#include "polygon.h"
#include "rectangle.h"
#include "triangle.h"

int main(int argc, char* argv[]) {
    rectangle *rect1 = new rectangle(2, 2);
    cout << "Area of rect1angle by calling the function area of rect1angle: " << rect1->area() << endl;

    rectangle *rect2 = new rectangle(3, 3);
    cout << "Area of rectangle by calling the function area of rectangle: " << rect2->area() << endl;

    cout << "Area of rect1 plus rect2 is: " << *rect1 + *rect2 << endl;

    triangle *tri1 = new triangle(2, 2);
    cout << "Area of triangle by calling the function area of triangle: " << tri1->area() << endl;

    triangle *tri2 = new triangle(3, 3);
    cout << "Area of triangle by calling the function area of triangle: " << tri2->area() << endl;

    cout << "Area of tri1 plus tri2 is: " << *tri1 + *tri2 << endl;

#ifdef RECT_PLUS_TRI
    cout << "Area of rect1 plus tri1 is: " << *rect1 + *tri1 << endl;
#endif

#ifdef TRI_PLUS_RECT
    cout << "Area of tri1 plus rect1 is: " << *tri1 + *rect1 << endl;
#endif

    delete rect1;
    delete rect2;
    delete tri1;
    delete tri2;
    return 0;
}

#############################################
#Makefile
#############################################
.PHONY: clean all

all: clean a.out

CPPFLAGS = -DUSE_VIRTUAL

ifeq (${RECT_PLUS_TRI}, 1)
CPPFLAGS += -DRECT_PLUS_TRI
endif

ifeq (${TRI_PLUS_RECT}, 1)
CPPFLAGS += -DTRI_PLUS_RECT
endif

clean:
rm -rf *.o *.out *.exe

a.out: main.o  polygon.o rectangle.o triangle.o
g++ -o $@ $^

8) smart pointer
/////////////////////////////////////////////
//hasPtr.h
/////////////////////////////////////////////
#ifndef __HASPTR_H__
#define __HASPTR_H__

#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::endl;

class HasPtr {
friend void swap(HasPtr&, HasPtr&);

public:
    HasPtr(const string &s = string()):
        ps(new string(s)), i(0), use(new std::size_t(1)) {}
    HasPtr(const HasPtr &);
    HasPtr& operator=(const HasPtr&);
    ~HasPtr();
    void display() {
        cout << "ps: " << *ps << " use: " << *use << endl;
    }
private:
    std::string *ps;
    int i;
    std::size_t *use;
};

#endif

/////////////////////////////////////////////
//hasPtr.cpp
/////////////////////////////////////////////
#ifndef __HASPTR_CPP__
#define __HASPTR_CPP__

#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::endl;

class HasPtr {
friend void swap(HasPtr&, HasPtr&);

public:
    HasPtr(const string &s = string()):
        ps(new string(s)), i(0), use(new std::size_t(1)) {}
    HasPtr(const HasPtr &);
    HasPtr& operator=(const HasPtr&);
    ~HasPtr();
    void display() {
        cout << "ps: " << *ps << " use: " << *use << endl;
    }
private:
    std::string *ps;
    int i;
    std::size_t *use;
};

HasPtr::HasPtr(const HasPtr &p): ps(p.ps), i(p.i), use(p.use) {
    ++*use;
}

HasPtr::~HasPtr() {
    if (--*use == 0) {
        delete ps;
        delete use;
    }
}

HasPtr& HasPtr::operator=(const HasPtr &rhs) {
    ++*rhs.use;
    if(--*use == 0) {
        delete ps;
        delete use;
    }
    ps = rhs.ps;
    i = rhs.i;
    use = rhs.use;
    return *this;
}

#endif

/////////////////////////////////////////////
//main.cpp
/////////////////////////////////////////////
#include "hasPtr.h"

int main(int argc, char* argv[]) {
    HasPtr *hasPtr1 = new HasPtr("string 1");
    HasPtr *hasPtr2 = new HasPtr("string 2");
    hasPtr1->display();
    hasPtr2->display();

    *hasPtr2 = *hasPtr1;
    hasPtr1->display();
    hasPtr2->display();

    delete hasPtr1;
    hasPtr2->display();

    delete hasPtr2;

    return 0;
}

#############################################
#Makefile
#############################################
.PHONY: clean

all: clean a.out

clean:
rm -rf *.o *.exe *.out

a.out: main.o hasPtr.o swap.o
g++ -o $@ $^

9) friend function
/////////////////////////////////////////////
//hasPtr.h
/////////////////////////////////////////////
#ifndef __HASPTR_H__
#define __HASPTR_H__

#include <string>
#include <iostream>
#include "swap.h"
using std::string;
using std::cout;
using std::endl;

class HasPtr {
friend void swap(HasPtr&, HasPtr&);

public:
    HasPtr(const string &s = string()):
        ps(new string(s)), i(0), use(new std::size_t(1)) {}
    HasPtr(const HasPtr &);
    HasPtr& operator=(const HasPtr&);
    ~HasPtr();
    void display() {
        cout << "ps: " << *ps << " use: " << *use << endl;
    }
private:
    std::string *ps;
    int i;
    std::size_t *use;
};

#endif

/////////////////////////////////////////////
//hasPtr.cpp
/////////////////////////////////////////////
#ifndef __HASPTR_CPP__
#define __HASPTR_CPP__

#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::endl;

class HasPtr {
friend void swap(HasPtr&, HasPtr&);

public:
    HasPtr(const string &s = string()):
        ps(new string(s)), i(0), use(new std::size_t(1)) {}
    HasPtr(const HasPtr &);
    HasPtr& operator=(const HasPtr&);
    ~HasPtr();
    void display() {
        cout << "ps: " << *ps << " use: " << *use << endl;
    }
private:
    std::string *ps;
    int i;
    std::size_t *use;
};

HasPtr::HasPtr(const HasPtr &p): ps(p.ps), i(p.i), use(p.use) {
    ++*use;
}

HasPtr::~HasPtr() {
    if (--*use == 0) {
        delete ps;
        delete use;
    }
}

HasPtr& HasPtr::operator=(const HasPtr &rhs) {
    ++*rhs.use;
    if(--*use == 0) {
        delete ps;
        delete use;
    }
    ps = rhs.ps;
    i = rhs.i;
    use = rhs.use;
    return *this;
}

#endif

/////////////////////////////////////////////
//swap.h
/////////////////////////////////////////////
#ifndef __SWAP_H__
#define __SWAP_H__

#include "hasPtr.h"

class HasPtr;

void swap(HasPtr&, HasPtr&);

#endif

/////////////////////////////////////////////
//swap.cpp
/////////////////////////////////////////////
#ifndef __SWAP_CPP__
#define __SWAP_CPP__

#include "swap.h"

void swap(HasPtr &lhs, HasPtr &rhs) {
    using std::swap;
    swap(lhs.ps, rhs.ps);
    swap(lhs.i, rhs.i);
}

#endif

/////////////////////////////////////////////
//main.cpp
/////////////////////////////////////////////
#include <iostream>
#include "hasPtr.h"
#include "swap.h"
using std::cout;
using std::endl;

int main(int argc, char* argv[]) {
    HasPtr *hasPtr1 = new HasPtr("string 1");
    HasPtr *hasPtr2 = new HasPtr("string 2");
    cout << "hasPtr1:" << endl;
    hasPtr1->display();
    cout << "hasPtr2:" << endl;
    hasPtr2->display();

    swap(*hasPtr1, *hasPtr2);

    cout << "hasPtr1:" << endl;
    hasPtr1->display();
    cout << "hasPtr2:" << endl;
    hasPtr2->display();

    delete hasPtr1;
    delete hasPtr2;

    return 0;
}

#############################################
#Makefile
#############################################
.PHONY: clean

all: clean a.out

clean:
rm -rf *.o *.exe *.out

a.out: main.o hasPtr.o swap.o
g++ -o $@ $^

10) friend class
/////////////////////////////////////////////
//hasPtr.h
/////////////////////////////////////////////
#ifndef __HASPTR_H__
#define __HASPTR_H__

#include <string>
#include <iostream>
#include "ptrOp.h"
using std::string;
using std::cout;
using std::endl;

class HasPtr {
friend class ptrOp;

public:
    HasPtr(const string &s = string()):
        ps(new string(s)), i(0), use(new std::size_t(1)) {}
    HasPtr(const HasPtr &);
    HasPtr& operator=(const HasPtr&);
    ~HasPtr();
    void display() {
        cout << "ps: " << *ps << " use: " << *use << endl;
    }
private:
    std::string *ps;
    int i;
    std::size_t *use;
};

#endif

/////////////////////////////////////////////
//hasPtr.cpp
/////////////////////////////////////////////
#ifndef __HASPTR_CPP__
#define __HASPTR_CPP__

#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::endl;

class HasPtr {
friend class ptrOp;

public:
    HasPtr(const string &s = string()):
        ps(new string(s)), i(0), use(new std::size_t(1)) {}
    HasPtr(const HasPtr &);
    HasPtr& operator=(const HasPtr&);
    ~HasPtr();
    void display() {
        cout << "ps: " << *ps << " use: " << *use << endl;
    }
private:
    std::string *ps;
    int i;
    std::size_t *use;
};

HasPtr::HasPtr(const HasPtr &p): ps(p.ps), i(p.i), use(p.use) {
    ++*use;
}

HasPtr::~HasPtr() {
    if (--*use == 0) {
        delete ps;
        delete use;
    }
}

HasPtr& HasPtr::operator=(const HasPtr &rhs) {
    ++*rhs.use;
    if(--*use == 0) {
        delete ps;
        delete use;
    }
    ps = rhs.ps;
    i = rhs.i;
    use = rhs.use;
    return *this;
}

#endif

/////////////////////////////////////////////
//ptrOp.h
/////////////////////////////////////////////
#ifndef __SWAP_H__
#define __SWAP_H__

#include "hasPtr.h"

class HasPtr;

class ptrOp {
public:
    ptrOp(HasPtr&, HasPtr&);
    void swap(HasPtr&, HasPtr&);
private:
    HasPtr *hasPtr1;
    HasPtr *hasPtr2;
};

#endif

/////////////////////////////////////////////
//ptrOp.cpp
/////////////////////////////////////////////
#ifndef __PTROP_CPP__
#define __PTROP_CPP__

#include "ptrOp.h"

ptrOp::ptrOp(HasPtr& hasPtr1, HasPtr& hasPtr2) {
    this->hasPtr1 = &hasPtr1;
    this->hasPtr2 = &hasPtr2;
}

void ptrOp::swap(HasPtr &lhs, HasPtr &rhs) {
    using std::swap;
    swap(lhs.ps, rhs.ps);
    swap(lhs.i, rhs.i);
    swap(hasPtr1->ps, hasPtr2->ps);
    swap(hasPtr1->i, hasPtr2->i);
}

#endif

/////////////////////////////////////////////
//main.cpp
/////////////////////////////////////////////
#include <iostream>
#include "hasPtr.h"
#include "ptrOp.h"
using std::cout;
using std::endl;

int main(int argc, char* argv[]) {
    HasPtr *hasPtr1 = new HasPtr("string 1");
    HasPtr *hasPtr2 = new HasPtr("string 2");
    HasPtr *hasPtr3 = new HasPtr("string 3");
    HasPtr *hasPtr4 = new HasPtr("string 4");
    cout << "hasPtr1:" << endl;
    hasPtr1->display();
    cout << "hasPtr2:" << endl;
    hasPtr2->display();
    cout << "hasPtr3:" << endl;
    hasPtr3->display();
    cout << "hasPtr4:" << endl;
    hasPtr4->display();

    ptrOp *ptrOp1 = new ptrOp(*hasPtr1, *hasPtr2);
    ptrOp1->swap(*hasPtr3, *hasPtr4);

    cout << "hasPtr1:" << endl;
    hasPtr1->display();
    cout << "hasPtr2:" << endl;
    hasPtr2->display();
    cout << "hasPtr3:" << endl;
    hasPtr3->display();
    cout << "hasPtr4:" << endl;
    hasPtr4->display();

    delete hasPtr1;
    delete hasPtr2;
    delete hasPtr3;
    delete hasPtr4;

    return 0;
}

#############################################
#Makefile
#############################################
.PHONY: clean

all: clean a.out

clean:
rm -rf *.o *.exe *.out

a.out: main.o hasPtr.o ptrOp.o
g++ -o $@ $^

11) inline
/////////////////////////////////////////////
//rectangle.h
/////////////////////////////////////////////
#ifndef __RECTANGLE_H__
#define __RECTANGLE_H__
#include <iostream>
using std::cout;
using std::endl;

class rectangle {
public:
    rectangle(int, int);
    virtual ~rectangle();

    inline int area() {
        return width * height;
    }

private:
    int width;
    int height;
};

#endif

/////////////////////////////////////////////
//rectangle.cpp
/////////////////////////////////////////////
#ifndef __RECTANGLE_CPP__
#define __RECTANGLE_CPP__
#include "rectangle.h"

rectangle::rectangle(int width, int height) {
    this->width = width;
    this->height = height;
}

rectangle::~rectangle() {
}

#endif

/////////////////////////////////////////////
//main.cpp
/////////////////////////////////////////////
#include <iostream>
#include "rectangle.h"
using std::cout;
using std::endl;

int main(int argc, char* argv[]) {

    rectangle *rect = new rectangle(2, 3);
    cout << rect->area() << endl;

    delete rect;
    return 0;
}

#############################################
#Makefile
#############################################
.PHONY: clean

all: clean a.out

clean:
rm -rf *.o *.exe *.out

a.out: main.o rectangle.o
g++ -o $@ $^

21) vector
/////////////////////////////////////////////
//main.cpp
/////////////////////////////////////////////
#include <vector>
#include <iostream>
#include <string>
using std::vector;
using std::cout;
using std::endl;
using std::string;

int main(int argc, char* argv[]) {
    vector<int> a;
    if(a.empty()) {
        for (int i = 0; i != 3; ++i) {
            a.push_back(i+10);
        }
    }

    cout << "a size: " << a.size() << " max size: " << a.max_size() << endl;

    vector<int> b(a);
    cout << "b size: " << b.size() << " max size: " << b.max_size() << endl;
    cout << "b capacity: " << b.capacity() << endl;
    b.resize(10);
    b.reserve(100);
    cout << "b size: " << b.size() << " max size: " << b.max_size() << endl;
    cout << "b capacity: " << b.capacity() << endl;

    vector<int> c = a;
    vector<int> d(3);
    cout << d[0] << endl;
    while(d != a) {
        d = a;
        cout << d[0] << endl;
    }
    vector<int> e(3, 2);
    cout << e[0] << endl;

    //supported in C++11
    vector<int> f{1, 2, 3};
    vector<int> g = {4, 5, 6};

    vector<int> h{1,2,3};
    for (auto &i : h) {
        i *= i;
    }
    for (auto i : h) {
        cout << i << " ";
    }
    cout << endl;

    //cout << decltype(h.size()) << endl;
    for (auto it = h.cbegin(); it != h.cend(); ++it) {
        if(*it == 1) {
            //illegal
            //*it = 1;
        }
        cout << *it << " ";
    }
    cout << endl;
    for (auto it = h.crbegin(); it != h.crend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;

    for (vector<int>::iterator it = a.begin(); it != a.end(); ++it) {
        if(*it == 10) {
            *it = 0;
        }
    }
    for (vector<int>::iterator it = a.begin(); it != a.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    for (vector<int>::reverse_iterator it = a.rbegin(); it != a.rend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;

    for (vector<int>::const_iterator it = a.begin(); it != a.end(); ++it) {
        if(*it == 11) {
            //is not legal
            //*it = 1;
        }
    }
    for (vector<int>::const_iterator it = a.begin(); it != a.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;

    int i = 0;
    for (vector<int>::iterator it = b.begin(); it != b.end(); ++it) {
        *it = i;
        i++;
    }
    for (auto it = b.cbegin(); it != b.cend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    b.pop_back();
    for (auto it = b.cbegin(); it != b.cend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    b.insert(b.begin() + 1, 10);
    for (auto it = b.cbegin(); it != b.cend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    b.erase(b.begin() + 3);
    for (auto it = b.cbegin(); it != b.cend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    b.swap(c);
    for (auto it = b.cbegin(); it != b.cend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    b.clear();
    cout << "b size: " << b.size() << " max size: " << b.max_size() << endl;

    return 0;
}

#############################################
#Makefile
#############################################
.PHONY: clean

CPPFLAGS = -std=c++0x

all: clean a.out

clean:
rm -rf *.o *.exe *.out

a.out: main.o
g++ -o $@ $^

cpp compile steps


//base.h
#ifndef __BASE_H__
#define __BASE_H__
#include <iostream>
using std::cout;
using std::endl;

class basePoint {
public:
    void setPoint(int, int);
    void display();
private:
    int x;
    int y;
};

#endif

//base.cpp
#ifndef __BASE_CPP__
#define __BASE_CPP__
#include "base.h"

void basePoint::setPoint(int x, int y) {
    this->x = x;
    this->y = y;
}

void basePoint::display() {
    std::cout << x << " " << y << std::endl;
}

#endif

//main.cpp
#include "base.h"

int main(int argc, char* argv[]) {
    basePoint bp0;
    basePoint *bp1 = new basePoint();

    bp0.setPoint(1, 2);
    bp1->setPoint(3, 4);
    bp0.display();
    bp1->display();
    return 0;
}

compile steps:
$ g++ -c base.cpp -o base.o
$ ar cr libbase.a base.o
$ g++ -c -I. main.cpp
$ g++ -o main main.o -L. -lbase

Saturday, February 22, 2014

VHDL code for serial interface

1) Design requirement:
This lab is to test your understanding of Serial Port Interface (SPI).  Your design shall accept a 50 megahertz clock signal, an asynchronous active low reset signal, an asynchronous 1-bit Load signal, an asynchronous 2-bit  slave selection signal , an asynchronous 5-bit  data signal. Your design shall have a master SPI controller which will accept the signals describe above and shall communicate with 3 slaves over a 3 wire SPI bus. Each slave shall drive 5 LEDs correspond to the 5-bit data received from the master as described in the table below.
slave selection [1:0]
Load
Definition
01
Rising edge
The master shall capture the data and send it to slave #1 and slave # 1 shall drive the LEDs with the data
10
Rising edge
The master shall capture the data and send it to slave #2 and slave # 2 shall drive the LEDs with the data
11
Rising edge
The master shall capture the data and send it to slave #3 and slave # 3 shall drive the LEDs with the data

                                              


                            SPI Timing Diagram

2) VHDL code:
library ieee;
use ieee.std_logic_1164.all;

--spi master
entity spi_m is
port (
    clk     : in std_logic;
    rst_n   : in std_logic;
    load    : in std_logic;
    slv_sel : in std_logic_vector(1 downto 0);
    din     : in std_logic_vector(4 downto 0);
    sclk    : out std_logic;
    cs_n    : out std_logic_vector(2 downto 0);
    sdio    : inout std_logic
);
end entity spi_m;

--begin of architecture
architecture behavioral of spi_m is
type spi_status is (IDLE, LOADDATA, SENDDATA, DONE);
signal clk_en       : std_logic                    ;
signal load_ff1     : std_logic                    ;
signal load_ff2     : std_logic                    ;
signal load_ff3     : std_logic                    ;
signal load_trig    : std_logic                    ;
signal slv_sel_ff1  : std_logic_vector(1 downto 0) ;
signal slv_sel_ff2  : std_logic_vector(1 downto 0) ;
signal spi_stat     : spi_status                   ;
signal spi_stat_nxt : spi_status                   ;
signal data         : std_logic_vector(4 downto 0) ;
signal index        : integer range 0 to 10        ;
signal sdi          : std_logic                    ;
signal sdo_en       : std_logic                    ;
begin

--generate sclk
sclk <= clk when clk_en = '1' else '0';

--generate sdio
sdio <= data(4) when sdo_en = '1' else 'Z';

--get sdi
sdi <= sdio;

--solve the metastability of async input
process(clk, rst_n)
begin
    if(rst_n = '0') then
        load_ff1 <= '0';
        load_ff2 <= '0';
        load_ff3 <= '0';
        slv_sel_ff1 <= "00";
        slv_sel_ff2 <= "00";
    elsif(rising_edge(clk)) then
        load_ff1 <= load;
        load_ff2 <= load_ff1;
        load_ff3 <= load_ff2;
        slv_sel_ff1 <= slv_sel;
        slv_sel_ff2 <= slv_sel_ff1;
    end if;
end process;

--get the change of load
load_trig <= load_ff2 and (not load_ff3);

--generate cs_n
process(clk, rst_n)
begin
    if(rst_n = '0') then
        cs_n <= "111";
    elsif(rising_edge(clk)) then
        if(spi_stat = IDLE) then
            case slv_sel_ff2 is
                when "01" =>
                    cs_n <= "110";
                when "10" =>
                    cs_n <= "101";
                when "11" =>
                    cs_n <= "011";
                when others =>
                    cs_n <= "111";
            end case;
        end if;
    end if;
end process;

--generate clk_en
process(clk, rst_n)
begin
    if(rst_n = '0') then
        clk_en <= '0';
    elsif(falling_edge(clk)) then
        if((spi_stat = SENDDATA) or (spi_stat = DONE)) then
            clk_en <= '1';
        else
            clk_en <= '0';
        end if;
    end if;
end process;

--generate data
process(clk, rst_n)
begin
    if(rst_n = '0') then
        data <= (others => '0');
    elsif(rising_edge(clk)) then
        if(spi_stat = LOADDATA) then
            data <= din;
        elsif(spi_stat = SENDDATA) then
            data <= data(3 downto 0) & '0';
        end if;
    end if;
end process;

--count index
process(clk, rst_n)
begin
    if(rst_n = '0') then
        index <= 0;
    elsif(rising_edge(clk)) then
        if(spi_stat = SENDDATA) then
            index <= index + 1;
        else
            index <= 0;
        end if;
    end if;
end process;

--generate sdo_en
process(clk, rst_n)
begin
    if(rst_n = '0') then
        sdo_en <= '0';
    elsif(rising_edge(clk)) then
        if((spi_stat = LOADDATA) or (spi_stat = SENDDATA)) then
            sdo_en <= '1';
        else
            sdo_en <= '0';
        end if;
    end if;
end process;

--spi master state machine
process(spi_stat, load_trig, index)
begin
    case spi_stat is
        when IDLE =>
            if(load_trig = '1') then
                spi_stat_nxt <= LOADDATA;
            else
                spi_stat_nxt <= IDLE;
            end if;
        when LOADDATA =>
            spi_stat_nxt <= SENDDATA;
        when SENDDATA =>
            if(index <= 2) then
                spi_stat_nxt <= SENDDATA;
            else
                spi_stat_nxt <= DONE;
            end if;
        when DONE =>
            spi_stat_nxt <= IDLE;
        when others =>
            spi_stat_nxt <= IDLE;
    end case;
end process;

--flip-flop spi_stat
process(clk, rst_n)
begin
    if(rst_n = '0') then
        spi_stat <= IDLE;
    elsif(rising_edge(clk)) then
        spi_stat <= spi_stat_nxt;
    end if;
end process;

--end of architecture
end behavioral;

library ieee;
use ieee.std_logic_1164.all;

--spi slave
entity spi_s is
port (
    sclk    : in    std_logic;
    rst_n   : in    std_logic;
    cs_n    : in    std_logic;
    sdio    : inout std_logic;
    led     : out   std_logic_vector(4 downto 0)
);
end entity spi_s;

--begin of architecture
architecture behavioral of spi_s is
signal sdi    : std_logic;
signal sdo    : std_logic;
signal sdo_en : std_logic;
signal data   : std_logic_vector(4 downto 0);
begin

sdi <= sdio;
sdio <= sdo when sdo_en = '1' else 'Z';

sdo_en <= '0';
sdo <= '0';

process(sclk, rst_n)
begin
    if(rst_n = '0') then
        data <= "00000";
    elsif(rising_edge(sclk)) then
        if(cs_n = '0') then
            data <= data(3 downto 0) & sdi;
        end if;
    end if;
end process;

led <= data;

--end of architecture
end behavioral;

library ieee;
use ieee.std_logic_1164.all;

entity top is
port (
    clk     : in std_logic;
    rst_n   : in std_logic;
    load    : in std_logic;
    slv_sel : in std_logic_vector(1 downto 0);
    din     : in std_logic_vector(4 downto 0);
    led0    : out std_logic_vector(4 downto 0);
    led1    : out std_logic_vector(4 downto 0);
    led2    : out std_logic_vector(4 downto 0)
);
end entity top;

architecture behavioral of top is
component spi_m is
port (
    clk     : in std_logic;
    rst_n   : in std_logic;
    load    : in std_logic;
    slv_sel : in std_logic_vector(1 downto 0);
    din     : in std_logic_vector(4 downto 0);
    sclk    : out std_logic;
    cs_n    : out std_logic_vector(2 downto 0);
    sdio    : inout std_logic
);
end component;

component spi_s is
port (
    sclk    : in    std_logic;
    rst_n   : in    std_logic;
    cs_n    : in    std_logic;
    sdio    : inout std_logic;
    led     : out   std_logic_vector(4 downto 0)
);
end component;

signal sclk: std_logic;
signal cs_n: std_logic_vector(2 downto 0);
signal sdio: std_logic;

begin

u_spi_m: spi_m port map (
    clk     => clk     ,
    rst_n   => rst_n   ,
    load    => load    ,
    slv_sel => slv_sel ,
    din     => din     ,
    sclk    => sclk    ,
    cs_n    => cs_n    ,
    sdio    => sdio  
);

u_spi0: spi_s port map (
    sclk  => sclk,
    rst_n => rst_n,
    cs_n  => cs_n(0),
    sdio  => sdio,
    led   => led0
);

u_spi1: spi_s port map (
    sclk  => sclk,
    rst_n => rst_n,
    cs_n  => cs_n(1),
    sdio  => sdio,
    led   => led1
);

u_spi2: spi_s port map (
    sclk  => sclk,
    rst_n => rst_n,
    cs_n  => cs_n(2),
    sdio  => sdio,
    led   => led2
);

end behavioral;

Friday, February 14, 2014

use VHDL to write a counter with more functions(2)

--Selector[1:0] | Boundary enable | Output [N: 0]
----------------------------------------------------------------
--00              0 or 1            0
--01              0                 Increment count by 7 from Boundary to 255 every half second and stop
--10              0                 Decrement count by 9 from 255 to Boundary every half second and stop
--11              0                 Increment count by 11 from Boundary to 255 then decrement by 15 to  Boundary every half second and stop
--01              1                 Increment count by 8 from 1 to Boundary every half second and stop
--10              1                 Decrement count by 13 from Boundary to 0 every half second and stop
--11              1                 Increment count by 14  from 1 to Boundary then decrement by 6 to  0 every half second and stop

-----------------------------------------------------------------
--clk dividor
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;

entity clk_div is
generic (
    N: integer := 12499999
);
port (
    clk     : in  std_logic;
    rst_n   : in  std_logic;
    clk_out : out std_logic
);
end entity clk_div;

architecture behavioral of clk_div is
signal clk_cnt     : integer range 0 to N;
signal clk_out_tmp : std_logic;
begin
--counter for half second
process(clk, rst_n)
begin
    if(rst_n = '0')then
        clk_cnt <= 0;
        clk_out_tmp <= '0';
    elsif(clk'event and clk = '1')  then
        --when counter reaches to half second,
        --need to reset the counter to 0
        if(clk_cnt = N) then
            clk_cnt <= 0;
            clk_out_tmp <= not (clk_out_tmp);
        else
            clk_cnt <= clk_cnt + 1;
            clk_out_tmp <= clk_out_tmp;
        end if;
    end if;
end process;

clk_out <= clk_out_tmp;

end behavioral;

-----------------------------------------------------------------
--kernel counter
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

entity kernel_counter is
generic (
    CNT_LEN : integer := 8
);
port (
    clk_in        : in  std_logic;
    rst_n         : in  std_logic;
    cnt_restart   : in  std_logic;
    cnt_type      : in  std_logic;
    cnt_inc       : in  std_logic_vector(CNT_LEN-1 downto 0);
    cnt_st_data   : in  std_logic_vector(CNT_LEN-1 downto 0);
    cnt_end_data  : in  std_logic_vector(CNT_LEN-1 downto 0);
    cnt_out       : out std_logic_vector(CNT_LEN-1 downto 0);
    cnt_done      : out std_logic
);
end entity kernel_counter;

architecture behavioral of kernel_counter is
signal cnt_end_data_new : std_logic_vector(CNT_LEN-1 downto 0);
signal cnt              : std_logic_vector(CNT_LEN-1 downto 0);
signal cnt_end          : std_logic_vector(CNT_LEN-1 downto 0);
type   cnt_status is (IDLE, LOAD, INC, DEC, DONE);
signal cnt_stat         : cnt_status;
signal cnt_stat_nxt     : cnt_status;
--signal cnt_type_ff1     : std_logic;

begin

process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt_end_data_new <= x"00";
    elsif(rising_edge(clk_in)) then
        if(cnt_stat = LOAD) then
            cnt_end_data_new <= cnt_end_data;
        end if;
    end if;
end process;

--when counter increase or decrease, get the last data that the counter can reach when counting
--process(cnt_restart, cnt_type_ff1, cnt_end_data, cnt_inc)
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt_end <= x"00";
    elsif(rising_edge(clk_in)) then
        if(cnt_stat = LOAD) then
            if(cnt_type = '0') then
                cnt_end <= cnt_end_data - cnt_inc - cnt_inc;
            else
                cnt_end <= cnt_end_data + cnt_inc + cnt_inc;
            end if;
        end if;
    end if;
end process;

--counter state machine
--counter to count how many half seconds
process(cnt_stat, cnt_type, cnt, cnt_end, cnt_restart)
begin
    case cnt_stat is
        when IDLE =>
            if(cnt_restart = '1') then
                cnt_stat_nxt <= LOAD;
            else
                cnt_stat_nxt <= IDLE;
            end if;
        when LOAD =>
            if(cnt_restart = '1') then
                cnt_stat_nxt <= LOAD;
            elsif(cnt_type = '0') then
                cnt_stat_nxt <= INC;
            else
                cnt_stat_nxt <= DEC;
            end if;
        when INC =>
            if(cnt_restart = '1') then
                cnt_stat_nxt <= LOAD;
            elsif(cnt >= cnt_end) then
                cnt_stat_nxt <= DONE;
            else
                cnt_stat_nxt <= INC;
            end if;
        when DEC =>
            if(cnt_restart = '1') then
                cnt_stat_nxt <= LOAD;
            elsif(cnt <= cnt_end) then
                cnt_stat_nxt <= DONE;
            else
                cnt_stat_nxt <= DEC;
            end if;
        when DONE =>
            if(cnt_restart = '1') then
                cnt_stat_nxt <= LOAD;
            else
                cnt_stat_nxt <= IDLE;
            end if;
        when others =>
            cnt_stat_nxt <= cnt_stat;
    end case;
end process;

process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt_stat <= IDLE;
    elsif(rising_edge(clk_in)) then
        cnt_stat <= cnt_stat_nxt;
    end if;
end process;

--cnt done
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt_done <= '0';
    elsif(rising_edge(clk_in)) then
        if(cnt_stat = DONE) then
            cnt_done <= '1';
        else
            cnt_done <= '0';
        end if;
    end if;
end process;

--one half second count
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt <= (others => '0');
    elsif(rising_edge(clk_in)) then
        if(cnt_stat = LOAD) then
            cnt <= cnt_st_data;
        elsif(cnt_stat = INC) then
            cnt <= cnt + cnt_inc;
        elsif(cnt_stat = DEC) then
            cnt <= cnt - cnt_inc;
        elsif(cnt_stat = DONE) then
            cnt <= cnt_end_data_new;
        end if;
    end if;
end process;

--send data out
cnt_out <= cnt;

end behavioral;

-----------------------------------------------------------------
--counter
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

entity counter is
port (
    clk_in        : in  std_logic;
    rst_n         : in  std_logic;
    selector      : in  std_logic_vector(1 downto 0);
    boundary_en   : in  std_logic;
    boundary_data : in  std_logic_vector(7 downto 0);
    data          : out std_logic_vector(7 downto 0)
);
end entity counter;

architecture behavioral of counter is
--signal declaration in architecture
signal selector_ff1            : std_logic_vector(1 downto 0);
signal selector_ff2            : std_logic_vector(1 downto 0);
signal selector_ff3            : std_logic_vector(1 downto 0);
signal selector_trig           : std_logic_vector(3 downto 0);
signal selector_trig_for_rvs   : std_logic_vector(3 downto 0);
signal boundary_en_ff1         : std_logic;
signal boundary_en_ff2         : std_logic;
signal boundary_en_ff3         : std_logic;
signal boundary_en_trig        : std_logic;
signal boundary_data_ff1       : std_logic_vector(7 downto 0);
signal boundary_data_ff2       : std_logic_vector(7 downto 0);
signal boundary_data_ff3       : std_logic_vector(7 downto 0);
signal boundary_data_trig      : std_logic;
signal cnt_restart             : std_logic;
signal reverse                 : std_logic;
signal reverse_ff1             : std_logic;
signal reverse_trig            : std_logic;
signal reverse_nxt             : std_logic;
signal cnt_type                : std_logic;
signal cnt_inc                 : std_logic_vector(7 downto 0);
signal cnt_st_data             : std_logic_vector(7 downto 0);
signal cnt_end_data            : std_logic_vector(7 downto 0);
signal cnt_out                 : std_logic_vector(7 downto 0);
signal cnt_inc_end             : std_logic_vector(7 downto 0);
signal cnt_en_trig             : std_logic;
signal cnt_dis_trig            : std_logic;
signal cnt_type_1_trig         : std_logic;
signal cnt_done                : std_logic;

constant select01_boundary0_inc : std_logic_vector(7 downto 0) := x"07" ;
constant select01_boundary1_inc : std_logic_vector(7 downto 0) := x"08" ;
constant select10_boundary0_dec : std_logic_vector(7 downto 0) := x"09" ;
constant select10_boundary1_dec : std_logic_vector(7 downto 0) := x"0d" ;
constant select11_boundary0_inc : std_logic_vector(7 downto 0) := x"0b" ;
constant select11_boundary1_inc : std_logic_vector(7 downto 0) := x"0e" ;
constant select11_boundary0_dec : std_logic_vector(7 downto 0) := x"0f" ;
constant select11_boundary1_dec : std_logic_vector(7 downto 0) := x"06" ;

--function to convert boolean to std_logic
function to_stdulogic(V: Boolean) return std_ulogic is
begin
    if V then
        return '1';
    else
        return '0';
    end if;
end to_stdulogic;

--kernel counter
component kernel_counter is
generic (
    CNT_LEN : integer := 8
);
port (
    clk_in        : in  std_logic;
    rst_n         : in  std_logic;
    cnt_restart   : in  std_logic;
    cnt_type      : in  std_logic;
    cnt_inc       : in  std_logic_vector(CNT_LEN-1 downto 0);
    cnt_st_data   : in  std_logic_vector(CNT_LEN-1 downto 0);
    cnt_end_data  : in  std_logic_vector(CNT_LEN-1 downto 0);
    cnt_out       : out std_logic_vector(CNT_LEN-1 downto 0);
    cnt_done      : out std_logic
);
end component;

--begin of architecture
begin

--instance kernel counter
u_kernel_counter: kernel_counter generic map (
    CNT_LEN => 8
) port map (
    clk_in        => clk_in       ,
    rst_n         => rst_n        ,
    cnt_restart   => cnt_restart  ,
    cnt_type      => cnt_type     ,
    cnt_inc       => cnt_inc      ,
    cnt_st_data   => cnt_st_data  ,
    cnt_end_data  => cnt_end_data ,
    cnt_out       => cnt_out      ,
    cnt_done      => cnt_done
);

--solve metastability issue, so 2 flip-flops are needed
--sample the change of selector, so 3 flip-flops are needed
--so add 3 flip-flops
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        selector_ff1      <= b"00" ;
        selector_ff2      <= b"00" ;
        selector_ff3      <= b"00" ;
        boundary_en_ff1   <= '0'   ;
        boundary_en_ff2   <= '0'   ;
        boundary_en_ff3   <= '0'   ;
        boundary_data_ff1 <= x"00" ;
        boundary_data_ff2 <= x"00" ;
        boundary_data_ff3 <= x"00" ;
    elsif(clk_in'event and clk_in = '1') then
        selector_ff1      <= selector          ;
        selector_ff2      <= selector_ff1      ;
        selector_ff3      <= selector_ff2      ;
        boundary_en_ff1   <= boundary_en       ;
        boundary_en_ff2   <= boundary_en_ff1   ;
        boundary_en_ff3   <= boundary_en_ff2   ;
        boundary_data_ff1 <= boundary_data     ;
        boundary_data_ff2 <= boundary_data_ff1 ;
        boundary_data_ff3 <= boundary_data_ff2 ;
    end if;
end process;

boundary_data_trig <= to_stdulogic(boundary_data_ff2 /= boundary_data_ff3);
boundary_en_trig <= to_stdulogic(boundary_en_ff2 /= boundary_en_ff3);

--sample the change of selector
--use each bit to represent one selector
selector_trig_for_rvs(0) <= to_stdulogic(
                        ((selector_ff2 = b"00") and (selector_ff3 /= b"00")) or
                        (((boundary_data_trig = '1') or (boundary_en_trig = '1')) and (selector_ff2 = b"00"))
                    );
selector_trig_for_rvs(1) <= to_stdulogic(
                        ((selector_ff2 = b"01") and (selector_ff3 /= b"01")) or
                        (((boundary_data_trig = '1') or (boundary_en_trig = '1')) and (selector_ff2 = b"01"))
                    );
selector_trig_for_rvs(2) <= to_stdulogic(
                        ((selector_ff2 = b"10") and (selector_ff3 /= b"10")) or
                        (((boundary_data_trig = '1') or (boundary_en_trig = '1')) and (selector_ff2 = b"10"))
                    );
selector_trig_for_rvs(3) <= to_stdulogic(
                        ((selector_ff2 = b"11") and (selector_ff3 /= b"11")) or
                        (((boundary_data_trig = '1') or (boundary_en_trig = '1')) and (selector_ff2 = b"11"))
                    );

selector_trig <= to_stdulogic(
                        ((selector_ff2 = b"11") and (selector_ff3 /= b"11")) or
                        (((boundary_data_trig = '1') or (boundary_en_trig = '1') or (reverse_trig = '1')) and (selector_ff2 = b"11"))
                    ) & selector_trig_for_rvs(2) & selector_trig_for_rvs(1) & selector_trig_for_rvs(0);

--when selector is change, calculate the next data displayed on screen
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt_st_data <= x"00";
    elsif(rising_edge(clk_in)) then
        case selector_trig is
            when b"0001" =>
                cnt_st_data <= x"00";
            when b"0010" =>
                if(boundary_en_ff2 = '0') then
                    cnt_st_data <= boundary_data_ff2;
                else
                    cnt_st_data <= x"01";
                end if;
            when b"0100" =>
                if(boundary_en_ff2 = '0') then
                    cnt_st_data <= x"ff";
                else
                    cnt_st_data <= boundary_data_ff2;
                end if;
            when b"1000" =>
                if(boundary_en_ff2 = '0') then
                    if(reverse = '1') then
                        cnt_st_data <= x"ff" - select11_boundary0_dec;
                    else
                        cnt_st_data <= boundary_data_ff2;
                    end if;
                else
                    if(reverse = '1') then
                        cnt_st_data <= boundary_data_ff2 - select11_boundary1_dec;
                    else
                        cnt_st_data <= x"01";
                    end if;
                end if;
            when others =>
                cnt_st_data <= cnt_st_data;
        end case;
    end if;
end process;

--when counter cannot counter but has not reached the last data, calculate the last data to display
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt_end_data <= x"00";
    elsif(rising_edge(clk_in)) then
        case selector_trig is
            when b"0001" =>
                cnt_end_data <= x"00";
            when b"0010" =>
                if(boundary_en_ff2 = '0') then
                    cnt_end_data <= x"ff";
                else
                    cnt_end_data <= boundary_data_ff2;
                end if;
            when b"0100" =>
                if(boundary_en_ff2 = '0') then
                    cnt_end_data <= boundary_data_ff2;
                else
                    cnt_end_data <= x"00";
                end if;
            when b"1000" =>
                if(boundary_en_ff2 = '0') then
                    if(reverse = '1') then
                        cnt_end_data <= boundary_data_ff2;
                    else
                        cnt_end_data <= x"ff";
                    end if;
                else
                    if(reverse = '1') then
                        cnt_end_data <= x"00";
                    else
                        cnt_end_data <= boundary_data_ff2;
                    end if;
                end if;
            when others =>
                cnt_end_data <= cnt_end_data;
        end case;
    end if;
end process;

--counter increment or decrement for each clock
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt_inc <= x"00";
    elsif(rising_edge(clk_in)) then
        case selector_trig is
            when b"0001" =>
                cnt_inc  <= x"00";
            when b"0010" =>
                if(boundary_en_ff2 = '0') then
                    cnt_inc <= select01_boundary0_inc;
                else
                    cnt_inc <= select01_boundary1_inc;
                end if;
            when b"0100" =>
                if(boundary_en_ff2 = '0') then
                    cnt_inc <= select10_boundary0_dec;
                else
                    cnt_inc <= select10_boundary1_dec;
                end if;
            when b"1000" =>
                if(boundary_en_ff2 = '0') then
                    if(reverse = '1') then
                        cnt_inc <= select11_boundary0_dec;
                    else
                        cnt_inc <= select11_boundary0_inc;
                    end if;
                else
                    if(reverse = '1') then
                        cnt_inc <= select11_boundary1_dec;
                    else
                        cnt_inc <= select11_boundary1_inc;
                    end if;
                end if;
            when others =>
                cnt_inc  <= cnt_inc;
        end case;
    end if;
end process;

--when counter increase in mode 3, get the last data that the counter can reach when counting
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt_inc_end <= x"00";
    elsif(rising_edge(clk_in)) then
        case selector_trig is
            when b"1000" =>
                if(boundary_en_ff2 = '0') then
                    cnt_inc_end <= x"ff" - select11_boundary0_inc;
                else
                    cnt_inc_end <= boundary_data_ff2 - select11_boundary1_inc;
                end if;
            when others =>
                cnt_inc_end <= cnt_inc_end;
        end case;
    end if;
end process;

--signal to control whether it is an increment or decrement
cnt_type_1_trig <= to_stdulogic((selector_ff2 = "11" and (reverse_trig = '1' or reverse = '1')) or (selector_ff2 = "10"));
--process(cnt_type_1_trig)
--begin
--    if(cnt_type_1_trig = '1') then
--        cnt_type <= '1';
--    else
--        cnt_type <= '0';
--    end if;
--end process;
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt_type <= '0';
    elsif(clk_in'event and clk_in = '1') then
        if(cnt_type_1_trig = '1') then
            cnt_type <= '1';
        else
            cnt_type <= '0';
        end if;
    end if;
end process;

--when in mode3, reverse will be changed to 1 when counter reach to the last data when increasing
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        reverse     <= '0';
    elsif(clk_in'event and clk_in = '1') then
        if(selector_trig_for_rvs /= x"0") then
            reverse <= '0';
        elsif(selector_ff2 = b"11") then
            if(reverse = '0') then
                if(cnt_out >= cnt_inc_end) then
                    reverse <= '1';
                else
                    reverse <= reverse;
                end if;
            else
                reverse <= reverse;
            end if;
        else
            reverse <= '0';
        end if;
    end if;
end process;

--delay reverse one cycle
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        reverse_ff1 <= '0';
    elsif(clk_in'event and clk_in = '1') then
        reverse_ff1 <= reverse;
    end if;
end process;

--find a reverse change in mode3
reverse_trig <= reverse and (not reverse_ff1);
--signal to trigger kernel counter to restart
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt_restart  <= '0';
    elsif(clk_in'event and clk_in = '1') then
        cnt_restart  <= selector_trig(0) or selector_trig(1) or selector_trig(2) or selector_trig(3);
    end if;
end process;

--send the counter data out
data <= cnt_out;

end behavioral;
--end of architecture

-----------------------------------------------------------------
--convert to segment
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;

entity hex2segment is
generic (
    M: integer := 7
);
port (
    hex     : in std_logic_vector(3 downto 0);
    segment : out std_logic_vector(M-1 downto 0)
);
end entity hex2segment;

architecture behavioral of hex2segment is

begin

SEGMENT_WITHOUT_DP: if M=7 generate
process(hex)
begin
    case hex is
        --decode from hex to segment
        when x"0" => segment <= b"1000000";
        when x"1" => segment <= b"1111001";
        when x"2" => segment <= b"0100100";
        when x"3" => segment <= b"0110000";
        when x"4" => segment <= b"0011001";
        when x"5" => segment <= b"0010010";
        when x"6" => segment <= b"0000010";
        when x"7" => segment <= b"1111000";
        when x"8" => segment <= b"0000000";
        when x"9" => segment <= b"0010000";
        when x"a" => segment <= b"0001000";
        when x"b" => segment <= b"0000011";
        when x"c" => segment <= b"1000110";
        when x"d" => segment <= b"0100001";
        when x"e" => segment <= b"0000110";
        when x"f" => segment <= b"0001110";
        --when in selector 1, counter should add 1 after each half second
        --for other unknown selectors, set counter to 0
        when others => segment <= b"1000000";
    end case;
end process;
end generate SEGMENT_WITHOUT_DP;

SEGMENT_WITH_DP: if M=8 generate
process(hex)
begin
    case hex is
        --decode from hex to segment
        when x"0" => segment <= b"11000000";
        when x"1" => segment <= b"11111001";
        when x"2" => segment <= b"10100100";
        when x"3" => segment <= b"10110000";
        when x"4" => segment <= b"10011001";
        when x"5" => segment <= b"10010010";
        when x"6" => segment <= b"10000010";
        when x"7" => segment <= b"11111000";
        when x"8" => segment <= b"10000000";
        when x"9" => segment <= b"10010000";
        when x"a" => segment <= b"10001000";
        when x"b" => segment <= b"10000011";
        when x"c" => segment <= b"11000110";
        when x"d" => segment <= b"10100001";
        when x"e" => segment <= b"10000110";
        when x"f" => segment <= b"10001110";
        --when in selector 1, counter should add 1 after each half second
        --for other unknown selectors, set counter to 0
        when others => segment <= b"11000000";
    end case;
end process;

end generate SEGMENT_WITH_DP;

end behavioral;

-----------------------------------------------------------------
--top
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;

entity top is
generic (
    M: integer := 7;
    N: integer := 12499999
);
port (
    clk           : in  std_logic;
    rst_n         : in  std_logic;
    selector      : in  std_logic_vector(1 downto 0);
    boundary_en   : in  std_logic;
    boundary_data : in  std_logic_vector(7 downto 0);
    data          : out std_logic_vector(7 downto 0);
    segment0      : out std_logic_vector(M-1 downto 0);
    segment1      : out std_logic_vector(M-1 downto 0)
);
end entity top;

architecture behavioral of top is
--signal declaration in architecture
signal clk_out  : std_logic;
signal data_tmp : std_logic_vector(7 downto 0);
signal hex      : std_logic_vector(11 downto 0);

component clk_div is
generic (
    N: integer := 12499999
);
port (
    clk     : in  std_logic;
    rst_n   : in  std_logic;
    clk_out : out std_logic
);
end component;

component counter is
port (
    clk_in        : in  std_logic;
    rst_n         : in  std_logic;
    selector      : in  std_logic_vector(1 downto 0);
    boundary_en   : in  std_logic;
    boundary_data : in  std_logic_vector(7 downto 0);
    data          : out std_logic_vector(7 downto 0)
);
end component;

component hex2segment is
generic (
    M: integer := 7
);
port (
    hex     : in std_logic_vector(3 downto 0);
    segment : out std_logic_vector(M-1 downto 0)
);
end component;

--begin of architecture
begin

--instance clock dividor
u_clk_div: clk_div generic map (
    N => N
) PORT MAP (
    clk     => clk     ,
    rst_n   => rst_n   ,
    clk_out => clk_out
);

--instance counter
u_counter: counter PORT MAP (
    clk_in        => clk_out       ,
    rst_n         => rst_n         ,
    selector      => selector      ,
    boundary_en   => boundary_en   ,
    boundary_data => boundary_data ,
    data          => data_tmp    
);

data <= data_tmp;

--instance segment0
u_hex2segment_0: hex2segment generic map (
    M => M
) PORT MAP (
    hex     => data_tmp(3 downto 0),
    segment => segment0
);

--instance segment1
u_hex2segment_1: hex2segment generic map (
    M => M
) PORT MAP (
    hex     => data_tmp(7 downto 4),
    segment => segment1
);

end behavioral;
--end of architecture