4
 
1
# <center>Implementation of a Ring Oscilator on Xilinx PYNQ-Z1</center>
2
3
<center> TestLab, NCUE, Taiwan</center>
4
<center> 2020/11/28</center>

Implementation of a Ring Oscilator on Xilinx PYNQ-Z1

TestLab, NCUE, Taiwan
2020/11/28
1
 
1
## (1) Create a New Slave AXI Lite IP

(1) Create a New Slave AXI Lite IP

2
 
1
* Open Vivado HLx 2018.2 > Create Project <u>RingOsc</u> at *workspace/RingOsc/* > Next > Next > Next > Next > Select Board <u>Pynq-z1</u> > Next > Finish
2
* Create Block Design > Add IP ZYNQ7 > Tools > Create and New Package IP > Next > Create a New AXI4 Periphal > Name <u>RingOsc</u> > Next > Next > Next Steps: <u>Edit IP</u> > Finish
  • Open Vivado HLx 2018.2 > Create Project RingOsc at workspace/RingOsc/ > Next > Next > Next > Next > Select Board Pynq-z1 > Next > Finish
  • Create Block Design > Add IP ZYNQ7 > Tools > Create and New Package IP > Next > Create a New AXI4 Periphal > Name RingOsc > Next > Next > Next Steps: Edit IP > Finish
40
 
1
# * Double click to open RingOsc_v1_0_S00_AXI.v
2
* Edit the tail after Line 369 as
3
4
```verilog
5
    // Add user logic here
6
    reg    [63:0] Q;
7
    reg    En, Clr;
8
    always @( posedge S_AXI_ACLK )
9
        case(slv_reg0 )
10
            32'h0   : begin En <= 1'h0; Clr <= 1'h0; end
11
            32'h1   : begin En <= 1'h1; Clr <= 1'h1; end           
12
            32'h2   : begin En <= 1'h1; Clr <= 1'h0; end           
13
        endcase
14
        
15
    parameter N = 21;
16
    wire  OscClk;
17
    (*DONT_TOUCH= "true"*) wire [N-1:0] Inv;
18
    assign  Inv[N-1:1] = ~ Inv[N-2:0];
19
    nand    g1(Inv[0], En, Inv[N-1]);
20
    assign  OscClk = Inv[N-1];
21
        
22
    always @(posedge OscClk)
23
        if (Clr == 1'h1) Q <= 64'h0;
24
        else Q <= Q + 1'h1;
25
    // User logic ends
26
    
27
    always @(*)
28
    begin
29
          // Address decoding for reading registers
30
          case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
31
            2'h0   : reg_data_out <= slv_reg0;
32
            2'h1   : reg_data_out <= Q[63:32];
33
            2'h2   : reg_data_out <= Q[31:0];
34
            2'h3   : reg_data_out <= slv_reg3;
35
            default : reg_data_out <= 0;
36
          endcase
37
    end
38
endmodule
39
```
40
* Review and Package > Re-Package IP > Yes

* Double click to open RingOsc_v1_0_S00_AXI.v

  • Edit the tail after Line 369 as
    // Add user logic here
    reg    [63:0] Q;
    reg    En, Clr;
    always @( posedge S_AXI_ACLK )
        case(slv_reg0 )
            32'h0   : begin En <= 1'h0; Clr <= 1'h0; end
            32'h1   : begin En <= 1'h1; Clr <= 1'h1; end           
            32'h2   : begin En <= 1'h1; Clr <= 1'h0; end           
        endcase

    parameter N = 21;
    wire  OscClk;
    (*DONT_TOUCH= "true"*) wire [N-1:0] Inv;
    assign  Inv[N-1:1] = ~ Inv[N-2:0];
    nand    g1(Inv[0], En, Inv[N-1]);
    assign  OscClk = Inv[N-1];

    always @(posedge OscClk)
        if (Clr == 1'h1) Q <= 64'h0;
        else Q <= Q + 1'h1;
    // User logic ends

    always @(*)
    begin
          // Address decoding for reading registers
          case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
            2'h0   : reg_data_out <= slv_reg0;
            2'h1   : reg_data_out <= Q[63:32];
            2'h2   : reg_data_out <= Q[31:0];
            2'h3   : reg_data_out <= slv_reg3;
            default : reg_data_out <= 0;
          endcase
    end
endmodule
  • Review and Package > Re-Package IP > Yes
3
 
1
## (2) Incooperate the IP to Block Design
2
3
* Add IP > RingOsc_V1.0 > Run Block Automation > OK > Run Connection Automation > OK > Regenerate Layout > Save > Validate

(2) Incooperate the IP to Block Design

  • Add IP > RingOsc_V1.0 > Run Block Automation > OK > Run Connection Automation > OK > Regenerate Layout > Save > Validate
1
 
1
![image.png](attachment:image.png)

image.png

4
 
1
* Keep note of the address of S00_AXI in Address Editor, 0x43C0_0000
2
* Change the label from Design to Source > Right click RingOsc.bd > Create HDL Wrapper > OK
3
* Generate Bitstream
4
* Read the log and error message
  • Keep note of the address of S00_AXI in Address Editor, 0x43C0_0000
  • Change the label from Design to Source > Right click RingOsc.bd > Create HDL Wrapper > OK
  • Generate Bitstream
  • Read the log and error message
21
 
1
## (3) Add Constraint Files
2
3
* Directives for Design Constraints:
4
5
|Level | Approach | Example |
6
|----|----|----|
7
|Normal|Variable Tappping|Combinational Circuit|
8
|Generic synthesis|(*KEEP="TRUE"*)|Generic Logic|
9
|Placement synthesis|(*DONT_TOUCH="TRUE"*)|Delayline|
10
|Routing DRC|(*ALLOW_COMBINATORIAL_LOOPS="TRUE"*)|Ring Oscillator|
11
|Full Custom|set_property LOC SLICE_X50Y151  [get_cells hierachy/inst.LUT]|Specific MSA|
12
13
* Without DRC constraints, you will get a suggestion as follows:
14
15
```
16
    [DRC LUTLP-1] Combinatorial Loop Alert: ...
17
    'set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets <myHier/myNet>]'
18
    One net in the loop is RingOsc_i/RingOsc_0/inst/RingOsc_v1_0_S00_AXI_inst/Inv[11].
19
```    
20
    
21
* This helps you to unroll and look up the complex hierarchy for next step.

(3) Add Constraint Files

  • Directives for Design Constraints:
Level Approach Example
Normal Variable Tappping Combinational Circuit
Generic synthesis (KEEP="TRUE") Generic Logic
Placement synthesis (DONT_TOUCH="TRUE") Delayline
Routing DRC (ALLOW_COMBINATORIAL_LOOPS="TRUE") Ring Oscillator
Full Custom set_property LOC SLICE_X50Y151 [get_cells hierachy/inst.LUT] Specific MSA
  • Without DRC constraints, you will get a suggestion as follows:
    [DRC LUTLP-1] Combinatorial Loop Alert: ...
    'set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets <myHier/myNet>]'
    One net in the loop is RingOsc_i/RingOsc_0/inst/RingOsc_v1_0_S00_AXI_inst/Inv[11].
  • This helps you to unroll and look up the complex hierarchy for next step.
10
 
1
* Click Constraints > Right click constrs_1 > Add Sources > Add and Generate Constraints > Next > Create File < <u>RingOsc</u> > OK > Finish
2
* Unroll Hierarchy /Design Sources/RingOsc_wrapper/RingOsc_i/RingOsc_0/
3
* Under Label Sources > Click constrs_1 > Double click RingOsc.xdc to edit as follows:
4
5
    **set_property ALLOW_COMBINATORIAL_LOOPS TRUE [ get_nets  RingOsc_i/RingOsc_0/inst/RingOsc_v1_0_S00_AXI_inst/Inv[11] ]**
6
    
7
* Generate Bitstream
8
* File > Explort Bitstream to E:/Work/Vivado/RingOsc/RingOsc.bit
9
* In the TCL Console > *write_bd_tcl  Workspace/Vivado/RingOsc/RingOsc.tcl*
10
* File > Export Hardware, one .hwh can be found in Workspace\Vivado\RingOsc\RingOsc.srcs\sources_1\bd\RingOsc\hw_handoff.
  • Click Constraints > Right click constrs_1 > Add Sources > Add and Generate Constraints > Next > Create File < RingOsc > OK > Finish
  • Unroll Hierarchy /Design Sources/RingOsc_wrapper/RingOsc_i/RingOsc_0/
  • Under Label Sources > Click constrs_1 > Double click RingOsc.xdc to edit as follows:

    set_property ALLOW_COMBINATORIAL_LOOPS TRUE [ get_nets RingOsc_i/RingOsc_0/inst/RingOsc_v1_0_S00_AXI_inst/Inv[11] ]

  • Generate Bitstream

  • File > Explort Bitstream to E:/Work/Vivado/RingOsc/RingOsc.bit
  • In the TCL Console > write_bd_tcl Workspace/Vivado/RingOsc/RingOsc.tcl
  • File > Export Hardware, one .hwh can be found in Workspace\Vivado\RingOsc\RingOsc.srcs\sources_1\bd\RingOsc\hw_handoff.
4
 
1
## (4) Report Inspection
2
3
* Schematics:
4
![image.png](attachment:image.png)

(4) Report Inspection

  • Schematics: image.png
3
 
1
* Inverter ring and driven tree
2
3
![image.png](attachment:image.png)
  • Inverter ring and driven tree

image.png

3
 
1
* Pyhsical Layout
2
3
![image.png](attachment:image.png)
  • Pyhsical Layout

image.png

3
 
1
## (5) Testing the RingOsc IP
2
3
* Rename all .bit, .tcl and .hwh file as the same name > Upload to PYNQ here.

(5) Testing the RingOsc IP

  • Rename all .bit, .tcl and .hwh file as the same name > Upload to PYNQ here.
In [7]:
1
25
 
1
%matplotlib inline
2
import matplotlib.pyplot as plt
3
import numpy as np
4
import time
5
6
from pynq import Overlay
7
from pynq import MMIO
8
overlay = Overlay('RingOsc.bit')
9
ip = MMIO(0x43C00000, 0x10000)
10
11
ip.write(0, 0) # reset
12
ip.write(0, 1) # enable oscillating and reset counter
13
ip.write(0, 2) # oscilating and counting
14
15
x, y = [], []
16
for i in range(100):
17
    ip.write(0, 1) # enable oscillating and reset counter
18
    ip.write(0, 2) # oscilating and counting
19
    time.sleep(0.01)
20
    n = ip.read(4) * (1<<32) + ip.read(8)
21
    x.append(i)
22
    y.append( n )
23
plt.title('Frequency (Count per 10ms) with Ambles')
24
plt.plot(x, y)
25
plt.grid(True)   
In [2]:
1
 
1
ip.read(4), ip.read(8)
Out[2]:
(0, 353243443)
In [3]:
1
 
1
ip.read(4), ip.read(8)
Out[3]:
(0, 406953378)
In [4]:
1
 
1
ip.read(4), ip.read(8)
Out[4]:
(0, 446130631)
In [5]:
1
 
1
ip.read(4), ip.read(8)
Out[5]:
(0, 489538343)
In [6]:
1
 
1
ip.write(0, 1)
2
ip.write(0, 2)
3
ip.read(8)
Out[6]:
70478
9
 
1
## (6) Applications
2
3
* True Random Number Generator
4
* Physical Unclonable Function (PUF) for Hardware Security
5
* Thermal Sensors
6
* Aging Sensors
7
* Voltage Drop and IDDQ Sensors (inaccurate)
8
* Clock Generator for coarse applications
9
* Digital Delay Lock Loop (rough due to $\Delta{f}/{f} > 2\%$)

(6) Applications

  • True Random Number Generator
  • Physical Unclonable Function (PUF) for Hardware Security
  • Thermal Sensors
  • Aging Sensors
  • Voltage Drop and IDDQ Sensors (inaccurate)
  • Clock Generator for coarse applications
  • Digital Delay Lock Loop (rough due to Δf/f>2%)