-
Notifications
You must be signed in to change notification settings - Fork 1
/
red_pitaya_asg_ch.v
314 lines (257 loc) · 9.66 KB
/
red_pitaya_asg_ch.v
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
/**
* $Id: red_pitaya_asg_ch.v 1271 2014-02-25 12:32:34Z matej.oblak $
*
* @brief Red Pitaya ASG submodule. Holds table and FSM for one channel.
*
* @Author Matej Oblak
*
* (c) Red Pitaya http://www.redpitaya.com
*
* This part of code is written in Verilog hardware description language (HDL).
* Please visit http://en.wikipedia.org/wiki/Verilog
* for more details on the language used herein.
*/
/**
* GENERAL DESCRIPTION:
*
* Arbitrary signal generator takes data stored in buffer and sends them to DAC.
*
*
* /-----\ /--------\
* SW --------> | BUF | ------> | kx + o | ---> DAC DAT
* | \-----/ \--------/
* | ^
* | |
* | /-----\
* ----> | |
* | FSM | ------> trigger notification
* trigger ---> | |
* \-----/
*
*
* Submodule for ASG which hold buffer data and control registers for one channel.
*
*/
module red_pitaya_asg_ch #(
parameter RSZ = 14,
parameter CYCLE_BITS = 32
)(
// DAC
output reg [ 14-1: 0] dac_o , //!< dac data output
input dac_clk_i , //!< dac clock
input dac_rstn_i , //!< dac reset - active low
// trigger
input trig_sw_i , //!< software trigger
input trig_ext_i , //!< external trigger
input [ 3-1: 0] trig_src_i , //!< trigger source selector
output trig_done_o , //!< trigger event
// buffer ctrl
input buf_we_i , //!< buffer write enable
input [ 14-1: 0] buf_addr_i , //!< buffer address
input [ 14-1: 0] buf_wdata_i , //!< buffer write data
output reg [ 14-1: 0] buf_rdata_o , //!< buffer read data
output reg [RSZ-1: 0] buf_rpnt_o , //!< buffer current read pointer
// configuration
input [RSZ+16-1: 0] set_size_i , //!< set table data size
input [RSZ+16-1: 0] set_step_i , //!< set pointer step
input [RSZ+16-1: 0] set_ofs_i , //!< set reset offset
input set_rst_i , //!< set FSM to reset
input set_once_i , //!< set only once -- not used
input set_wrap_i , //!< set wrap enable
input [ 14-1: 0] set_amp_i , //!< set amplitude scale
input [ 14-1: 0] set_dc_i , //!< set output offset
input set_zero_i , //!< set output to zero
input [ CYCLE_BITS-1: 0] set_ncyc_i , //!< set number of cycle
input [ 16-1: 0] set_rnum_i , //!< set number of repetitions
input [ 32-1: 0] set_rdly_i , //!< set delay between repetitions
input set_rgate_i , //!< set external gated repetition
////////////////////////////////
////////////////////////////////
input [14-1:0] amp_mod, // allows to do amplitude modulation
////////////////////////////////
////////////////////////////////
input rand_on_i , // random number generator on
input [RSZ-1:0] rand_pnt_i // random pointer for output data
);
//---------------------------------------------------------------------------------
//
// DAC buffer RAM
reg [ 14-1: 0] dac_buf [0:(1<<RSZ)-1] ;
reg [ 14-1: 0] dac_rd ;
reg [ 14-1: 0] dac_rdat ;
reg [ RSZ-1: 0] dac_rp ;
reg [RSZ+16-1: 0] dac_pnt ; // read pointer
reg [RSZ+16-1: 0] dac_pntp ; // previous read pointer
wire [RSZ+17-1: 0] dac_npnt ; // next read pointer
wire [RSZ+17-1: 0] dac_npnt_sub ;
wire dac_npnt_sub_neg;
reg [ 28-1: 0] dac_mult ;
////////////////////////////////
////////////////////////////////
reg [ 28-1: 0] dac_mod;
reg [ 15-1: 0] mod_sum;
reg [ 14-1: 0] amp_mod_reg;
////////////////////////////////
////////////////////////////////
reg [ 15-1: 0] dac_sum ;
// read
always @(posedge dac_clk_i)
begin
buf_rpnt_o <= dac_pnt[16+RSZ-1:16];
dac_rp <= (rand_on_i == 1'b1) ? rand_pnt_i : dac_pnt[RSZ+15:16];
dac_rd <= dac_buf[dac_rp] ;
dac_rdat <= dac_rd ; // improve timing
end
// write
always @(posedge dac_clk_i)
if (buf_we_i) dac_buf[buf_addr_i] <= buf_wdata_i[14-1:0] ;
// read-back disabled
//always @(posedge dac_clk_i)
//buf_rdata_o <= dac_buf[buf_addr_i] ;
// scale and offset
always @(posedge dac_clk_i)
begin
////////////////////////////////
////////////////////////////////
amp_mod_reg <= amp_mod;
dac_mod <= $signed(dac_rdat) * $signed(amp_mod_reg) ;
mod_sum <= $signed(dac_mod[28-1:14]) + $signed({{2{dac_rdat[14-1]}}, dac_rdat[14-1:2]}) ;
////////////////////////////////
////////////////////////////////
dac_mult <= $signed(mod_sum) * $signed({1'b0,set_amp_i}) ;
dac_sum <= $signed(dac_mult[28-1:13]) + $signed(set_dc_i) ;
// saturation
if (set_zero_i) dac_o <= 14'h0;
else dac_o <= ^dac_sum[15-1:15-2] ? {dac_sum[15-1], {13{~dac_sum[15-1]}}} : dac_sum[13:0];
end
//---------------------------------------------------------------------------------
//
// read pointer & state machine
reg trig_in ;
wire ext_trig_p ;
wire ext_trig_n ;
reg [ 32-1: 0] cyc_cnt ;
reg [ 16-1: 0] rep_cnt ;
reg [ 32-1: 0] dly_cnt ;
reg [ 8-1: 0] dly_tick ;
reg dac_do ;
reg dac_rep ;
wire dac_trig ;
reg dac_trigr ;
// state machine
always @(posedge dac_clk_i) begin
if (dac_rstn_i == 1'b0) begin
cyc_cnt <= {CYCLE_BITS{1'b0}} ;
rep_cnt <= 16'h0 ;
dly_cnt <= 32'h0 ;
dly_tick <= 8'h0 ;
dac_do <= 1'b0 ;
dac_rep <= 1'b0 ;
trig_in <= 1'b0 ;
dac_pntp <= {RSZ+16{1'b0}} ;
dac_trigr <= 1'b0 ;
end
else begin
// make 1us tick
if (dac_do || (dly_tick == 8'd124))
dly_tick <= 8'h0 ;
else
dly_tick <= dly_tick + 8'h1 ;
// delay between repetitions
if (set_rst_i || dac_do)
dly_cnt <= set_rdly_i ;
else if (|dly_cnt && (dly_tick == 8'd124))
dly_cnt <= dly_cnt - 32'h1 ;
// repetitions counter
if (trig_in && !dac_do)
rep_cnt <= set_rnum_i ;
else if (!set_rgate_i && (|rep_cnt && dac_rep && (dac_trig && !dac_do)))
rep_cnt <= rep_cnt - 16'h1 ;
else if (set_rgate_i && ((!trig_ext_i && trig_src_i==3'd2) || (trig_ext_i && trig_src_i==3'd3)))
rep_cnt <= 16'h0 ;
// count number of table read cycles
dac_pntp <= dac_pnt;
dac_trigr <= dac_trig; // ignore trigger when count
if (dac_trig)
cyc_cnt <= set_ncyc_i ;
else if (!dac_trigr && |cyc_cnt && ({1'b0,dac_pntp} > {1'b0,dac_pnt}))
cyc_cnt <= cyc_cnt - 32'h1 ;
// trigger arrived
case (trig_src_i)
3'd1 : trig_in <= trig_sw_i ; // sw
3'd2 : trig_in <= ext_trig_p ; // external positive edge
3'd3 : trig_in <= ext_trig_n ; // external negative edge
3'd4 : trig_in <= trig_ext_i ; // unprocessed ext trigger
3'd5 : trig_in <= 1'b1 ; // always high
default : trig_in <= 1'b0 ;
endcase
// in cycle mode
if (dac_trig && !set_rst_i)
dac_do <= 1'b1 ;
else if (set_rst_i || ((cyc_cnt==32'h1) && ~dac_npnt_sub_neg) )
dac_do <= 1'b0 ;
// in repetition mode
if (dac_trig && !set_rst_i)
dac_rep <= 1'b1 ;
else if (set_rst_i || (rep_cnt==16'h0))
dac_rep <= 1'b0 ;
end
end
assign dac_trig = (!dac_rep && trig_in) || (dac_rep && |rep_cnt && (dly_cnt == 32'h0)) ;
assign dac_npnt_sub = dac_npnt - {1'b0,set_size_i} - 1;
assign dac_npnt_sub_neg = dac_npnt_sub[RSZ+16];
// read pointer logic
always @(posedge dac_clk_i)
if (dac_rstn_i == 1'b0) begin
dac_pnt <= {RSZ+16{1'b0}};
end else begin
if (set_rst_i || (dac_trig && !dac_do)) // manual reset or start
dac_pnt <= set_ofs_i;
else if (dac_do) begin
if (~dac_npnt_sub_neg) dac_pnt <= set_wrap_i ? dac_npnt_sub : set_ofs_i; // wrap or go to start
else dac_pnt <= dac_npnt[RSZ+16-1:0]; // normal increase
end
end
assign dac_npnt = dac_pnt + set_step_i;
assign trig_done_o = (!dac_rep && trig_in) | (~dac_npnt_sub_neg);
//---------------------------------------------------------------------------------
//
// External trigger
reg [ 3-1: 0] ext_trig_in ;
reg [ 2-1: 0] ext_trig_dp ;
reg [ 2-1: 0] ext_trig_dn ;
reg [ 20-1: 0] ext_trig_debp ;
reg [ 20-1: 0] ext_trig_debn ;
always @(posedge dac_clk_i) begin
if (dac_rstn_i == 1'b0) begin
ext_trig_in <= 3'h0 ;
ext_trig_dp <= 2'h0 ;
ext_trig_dn <= 2'h0 ;
ext_trig_debp <= 20'h0 ;
ext_trig_debn <= 20'h0 ;
end
else begin
//----------- External trigger
// synchronize FFs
ext_trig_in <= {ext_trig_in[1:0],trig_ext_i} ;
// look for input changes
if ((ext_trig_debp == 20'h0) && (ext_trig_in[1] && !ext_trig_in[2]))
ext_trig_debp <= 20'd62500 ; // ~0.5ms
else if (ext_trig_debp != 20'h0)
ext_trig_debp <= ext_trig_debp - 20'd1 ;
if ((ext_trig_debn == 20'h0) && (!ext_trig_in[1] && ext_trig_in[2]))
ext_trig_debn <= 20'd62500 ; // ~0.5ms
else if (ext_trig_debn != 20'h0)
ext_trig_debn <= ext_trig_debn - 20'd1 ;
// update output values
ext_trig_dp[1] <= ext_trig_dp[0] ;
if (ext_trig_debp == 20'h0)
ext_trig_dp[0] <= ext_trig_in[1] ;
ext_trig_dn[1] <= ext_trig_dn[0] ;
if (ext_trig_debn == 20'h0)
ext_trig_dn[0] <= ext_trig_in[1] ;
end
end
assign ext_trig_p = (ext_trig_dp == 2'b01) ;
assign ext_trig_n = (ext_trig_dn == 2'b10) ;
endmodule