kclkgen.v
3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// kclkgen.v v1 Frank Berndt
// pll clock generator module for r4300;
// :set tabstop=4
`timescale 1ps/1ps
module kclkgen (
ksyncout, ktclock, csclk4xb, cscd2xb, cscd1xb, cspll1xb, kcoldreset,
pbypasspllb, pdivmode, pmripll1x, pllcap0, pllcap1, padcoldresetb, crrp2, psyncin,
pmasterclock, phi1, phi2, sclk, sclkb
);
input sclkb; // for synchronization, not used;
input sclk; // for synchronization, not used;
input psyncin; // for synchronization, not used;
input pmripll1x; // for synchronization, not used;
input pmasterclock; // master clock;
inout pllcap0; // analog pll filter, not used;
inout pllcap1; // analog pll filter, not used;
inout phi2; // for synchronization, not used;
inout phi1; // for synchronization, not used;
input [2:0] pdivmode; // divide mode;
input padcoldresetb; // cold reset input;
input crrp2; // rp mode is not implemented;
input pbypasspllb; // pll bypass, not used;
output ktclock;
output ksyncout;
output kcoldreset;
output cspll1xb;
output csclk4xb;
output cscd2xb;
output cscd1xb;
// measure time between rising edges of master clock;
// require 8 master clocks before starting pll lock;
reg [3:0] nmclock;
wire lock; // start locking pll;
reg locked; // pll is locked;
integer t0, t1;
integer mclk_period; // masterclock period;
integer pclk_period; // pipeline clock period;
initial
begin
nmclock = 0;
locked = 0;
t0 = -1;
mclk_period = 10000;
pclk_period = 10000;
end
assign lock = nmclock[3];
always @(posedge pmasterclock)
begin
if( !lock) begin
t1 = $time;
mclk_period = t1 - t0;
t0 = t1;
nmclock = nmclock + 1;
end
end
// restart pll locking on assertion of cold reset;
always @(negedge padcoldresetb)
begin
nmclock = 4'd0;
locked = 0;
end
// monitor change in master clock;
always @(mclk_period)
begin
if(lock)
$display("ERROR: %t: %M: masterclock changed after pll started locking", $time);
end
// monitor change of divmode;
always @(pdivmode)
begin
if(lock)
$display("ERROR: %t: %M: divmode changed after pll started locking", $time);
end
// drive x1 clock;
reg cscd1xb;
initial
cscd1xb = 0;
always
#(mclk_period / 2) cscd1xb = ~cscd1xb;
// create pipeline clock;
reg pclock; // pipeline clock;
integer mult, div; // clock ratio;
integer pclk_check; // for fraction check;
integer pclk_rand; // random pclock before lock;
initial
begin
pclock = 1;
end
always @(mclk_period or pdivmode or lock)
begin
case(pdivmode)
3'b000: begin mult = 1; div = 1; end // x1
3'b001: begin mult = 1; div = 2; end // x2
3'b010: begin mult = 2; div = 5; end // x2.5
3'b011: begin mult = 1; div = 4; end // x4
3'b100: begin mult = 1; div = 4; end // x4
3'b101: begin mult = 2; div = 3; end // x1.5
3'b110: begin mult = 1; div = 2; end // x2
3'b111: begin mult = 1; div = 3; end // x3
endcase
pclk_period = (mclk_period * mult) / div;
pclk_check = (pclk_period * div) / mult;
if(lock & (mclk_period != pclk_check)) begin
$display("ERROR: %t: %M: fraction in clock ratios, mclk %0dps, pclk %0dps",
$time, mclk_period, pclk_period);
$finish;
end
end
// produce random pclock until locked;
// limit frequency range between 5ns...5ns+2^15;
// align rising edges of pmasterclock and pclock;
always
begin
if(locked)
#(pclk_period / 2);
else if(lock) begin
$display("%t: %M: mclk %0dps, pclk %0dps", $time, mclk_period, pclk_period);
@(posedge pmasterclock);
locked = 1;
pclock = 1;
#(pclk_period / 2);
end else begin
pclk_rand = 5000 + ($random & 16'h7fff);
#(pclk_rand);
end
pclock = ~pclock;
end
assign cscd2xb = pclock;
// hard-wire fixed signals;
assign kcoldreset = ~padcoldresetb;
assign ksyncout = pmasterclock;
assign ktclock = ~cscd1xb;
assign cspll1xb = 0;
assign csclk4xb = 0;
endmodule