x393  1.0
FPGAcodeforElphelNC393camera
status_generate.v
Go to the documentation of this file.
1 
39 `timescale 1ns/1ps
40 // mode bits:
41 // 0 disable status generation,
42 // 1 single status request,
43 // 2 - auto status, keep specified seq number,
44 // 3 - auto, inc sequence number
45 
46 module status_generate #(
47  parameter STATUS_REG_ADDR= 7, // status register address to direct data to
48  parameter PAYLOAD_BITS = 15, //6 // >=2! (2..26)
49  parameter REGISTER_STATUS = 1, // 1 - register input status data (for different clock domains), 0 - do not register (same domain)
50  parameter EXTRA_WORDS= 0, // should always be >0
51  // if EXTRA_WORDS >0 the mesasges with these extra data will be generated and sent before the status message itself
52  // if PAYLOAD_BITS == 0, then one status bit will still have to be provided (status input will have width of 1+32*EXTRA_WORDS),
53  // but the status message will not be sent - only the data words
54  parameter EXTRA_REG_ADDR= 8 // Where to place optional extra data words
55 )(
56  input rst,
57  input clk,
58  input srst, // @ posedge clk - sync reset
59  input we, // command strobe
60  input [7:0] wd, // command data - 6 bits of sequence and 2 mode bits
61  input [ALL_BITS-1:0] status, // parallel status data to be sent out, may come from different clock domain
62  output [7:0] ad, // byte-wide address/data
63  output rq, // request to send downstream (last byte with rq==0)
64  input start // acknowledge of address (first byte) from downstream
65 );
66  localparam STATUS_BITS = ((PAYLOAD_BITS > 0) ? PAYLOAD_BITS: 1);
67  localparam ALL_BITS = STATUS_BITS + 32 * EXTRA_WORDS;
68  generate
69  if (EXTRA_WORDS >0) begin
74  .EXTRA_WORDS (EXTRA_WORDS), // guaranteed >0
76  ) status_generate_extra_i (
77  .rst (rst), // input
78  .clk (clk), // input
79  .srst (srst), // input
80  .we (we), // input
81  .wd (wd), // input[7:0]
82  .status (status), // input[46:0]
83  .ad (ad), // output[7:0]
84  .rq (rq), // output
85  .start (start) // input
86  );
87 
88  end else begin
93  ) status_generate_only_i (
94  .rst (rst), // input
95  .clk (clk), // input
96  .srst (srst), // input
97  .we (we), // input
98  .wd (wd), // input[7:0]
99  .status (status[PAYLOAD_BITS-1:0]), // input[14:0]
100  .ad (ad), // output[7:0]
101  .rq (rq), // output
102  .start (start) // input
103  );
104 
105  end
106  endgenerate
107 
108 endmodule
109 
110 //module that generates only status message
112  parameter STATUS_REG_ADDR = 7, // status register address to direct data to
113  parameter PAYLOAD_BITS = 15, //6 // >=2! (2..26)
114  parameter REGISTER_STATUS = 1 // 1 - register input status data (for different clock domains), 0 - do not register (same domain)
115 )(
116  input rst,
117  input clk,
118  input srst, // @ posedge clk - sync reset
119  input we, // command strobe
120  input [7:0] wd, // command data - 6 bits of sequence and 2 mode bits
121  input [PAYLOAD_BITS-1:0] status, // parallel status data to be sent out, may come from different clock domain
122  output [7:0] ad, // byte-wide address/data
123  output rq, // request to send downstream (last byte with rq==0)
124  input start // acknowledge of address (first byte) from downsteram
125 );
126 /*
127  Some tools may not like {0{}}, and currently VEditor makes it UNDEFINED->32 bits
128  assigning to constant?a:b now works if constant has defined value, i.e. if constant=1 b is ignored
129 */
130  localparam NUM_BYTES=(PAYLOAD_BITS+21)>>3;
131  localparam ALIGNED_STATUS_WIDTH=((NUM_BYTES-2)<<3)+2; // 2 ->2,
132  // ugly solution to avoid warnings in unused "if" branch
134  wire [1:0] mode_w;
135  reg [1:0] mode;
136  reg [5:0] seq;
137 // reg [PAYLOAD_BITS-1:0] status_r0; // registered status as it may come from the different clock domain
138  reg [PAYLOAD_BITS-1:0] status_r0r; // registered status as it may come from the different clock domain
139  wire [PAYLOAD_BITS-1:0] status_r0; // registered/not registered status deata depending on the REGISTER_STATUS
140 
141  reg [PAYLOAD_BITS-1:0] status_r; // "frozen" status to be sent;
142  reg status_changed_r; // not reset if status changes back to original
143  reg cmd_pend;
144  reg [((NUM_BYTES-1)<<3)-1:0] data;
145  wire snd_rest;
148 
149  reg [NUM_BYTES-2:0] rq_r;
150 
152  assign ad=data[7:0];
153  assign need_to_send=cmd_pend || (mode[1] && status_changed_r); // latency
154  assign rq=rq_r[0]; // NUM_BYTES-2];
155  assign snd_rest=rq_r[0] && !rq_r[NUM_BYTES-2];
156  assign mode_w=wd[7:6];
158 
159  always @ (posedge rst or posedge clk) begin
160 
161  if (rst) status_changed_r <= 0;
162  else if (srst) status_changed_r <= 0;
163  else if (start) status_changed_r <= 0;
164 // In simulation should be able to detect changes from initial 'x' in memories, in hardware
165 // any initial walue is OK, if not equal - will update, if equal - keep
166 `ifdef SIMULATION
167  else status_changed_r <= status_changed_r || (status_r !== status_r0);
168 `else
170 `endif
171 
172  if (rst) mode <= 0;
173  else if (srst) mode <= 0;
174  else if (we) mode <= mode_w; // wd[7:6];
175 
176  if (rst) seq <= 0;
177  else if (srst) seq <= 0;
178  else if (we) seq <= wd[5:0];
179  else if ((mode==3) && start) seq <= seq+1;
180 
181  if (rst) cmd_pend <= 0;
182  else if (srst) cmd_pend <= 0;
183  else if (we && (mode_w!=0)) cmd_pend <= 1;
184  else if (start) cmd_pend <= 0;
185 
186  if (rst) status_r0r <= 0;
187  else if (srst) status_r0r <= 0;
188  else status_r0r <= status;
189 
190  if (rst) status_r<=0;
191  else if (srst) status_r<=0;
192  else if (start) status_r<=status_r0;
193 
194  if (rst) data <= STATUS_REG_ADDR;
195  else if (srst) data <= STATUS_REG_ADDR;
196  else if (start) data <= (NUM_BYTES>2)?
198  {seq,status_r0[1:0]};
199  else if ((NUM_BYTES>2) && snd_rest) data <= data >> 8; // never happens with 2-byte packet
200  else data <= STATUS_REG_ADDR;
201 
202  if (rst) rq_r <= 0;
203  else if (srst) rq_r <= 0;
204  else if (need_to_send && !rq_r[0]) rq_r <= {NUM_BYTES-1{1'b1}};
205  else if (start || ((NUM_BYTES>2) && !rq_r[NUM_BYTES-2])) rq_r <= rq_r >> 1;
206  end
207 endmodule
209 //module that generates several 32-bit words and optionally status message
211  parameter STATUS_REG_ADDR= 7, // status register address to direct data to
212  parameter PAYLOAD_BITS = 1, ///15, //6 // >=2! (2..26)
213  parameter REGISTER_STATUS = 0, ///1, // 1 - register input status data (for different clock domains), 0 - do not register (same domain)
214  parameter EXTRA_WORDS= 2, ///1, // should always be >0
215 // parameter EXTRA_WORDS_LN2 = 3, // number of bits to select among extra words and (optional) status
216  // if EXTRA_WORDS >0 the mesasges with these extra data will be generated and sent before the status message itself
217  // if PAYLOAD_BITS == 0, then one status bit will still have to be provided (status input will have width of 1+32*EXTRA_WORDS),
218  // but the status message will not be sent - only the data words
219  parameter EXTRA_REG_ADDR= 8 // Where to place optional extra data words
220 )(
221  input rst,
222  input clk,
223  input srst, // @ posedge clk - sync reset
224  input we, // command strobe
225  input [7:0] wd, // command data - 6 bits of sequence and 2 mode bits
226 // input [PAYLOAD_BITS-1:0] status, // parallel status data to be sent out, may come from different clock domain
227  input [ALL_BITS-1:0] status, // parallel status data to be sent out, may come from different clock domain
228  output [7:0] ad, // byte-wide address/data
229  output rq, // request to send downstream (last byte with rq==0)
230  input start // acknowledge of address (first byte) from downsteram
231 );
233 // localparam EXTRA_WORDS_LN2 = $clog2(EXTRA_WORDS+1); // number of bits to select among extra words and (optional) status
234  localparam EXTRA_WORDS_LN2 = clogb2(EXTRA_WORDS+1); // number of bits to select among extra words and (optional) status
235 // multiple of 32 bits added to PAYLOAD_BITS, these words are not compared but always sent before status to locations above/below status one
236 // no need to register extra words - status should be modified after the extra.
237  localparam STATUS_BITS = ((PAYLOAD_BITS > 0) ? PAYLOAD_BITS: 1);
238  localparam ALL_BITS = STATUS_BITS + 32 * EXTRA_WORDS;
239  localparam NUM_MSG = EXTRA_WORDS + ((PAYLOAD_BITS > 0)? 1 : 0);
240 
241  localparam NUM_BYTES = (STATUS_BITS + 21) >> 3;
242  localparam ALIGNED_STATUS_WIDTH = ((NUM_BYTES - 2) << 3) + 2; // 2 ->2,
243  // ugly solution to avoid warnings in unused "if" branch
244  localparam ALIGNED_STATUS_BIT_2 = (ALIGNED_STATUS_WIDTH > 2) ? 2 : 0;
245  localparam STATUS_MASK = (1 << (NUM_BYTES) -1) - 1;
246 
247 // localparam [EXTRA_WORDS:0] START1HOT = 1 << EXTRA_WORDS;
248 
249  wire [1:0] mode_w;
250  reg [1:0] mode;
251  reg [5:0] seq;
252  reg [STATUS_BITS-1:0] status_r0r; // registered status as it may come from the different clock domain
253  wire [STATUS_BITS-1:0] status_r0; // registered/not registered status deata depending on the REGISTER_STATUS
254  reg [STATUS_BITS-1:0] status_r; // "frozen" status to be sent;
255  reg status_changed_r; // not reset if status changes back to original
256  reg cmd_pend;
257  reg [39:0] data;
258  wire need_to_send;
260 
261  reg [2:0] rq_r; // for all messages
262 
263  reg [NUM_MSG-1:0] msg1hot;
265  wire start_last; // start last message (status if enabled, or last data if PAYLOAD_BITS ==0)
267  wire start_status; // only for status message (if it is ever sent)
268  reg [7:0] next_addr; // address to use in the next message
269  wire [7:0] first_addr; // address to use in the first message
270 
271  reg [2:0] next_mask; // define duration (0 - 1 cycle, 1 - 2, 3 - 3, 7 - 4)
272  wire [2:0] first_mask; // define duration (0 - 1 cycle, 1 - 2, 3 - 3, 7 - 4)
273 
274 
275  reg [EXTRA_WORDS_LN2-1:0] msg_num;
276  wire [31:0] dont_care= 32'bx;
277 // wire [31:0] pre_mux [0:(1<<EXTRA_WORDS_LN2)-1];
278  wire [32 * (1<<EXTRA_WORDS_LN2) -1 :0] pre_mux;
279  wire [31:0] status32=(NUM_BYTES>2) ?
280  ((ALIGNED_STATUS_WIDTH < 26)?
283  {24'b0,seq,aligned_status[1:0]};
284 
286  genvar i;
287  generate
288  for (i = 0; i < (1<<EXTRA_WORDS_LN2); i=i+1) begin:gen_cyc1
289  assign pre_mux[32 * i +: 32] = (i < EXTRA_WORDS)? //status[PAYLOAD_BITS + 32*i +:32] : // actually change order!
290 // {status[PAYLOAD_BITS + 32*i + 24 +:8],status[PAYLOAD_BITS + 32*i +:24] }:
291  {status[PAYLOAD_BITS + 32*i +:24],status[PAYLOAD_BITS + 32*i + 24 +:8]}:
292  (((i == EXTRA_WORDS) && (PAYLOAD_BITS > 0)) ? status32 : dont_care);
293  end
294  endgenerate
295 
296 
298  assign ad=data[7:0];
299  assign need_to_send=cmd_pend || (mode[1] && status_changed_r); // latency
300  assign rq=rq_r[0]; // NUM_BYTES-2];
301  assign mode_w=wd[7:6];
303 
304  assign msg_is_last = msg1hot[NUM_MSG-1];
305  assign msg_is_status = msg_is_last && (PAYLOAD_BITS > 0);
306  assign start_last = start && msg_is_last;
307  assign start_status = start && msg_is_status;
309  assign first_mask = (EXTRA_WORDS>0) ? 7 : STATUS_MASK;
310 
311  always @ (posedge rst or posedge clk) begin
312 
313  if (rst) status_changed_r <= 0;
314  else if (srst) status_changed_r <= 0;
315  else if (start_last) status_changed_r <= 0;
317 
318  if (rst) mode <= 0;
319  else if (srst) mode <= 0;
320  else if (we) mode <= mode_w; // wd[7:6];
321 
322  if (rst) seq <= 0;
323  else if (srst) seq <= 0;
324  else if (we) seq <= wd[5:0];
325  else if ((mode==3) && start_status) seq <= seq+1; // no need to increment sequence number if no status is sent
326 
327  if (rst) cmd_pend <= 0;
328  else if (srst) cmd_pend <= 0;
329  else if (we && (mode_w!=0)) cmd_pend <= 1;
330  else if (start_last) cmd_pend <= 0;
331 
332  if (rst) status_r0r <= 0;
333  else if (srst) status_r0r <= 0;
334  else status_r0r <= status[STATUS_BITS-1:0];
335 
336  if (rst) status_r <= 0;
337  else if (srst) status_r <= 0;
338  else if (start_last) status_r <= status_r0;
339 
340  if (rst) next_addr <= first_addr;
341  else if (srst) next_addr <= first_addr;
342  else if (!need_to_send || start_last) next_addr <= first_addr;
343 // else if (start && (msg1hot[EXTRA_WORDS -1:0])) next_addr <= STATUS_REG_ADDR;
344  else if (start && (msg1hot[EXTRA_WORDS -1])) next_addr <= STATUS_REG_ADDR;
345  else if (start) next_addr <= next_addr + 1;
346 
347  if (rst) next_mask <= first_mask;
348  else if (srst) next_mask <= first_mask;
349  else if (!need_to_send || start_last) next_mask <= first_mask;
350 // else if (start && (msg1hot[EXTRA_WORDS -1 :0])) next_mask <= STATUS_MASK;
351  else if (start && (msg1hot[EXTRA_WORDS -1])) next_mask <= STATUS_MASK;
352 
353  if (rst) rq_r <= 0;
354  else if (srst) rq_r <= 0;
355  else if (need_to_send && !rq_r[0]) rq_r <= 1;
356  else if (start) rq_r <= next_mask;
357  else if (|rq_r) rq_r <= rq_r >> 1;
358 
359  if (rst) msg_num <= 0;
360  else if (srst) msg_num <= 0;
361  else if (!need_to_send) msg_num <= 0;
362  else if (start) msg_num <= msg_num + 1;
363 
364  if (rst) msg1hot <= 1;
365  else if (srst) msg1hot <= 1;
366  else if (!need_to_send) msg1hot <= 1;
367 // else if (start) begin
368 // if (|msg1hot) msg1hot <= (msg1hot >> 1);
369 // else msg1hot <= 1 << (NUM_MSG-1);
370 // end
371  else if (start) if (|msg1hot) msg1hot <= msg1hot << 1;
372 
373  if (rst) shift_data <= 0;
374  else if (srst || !rq) shift_data <= 0;
375  else if (start) shift_data <= 1;
376  end
377 
378  always @ (posedge clk) begin
379 // if (!rq) data <= {next_addr, pre_mux[32 * msg_num +:32]};
380  if (!rq) data <= {pre_mux[32 * msg_num +:32], next_addr};
381  else if (start || shift_data) data <= data >> 8;
382  end
383  //http://www.edaboard.com/thread177879.html
384  function integer clogb2;
385  input [31:0] value;
386  integer i;
387  begin
388  clogb2 = 0;
389  for(i = 0; 2**i < value; i = i + 1)
390  clogb2 = i + 1;
391  end
392  endfunction
393 
394 
395 endmodule
396 
397 
10845msg1hotreg[NUM_MSG-1:0]
10795NUM_BYTES(PAYLOAD_BITS+21)>>3
10854msg_numreg[EXTRA_WORDS_LN2-1:0]
10825EXTRA_WORDS_LN2clogb2(EXTRA_WORDS+1
10802status_r0wire[PAYLOAD_BITS-1:0]
10827ALL_BITSSTATUS_BITS + 32 * EXTRA_WORDS
10838status_rreg[STATUS_BITS-1:0]
10843aligned_statuswire[ALIGNED_STATUS_WIDTH-1:0]
10803status_rreg[PAYLOAD_BITS-1:0]
10829NUM_BYTES(STATUS_BITS + 21) >> 3
10797ALIGNED_STATUS_BIT_2(ALIGNED_STATUS_WIDTH>2)?2:0
10831ALIGNED_STATUS_BIT_2(ALIGNED_STATUS_WIDTH > 2) ? 2 : 0
10832STATUS_MASK(1 << (NUM_BYTES) -1) - 1
status_generate_only_i status_generate_only[generate]
10856pre_muxwire[32*1<<EXTRA_WORDS_LN2-1:0]
10801status_r0rreg[PAYLOAD_BITS-1:0]
10810rq_rreg[NUM_BYTES-2:0]
10828NUM_MSGEXTRA_WORDS + ((PAYLOAD_BITS > 0)? 1 : 0
10796ALIGNED_STATUS_WIDTH((NUM_BYTES-2)<<3)+2
10781STATUS_BITS((PAYLOAD_BITS > 0) ? PAYLOAD_BITS: 1
10782ALL_BITSSTATUS_BITS + 32 * EXTRA_WORDS
10809aligned_statuswire[ALIGNED_STATUS_WIDTH-1:0]
10830ALIGNED_STATUS_WIDTH((NUM_BYTES - 2) << 3) + 2
10806datareg[NUM_BYTES-1<<3-1:0]
[ALL_BITS-1:0] 10777status
10826STATUS_BITS((PAYLOAD_BITS > 0) ? PAYLOAD_BITS: 1
10836status_r0rreg[STATUS_BITS-1:0]
status_generate_extra_i status_generate_extra[generate]
[ALL_BITS-1:0] 10821status
10837status_r0wire[STATUS_BITS-1:0]
[PAYLOAD_BITS-1:0] 10791status