# <center>Implementation of a Ring Oscilator on Xilinx PYNQ-Z1</center>
<center> TestLab, NCUE, Taiwan</center>
<center> 2020/11/28</center>
* 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
* 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
# * Double click to open RingOsc_v1_0_S00_AXI.v
* Edit the tail after Line 369 as
```verilog
// 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
// 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 [N1:0] Inv;
assign Inv[N1:1] Inv[N2:0];
nand g1(Inv[0], En, Inv[N1]);
assign OscClk Inv[N1];
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_LSBOPT_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
## (2) Incooperate the IP to Block Design
* Add IP > RingOsc_V1.0 > Run Block Automation > OK > Run Connection Automation > OK > Regenerate Layout > Save > Validate
![image.png](attachment:image.png)
* 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
## (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.
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 |
[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].
* Click Constraints > Right click constrs_1 > Add Sources > Add and Generate Constraints > Next > Create File < <u>RingOsc</u> > 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.
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
## (4) Report Inspection
* Schematics:
![image.png](attachment:image.png)
* Inverter ring and driven tree
![image.png](attachment:image.png)
* Pyhsical Layout
![image.png](attachment:image.png)
## (5) Testing the RingOsc IP
* Rename all .bit, .tcl and .hwh file as the same name > Upload to PYNQ here.
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import time
from pynq import Overlay
from pynq import MMIO
overlay = Overlay('RingOsc.bit')
ip = MMIO(0x43C00000, 0x10000)
ip.write(0, 0) # reset
ip.write(0, 1) # enable oscillating and reset counter
ip.write(0, 2) # oscilating and counting
x, y = [], []
for i in range(100):
ip.write(0, 1) # enable oscillating and reset counter
ip.write(0, 2) # oscilating and counting
time.sleep(0.01)
n = ip.read(4) * (1<<32) + ip.read(8)
x.append(i)
y.append( n )
plt.title('Frequency (Count per 10ms) with Ambles')
plt.plot(x, y)
plt.grid(True)
ip.read(4), ip.read(8)
ip.read(4), ip.read(8)
ip.read(4), ip.read(8)
ip.read(4), ip.read(8)
ip.write(0, 1)
ip.write(0, 2)
ip.read(8)
## (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 $\Delta{f}/{f} > 2\%$)