source: trunk/modules/vci_spi/caba/source/src/vci_spi.cpp@ 575

Last change on this file since 575 was 575, checked in by bouyer, 13 years ago

Make sure MOSI data changes on SPI clock falling edge,
not one system clock cycle later. With a dividor of 0, this would
delay the MOSI change to the SPI clock rising edge.

File size: 23.1 KB
Line 
1/* -*- c++ -*-
2 *
3 * SOCLIB_LGPL_HEADER_BEGIN
4 *
5 * This file is part of SoCLib, GNU LGPLv2.1.
6 *
7 * SoCLib is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; version 2.1 of the License.
10 *
11 * SoCLib is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with SoCLib; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 *
21 * SOCLIB_LGPL_HEADER_END
22 *
23 * Copyright (c) UPMC, Lip6, SoC
24 * manuel.bouyer@lip6.fr october 2013
25 *
26 * Maintainers: bouyer
27 */
28
29#include <stdint.h>
30#include <iostream>
31#include <fcntl.h>
32#include "vci_spi.h"
33#include "vcispi.h"
34
35namespace soclib { namespace caba {
36
37#define tmpl(t) template<typename vci_param> t VciSpi<vci_param>
38
39using namespace soclib::caba;
40using namespace soclib::common;
41
42////////////////////////
43tmpl(void)::transition()
44{
45 if(p_resetn.read() == false)
46 {
47 r_initiator_fsm = M_IDLE;
48 r_target_fsm = T_IDLE;
49 r_spi_fsm = S_IDLE;
50 r_ss = 0;
51 r_divider = 0xffff;
52 r_ctrl_char_len = 0;
53 r_ctrl_ie = false;
54 r_ctrl_cpol = false;
55 r_ctrl_cpha = false;
56 r_ctrl_go_bsy = false;
57 r_spi_clk_counter = 0xffff;
58 r_spi_clk = 0;
59 r_spi_done = false;
60
61 r_irq = false;
62 r_read = false;
63
64 return;
65 }
66
67 //////////////////////////////////////////////////////////////////////////////
68 // The Target FSM controls the following registers:
69 // r_target_fsm, r_irq_enable, r_nblocks, r_buf adress, r_lba, r_go, r_read
70 //////////////////////////////////////////////////////////////////////////////
71
72 if (r_spi_done)
73 r_ctrl_go_bsy = false;
74
75 switch(r_target_fsm) {
76 ////////////
77 case T_IDLE:
78 {
79 if ( p_vci_target.cmdval.read() )
80 {
81 r_srcid = p_vci_target.srcid.read();
82 r_trdid = p_vci_target.trdid.read();
83 r_pktid = p_vci_target.pktid.read();
84 uint32_t wdata = p_vci_target.wdata.read();
85 sc_dt::sc_uint<vci_param::N> address = p_vci_target.address.read();
86
87 bool found = false;
88 std::list<soclib::common::Segment>::iterator seg;
89 for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ )
90 {
91 if ( seg->contains(address) ) found = true;
92 }
93
94
95 if (not found) {
96 if (p_vci_target.cmd.read() == vci_param::CMD_WRITE)
97 r_target_fsm = T_ERROR_WRITE;
98 else
99 r_target_fsm = T_ERROR_READ;
100 } else if (p_vci_target.cmd.read() != vci_param::CMD_READ &&
101 p_vci_target.cmd.read() != vci_param::CMD_WRITE) {
102 r_target_fsm = T_ERROR_READ;
103 } else {
104 bool write = (p_vci_target.cmd.read() == vci_param::CMD_WRITE) & !r_ctrl_go_bsy;
105 uint32_t cell = (uint32_t)((address & 0x3F)>>2);
106 switch(cell) {
107 case SPI_DATA_TXRX0:
108 r_rdata = r_txrx[0] & (uint64_t)0x00000000ffffffffULL;
109 if (write) {
110 r_txrx[0] =
111 (r_txrx[0] & (uint64_t)0xffffffff00000000ULL) |
112 ((uint64_t)wdata);
113 }
114 r_target_fsm = (p_vci_target.cmd.read() == vci_param::CMD_WRITE) ? T_RSP_WRITE : T_RSP_READ;
115 break;
116 case SPI_DATA_TXRX1:
117 r_rdata = r_txrx[0] >> 32;
118 if (write) {
119 r_txrx[0] =
120 (r_txrx[0] & (uint64_t)0x00000000ffffffffULL) |
121 ((uint64_t)wdata << 32);
122 }
123 r_target_fsm = (p_vci_target.cmd.read() == vci_param::CMD_WRITE) ? T_RSP_WRITE : T_RSP_READ;
124 break;
125 case SPI_DATA_TXRX2:
126 r_rdata = r_txrx[1] & (uint64_t)0x00000000ffffffffULL;
127 if (write) {
128 r_txrx[1] =
129 (r_txrx[1] & (uint64_t)0xffffffff00000000ULL) |
130 ((uint64_t)wdata);
131 }
132 r_target_fsm = (p_vci_target.cmd.read() == vci_param::CMD_WRITE) ? T_RSP_WRITE : T_RSP_READ;
133 break;
134 case SPI_DATA_TXRX3:
135 r_rdata = r_txrx[1] >> 32;
136 if (write) {
137 r_txrx[1] =
138 (r_txrx[1] & (uint64_t)0x00000000ffffffffULL) |
139 ((uint64_t)wdata << 32);
140 }
141 r_target_fsm = (p_vci_target.cmd.read() == vci_param::CMD_WRITE) ? T_RSP_WRITE : T_RSP_READ;
142 break;
143 case SPI_CTRL:
144 {
145 uint32_t data = 0;
146 if (r_ctrl_cpol.read())
147 data |= SPI_CTRL_CPOL;
148 if (r_ctrl_cpha.read())
149 data |= SPI_CTRL_CPHA;
150 if (r_ctrl_ie.read())
151 data |= SPI_CTRL_IE_EN;
152 if (r_ctrl_go_bsy.read())
153 data |= SPI_CTRL_GO_BSY;
154 data |= (uint32_t)r_ctrl_char_len.read();
155 r_rdata = data;
156 if (write) {
157 r_ctrl_cpol = ((wdata & SPI_CTRL_CPOL) != 0);
158 r_ctrl_cpha = ((wdata & SPI_CTRL_CPHA) != 0);
159 r_ctrl_ie = ((wdata & SPI_CTRL_IE_EN) != 0);
160 if (wdata & SPI_CTRL_GO_BSY)
161 r_ctrl_go_bsy = true;
162 r_ctrl_char_len = (wdata & SPI_CTRL_CHAR_LEN_MASK);
163#ifdef SOCLIB_MODULE_DEBUG
164 if ((wdata & SPI_CTRL_GO_BSY) != 0) {
165 std::cout << name() << " start xfer " << std::dec << (int)r_ctrl_char_len.read() << " data " << std::hex << r_txrx[1] << " " << r_txrx[0] << std::endl;
166 }
167#endif
168 } else {
169 r_irq = r_irq & r_ctrl_go_bsy;
170 }
171 r_target_fsm = (p_vci_target.cmd.read() == vci_param::CMD_WRITE) ? T_RSP_WRITE : T_RSP_READ;
172 break;
173 }
174 case SPI_DIVIDER:
175 r_rdata = r_divider.read();
176 if (write) {
177#ifdef SOCLIB_MODULE_DEBUG
178 std::cout << name() << " divider set to " << std::dec << wdata << std::endl;
179#endif
180 r_divider = wdata;
181 }
182 r_target_fsm = (p_vci_target.cmd.read() == vci_param::CMD_WRITE) ? T_RSP_WRITE : T_RSP_READ;
183 break;
184 case SPI_SS:
185 r_rdata = r_ss.read();
186 if (write) {
187 r_ss = wdata;
188 }
189 r_target_fsm = (p_vci_target.cmd.read() == vci_param::CMD_WRITE) ? T_RSP_WRITE : T_RSP_READ;
190 break;
191 default:
192 r_target_fsm = (p_vci_target.cmd.read() == vci_param::CMD_WRITE) ? T_ERROR_WRITE : T_ERROR_READ;
193 break;
194 }
195 }
196 }
197 break;
198 }
199 ////////////////////
200 case T_RSP_READ:
201 case T_RSP_WRITE:
202 case T_ERROR_READ:
203 case T_ERROR_WRITE:
204 if (p_vci_target.rspack.read() ) {
205 r_target_fsm = T_IDLE;
206 }
207 break;
208 } // end switch target fsm
209
210
211
212
213 //////////////////////////////////////////////////////////////////////////////
214 // the SPI FSM controls SPI signals
215 //////////////////////////////////////////////////////////////////////////////
216 if (r_ctrl_go_bsy == false)
217 r_spi_done = false;
218 switch (r_spi_fsm) {
219 case S_IDLE:
220 r_spi_clk_counter = r_divider.read();
221 r_spi_clk = 0;
222 r_spi_clk_previous = r_ctrl_cpha;
223 r_spi_clk_ignore = r_ctrl_cpha;
224 r_spi_bit_count = r_ctrl_char_len;
225 r_spi_out = (r_txrx[(r_ctrl_char_len -1)/ 64] >> ((r_ctrl_char_len - 1) % 64)) & (uint64_t)0x0000000000000001ULL;
226 if (r_ctrl_go_bsy.read() && !r_spi_done.read())
227 r_spi_fsm = S_XMIT;
228 break;
229 case S_XMIT:
230 {
231 bool s_clk_sample;
232 // on clock transition, sample input line, and shift data
233 s_clk_sample = r_spi_clk ^ r_ctrl_cpha;
234 if (!r_spi_clk_ignore) {
235 if (r_spi_clk_previous == 0 && s_clk_sample == 1) {
236 // low to high transition: shift and sample
237 r_txrx[1] = (r_txrx[1] << 1) | (r_txrx[0] >> 63);
238 r_txrx[0] = (r_txrx[0] << 1) | p_spi_miso;
239 r_spi_bit_count = r_spi_bit_count - 1;
240 } else if (r_spi_clk_previous == 1 && s_clk_sample == 0) {
241 // high to low transition: change output, or stop
242 if (r_spi_bit_count == 0) {
243 r_spi_fsm = S_IDLE;
244 r_irq = r_ctrl_ie;
245 r_spi_done = true;
246#ifdef SOCLIB_MODULE_DEBUG0
247 std::cout << name() << " end xfer " << std::dec << (int)r_ctrl_char_len.read() << " data " << std::hex << r_txrx[1] << " " << r_txrx[0] << std::endl;
248#endif
249 } else {
250 r_spi_out = (r_txrx[(r_ctrl_char_len -1)/ 64] >> ((r_ctrl_char_len - 1) % 64)) & (uint64_t)0x0000000000000001ULL;
251 }
252 }
253 }
254 r_spi_clk_previous = s_clk_sample;
255 // generate the SPI clock
256 if (r_spi_clk_counter.read() == 0) {
257 r_spi_clk_counter = r_divider.read();
258 r_spi_clk = !r_spi_clk.read();
259 r_spi_clk_ignore = false;
260 } else {
261 r_spi_clk_counter = r_spi_clk_counter.read() - 1;
262 }
263 break;
264 }
265 }
266 //////////////////////////////////////////////////////////////////////////////
267 // The initiator FSM executes a loop, transfering one block per iteration.
268 // Each block is split in bursts, and the number of bursts depends
269 // on the memory buffer alignment on a burst boundary:
270 // - If buffer aligned, all burst have the same length (m_words_per burst)
271 // and the number of bursts is (m_bursts_per_block).
272 // - If buffer not aligned, the number of bursts is (m_bursts_per_block + 1)
273 // and first and last burst are shorter, because all words in a burst
274 // must be contained in a single cache line.
275 // first burst => nwords = m_words_per_burst - offset
276 // last burst => nwords = offset
277 // other burst => nwords = m_words_per_burst
278 //////////////////////////////////////////////////////////////////////////////
279
280 switch( r_initiator_fsm.read() ) {
281 ////////////
282 case M_IDLE: // check buffer alignment to compute the number of bursts
283 {
284 if ( false ) // XXX
285 {
286 r_index = 0;
287 r_block_count = 0;
288 r_burst_count = 0;
289 r_words_count = 0;
290
291 // compute r_burst_offset (zero when buffer aligned)
292 r_burst_offset = (uint32_t)((r_buf_address.read()>>2) % m_words_per_burst);
293
294 // start tranfer
295 if ( r_read.read() ) r_initiator_fsm = M_READ_BLOCK;
296 else r_initiator_fsm = M_WRITE_BURST;
297 }
298 break;
299 }
300 //////////////////
301 case M_READ_BLOCK: // read one block from disk after waiting m_latency cycles
302 {
303 r_burst_count = 0;
304 r_words_count = 0;
305 r_initiator_fsm = M_READ_BURST;
306 break;
307 }
308 //////////////////
309 case M_READ_BURST: // Compute the number of words and the number of flits in the burst
310 // The number of flits can be smaller than the number of words
311 // in case of 8 bytes flits...
312 {
313 uint32_t nwords;
314 uint32_t offset = r_burst_offset.read();
315
316 if ( offset ) // buffer not aligned
317 {
318 if ( r_burst_count.read() == 0 ) nwords = m_words_per_burst - offset;
319 else if ( r_burst_count.read() == m_bursts_per_block ) nwords = offset;
320 else nwords = m_words_per_burst;
321 }
322 else // buffer aligned
323 {
324 nwords = m_words_per_burst;
325 }
326
327 r_burst_nwords = nwords;
328 r_initiator_fsm = M_READ_CMD;
329 break;
330 }
331 ////////////////
332 case M_READ_CMD: // Send a multi-flits VCI WRITE command
333 {
334 if ( p_vci_initiator.cmdack.read() )
335 {
336 uint32_t nwords = r_burst_nwords.read() - r_words_count.read();
337
338 if ( vci_param::B == 4 ) // one word per flit
339 {
340 if ( nwords <= 1 ) // last flit
341 {
342 r_initiator_fsm = M_READ_RSP;
343 r_words_count = 0;
344 }
345 else // not the last flit
346 {
347 r_words_count = r_words_count.read() + 1;
348 }
349
350 // compute next word address and next local buffer index
351 r_buf_address = r_buf_address.read() + 4;
352 r_index = r_index.read() + 1;
353 }
354 else // 2 words per flit
355 {
356 if ( nwords <= 2 ) // last flit
357 {
358 r_initiator_fsm = M_READ_RSP;
359 r_words_count = 0;
360 }
361 else // not the last flit
362 {
363 r_words_count = r_words_count.read() + 2;
364 }
365
366 // compute next word address and next local buffer index
367 if ( nwords == 1 )
368 {
369 r_buf_address = r_buf_address.read() + 4;
370 r_index = r_index.read() + 1;
371 }
372 else
373 {
374 r_buf_address = r_buf_address.read() + 8;
375 r_index = r_index.read() + 2;
376 }
377 }
378 }
379 break;
380 }
381 ////////////////
382 case M_READ_RSP: // Wait a single flit VCI WRITE response
383 {
384 if ( p_vci_initiator.rspval.read() )
385 {
386 bool aligned = (r_burst_offset.read() == 0);
387
388 if ( (p_vci_initiator.rerror.read()&0x1) != 0 )
389 {
390 r_initiator_fsm = M_READ_ERROR;
391#ifdef SOCLIB_MODULE_DEBUG
392 std::cout << "vci_bd M_READ_ERROR" << std::endl;
393#endif
394 }
395 else if ( (not aligned and (r_burst_count.read() == m_bursts_per_block)) or
396 (aligned and (r_burst_count.read() == (m_bursts_per_block-1))) )
397 {
398 if ( r_block_count.read() == (r_nblocks.read()-1) ) // last burst of last block
399 {
400 r_initiator_fsm = M_READ_SUCCESS;
401#ifdef SOCLIB_MODULE_DEBUG
402 std::cout << "vci_bd M_READ_SUCCESS" << std::endl;
403#endif
404 }
405 else // last burst not last block
406 {
407 r_index = 0;
408 r_burst_count = 0;
409 r_block_count = r_block_count.read() + 1;
410 r_initiator_fsm = M_READ_BLOCK;
411 }
412 }
413 else // not the last burst
414 {
415 r_burst_count = r_burst_count.read() + 1;
416 r_initiator_fsm = M_READ_BURST;
417 }
418 }
419 break;
420 }
421 ///////////////////
422 case M_READ_SUCCESS:
423 case M_READ_ERROR:
424 {
425 if( !r_go ) r_initiator_fsm = M_IDLE;
426 break;
427 }
428 ///////////////////
429 case M_WRITE_BURST: // Compute the number of words in the burst
430 {
431 uint32_t nwords;
432 uint32_t offset = r_burst_offset.read();
433
434 if ( offset ) // buffer not aligned
435 {
436 if ( r_burst_count.read() == 0 ) nwords = m_words_per_burst - offset;
437 else if ( r_burst_count.read() == m_bursts_per_block ) nwords = offset;
438 else nwords = m_words_per_burst;
439 }
440 else // buffer aligned
441 {
442 nwords = m_words_per_burst;
443 }
444
445 r_burst_nwords = nwords;
446 r_initiator_fsm = M_WRITE_CMD;
447 break;
448 }
449 /////////////////
450 case M_WRITE_CMD: // This is actually a single flit VCI READ command
451 {
452 if ( p_vci_initiator.cmdack.read() ) r_initiator_fsm = M_WRITE_RSP;
453 break;
454 }
455 /////////////////
456 case M_WRITE_RSP: // This is actually a multi-words VCI READ response
457 {
458 if ( p_vci_initiator.rspval.read() )
459 {
460 bool aligned = (r_burst_offset.read() == 0);
461
462 if ( (vci_param::B == 8) and (r_burst_nwords.read() > 1) )
463 {
464 r_local_buffer[r_index.read()] = (uint32_t)p_vci_initiator.rdata.read();
465 r_local_buffer[r_index.read()+1] = (uint32_t)(p_vci_initiator.rdata.read()>>32);
466 r_index = r_index.read() + 2;
467 }
468 else
469 {
470 r_local_buffer[r_index.read()] = (uint32_t)p_vci_initiator.rdata.read();
471 r_index = r_index.read() + 1;
472 }
473
474 if ( p_vci_initiator.reop.read() ) // last flit of the burst
475 {
476 r_words_count = 0;
477 r_buf_address = r_buf_address.read() + (r_burst_nwords.read()<<2);
478
479 if( (p_vci_initiator.rerror.read()&0x1) != 0 )
480 {
481 r_initiator_fsm = M_WRITE_ERROR;
482#ifdef SOCLIB_MODULE_DEBUG
483 std::cout << "vci_bd M_WRITE_ERROR" << std::endl;
484#endif
485 }
486 else if ( (not aligned and (r_burst_count.read() == m_bursts_per_block)) or
487 (aligned and (r_burst_count.read() == (m_bursts_per_block-1))) ) // last burst
488 {
489 r_initiator_fsm = M_WRITE_BLOCK;
490 }
491 else // not the last burst
492 {
493 r_burst_count = r_burst_count.read() + 1;
494 r_initiator_fsm = M_WRITE_BURST;
495 }
496 }
497 else
498 {
499 r_words_count = r_words_count.read() + 1;
500 }
501 }
502 break;
503 }
504 ///////////////////
505 case M_WRITE_BLOCK: // write a block to disk after waiting m_latency cycles
506 {
507 if ( r_block_count.read() == r_nblocks.read() - 1 )
508 {
509 r_initiator_fsm = M_WRITE_SUCCESS;
510#ifdef SOCLIB_MODULE_DEBUG
511 std::cout << "vci_bd M_WRITE_SUCCESS" << std::endl;
512#endif
513 }
514 else
515 {
516 r_burst_count = 0;
517 r_index = 0;
518 r_block_count = r_block_count.read() + 1;
519 r_initiator_fsm = M_WRITE_BURST;
520 }
521 break;
522 }
523 /////////////////////
524 case M_WRITE_SUCCESS:
525 case M_WRITE_ERROR:
526 {
527 r_initiator_fsm = M_IDLE;
528 break;
529 }
530 } // end switch r_initiator_fsm
531} // end transition
532
533//////////////////////
534tmpl(void)::genMoore()
535{
536 // p_vci_target port
537 p_vci_target.rsrcid = (sc_dt::sc_uint<vci_param::S>)r_srcid.read();
538 p_vci_target.rtrdid = (sc_dt::sc_uint<vci_param::T>)r_trdid.read();
539 p_vci_target.rpktid = (sc_dt::sc_uint<vci_param::P>)r_pktid.read();
540 p_vci_target.reop = true;
541
542 switch(r_target_fsm) {
543 case T_IDLE:
544 p_vci_target.cmdack = true;
545 p_vci_target.rspval = false;
546 p_vci_target.rdata = 0;
547 break;
548 case T_RSP_READ:
549 p_vci_target.cmdack = false;
550 p_vci_target.rspval = true;
551 p_vci_target.rdata = r_rdata;
552 p_vci_target.rerror = VCI_READ_OK;
553 break;
554 case T_RSP_WRITE:
555 p_vci_target.cmdack = false;
556 p_vci_target.rspval = true;
557 p_vci_target.rdata = 0;
558 p_vci_target.rerror = VCI_WRITE_OK;
559 break;
560 case T_ERROR_READ:
561 p_vci_target.cmdack = false;
562 p_vci_target.rspval = true;
563 p_vci_target.rdata = 0;
564 p_vci_target.rerror = VCI_READ_ERROR;
565 break;
566 case T_ERROR_WRITE:
567 p_vci_target.cmdack = false;
568 p_vci_target.rspval = true;
569 p_vci_target.rdata = 0;
570 p_vci_target.rerror = VCI_WRITE_ERROR;
571 break;
572 } // end switch target fsm
573
574 // p_vci_initiator port
575 p_vci_initiator.srcid = (sc_dt::sc_uint<vci_param::S>)m_srcid;
576 p_vci_initiator.trdid = 0;
577 p_vci_initiator.contig = true;
578 p_vci_initiator.cons = false;
579 p_vci_initiator.wrap = false;
580 p_vci_initiator.cfixed = false;
581 p_vci_initiator.clen = 0;
582
583 switch (r_initiator_fsm) {
584 case M_WRITE_CMD: // It is actually a single flit VCI read command
585 p_vci_initiator.rspack = false;
586 p_vci_initiator.cmdval = true;
587 p_vci_initiator.address = (sc_dt::sc_uint<vci_param::N>)r_buf_address.read();
588 p_vci_initiator.cmd = vci_param::CMD_READ;
589 p_vci_initiator.pktid = TYPE_READ_DATA_UNC;
590 p_vci_initiator.wdata = 0;
591 p_vci_initiator.be = 0;
592 p_vci_initiator.plen = (sc_dt::sc_uint<vci_param::K>)(r_burst_nwords.read()<<2);
593 p_vci_initiator.eop = true;
594 break;
595 case M_READ_CMD: // It is actually a multi-words VCI WRITE command
596 p_vci_initiator.rspack = false;
597 p_vci_initiator.cmdval = true;
598 p_vci_initiator.address = (sc_dt::sc_uint<vci_param::N>)r_buf_address.read();
599 p_vci_initiator.cmd = vci_param::CMD_WRITE;
600 p_vci_initiator.pktid = TYPE_WRITE;
601 p_vci_initiator.plen = (sc_dt::sc_uint<vci_param::K>)(r_burst_nwords.read()<<2);
602 if ( (vci_param::B == 8) and ((r_burst_nwords.read() - r_words_count.read()) > 1) )
603 {
604 p_vci_initiator.wdata = ((uint64_t)r_local_buffer[r_index.read() ]) +
605 (((uint64_t)r_local_buffer[r_index.read()+1]) << 32);
606 p_vci_initiator.be = 0xFF;
607 p_vci_initiator.eop = ( (r_burst_nwords.read() - r_words_count.read()) <= 2 );
608 }
609 else
610 {
611 p_vci_initiator.wdata = r_local_buffer[r_index.read()];
612 p_vci_initiator.be = 0xF;
613 p_vci_initiator.eop = ( r_words_count.read() == (r_burst_nwords.read() - 1) );
614 }
615 break;
616 case M_READ_RSP:
617 case M_WRITE_RSP:
618 p_vci_initiator.rspack = true;
619 p_vci_initiator.cmdval = false;
620 break;
621 default:
622 p_vci_initiator.rspack = false;
623 p_vci_initiator.cmdval = false;
624 break;
625 }
626
627 // SPI signals
628 p_spi_ss = ((r_ss & 0x1) == 0);
629 switch(r_spi_fsm) {
630 case S_IDLE:
631 p_spi_mosi = 0;
632 p_spi_clk = 0;
633 break;
634 case S_XMIT:
635 {
636 bool s_clk_sample = r_spi_clk ^ r_ctrl_cpha;
637 p_spi_clk = r_spi_clk ^ r_ctrl_cpol;
638 if (s_clk_sample == 0) {
639 // clock low: get data directly from shift register
640 // as r_spi_out may be delayed by one clock cycle
641 p_spi_mosi = (r_txrx[(r_ctrl_char_len -1)/ 64] >> ((r_ctrl_char_len - 1) % 64)) & (uint64_t)0x0000000000000001ULL;
642 } else {
643 // clock high: get data from saved value, as the shift register
644 // may have changed
645 p_spi_mosi = r_spi_out;
646 }
647 break;
648 }
649 }
650
651 // IRQ signal
652 p_irq = r_irq;
653} // end GenMoore()
654
655//////////////////////////////////////////////////////////////////////////////
656tmpl(/**/)::VciSpi( sc_core::sc_module_name name,
657 const soclib::common::MappingTable &mt,
658 const soclib::common::IntTab &srcid,
659 const soclib::common::IntTab &tgtid,
660 const uint32_t burst_size)
661
662: caba::BaseModule(name),
663 m_seglist(mt.getSegmentList(tgtid)),
664 m_srcid(mt.indexForId(srcid)),
665 m_words_per_block(512/4),
666 m_words_per_burst(burst_size/4),
667 m_bursts_per_block(512/burst_size),
668 p_clk("p_clk"),
669 p_resetn("p_resetn"),
670 p_vci_initiator("p_vci_initiator"),
671 p_vci_target("p_vci_target"),
672 p_irq("p_irq"),
673 p_spi_ss("p_spi_ss"),
674 p_spi_clk("p_spi_clk"),
675 p_spi_mosi("p_spi_mosi"),
676 p_spi_miso("p_spi_miso")
677{
678 std::cout << " - Building VciSpi " << name << std::endl;
679
680 SC_METHOD(transition);
681 dont_initialize();
682 sensitive << p_clk.pos();
683
684 SC_METHOD(genMoore);
685 dont_initialize();
686 sensitive << p_clk.neg();
687
688 size_t nbsegs = 0;
689 std::list<soclib::common::Segment>::iterator seg;
690 for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ )
691 {
692 nbsegs++;
693
694 if ( (seg->baseAddress() & 0x0000003F) != 0 )
695 {
696 std::cout << "Error in component VciSpi : " << name
697 << "The base address of segment " << seg->name()
698 << " must be multiple of 64 bytes" << std::endl;
699 exit(1);
700 }
701 if ( seg->size() < 64 )
702 {
703 std::cout << "Error in component VciSpi : " << name
704 << "The size of segment " << seg->name()
705 << " cannot be smaller than 64 bytes" << std::endl;
706 exit(1);
707 }
708 std::cout << " => segment " << seg->name()
709 << " / base = " << std::hex << seg->baseAddress()
710 << " / size = " << seg->size() << std::endl;
711 }
712
713 if( nbsegs == 0 )
714 {
715 std::cout << "Error in component VciSpi : " << name
716 << " No segment allocated" << std::endl;
717 exit(1);
718 }
719
720 if( (burst_size != 8 ) &&
721 (burst_size != 16) &&
722 (burst_size != 32) &&
723 (burst_size != 64) )
724 {
725 std::cout << "Error in component VciSpi : " << name
726 << " The burst size must be 8, 16, 32 or 64 bytes" << std::endl;
727 exit(1);
728 }
729
730 if ( (vci_param::B != 4) and (vci_param::B != 8) )
731 {
732 std::cout << "Error in component VciSpi : " << name
733 << " The VCI data fields must have 32 bits or 64 bits" << std::endl;
734 exit(1);
735 }
736
737 r_local_buffer = new uint32_t[m_words_per_block];
738
739} // end constructor
740
741tmpl(/**/)::~VciSpi()
742{
743 delete [] r_local_buffer;
744}
745
746
747//////////////////////////
748tmpl(void)::print_trace()
749{
750 const char* initiator_str[] =
751 {
752 "M_IDLE",
753
754 "M_READ_BLOCK",
755 "M_READ_BURST",
756 "M_READ_CMD",
757 "M_READ_RSP",
758 "M_READ_SUCCESS",
759 "M_READ_ERROR",
760
761 "M_WRITE_BURST",
762 "M_WRITE_CMD",
763 "M_WRITE_RSP",
764 "M_WRITE_BLOCK",
765 "M_WRITE_SUCCESS",
766 "M_WRITE_ERROR",
767 };
768 const char* target_str[] =
769 {
770 "T_IDLE",
771 "T_RSP_READ",
772 "T_RSP_WRITE",
773 "T_ERROR_READ",
774 "T_ERROR_WRITE",
775 };
776 const char* spi_str[] =
777 {
778 "S_IDLE",
779 "S_XMIT",
780 };
781
782 std::cout << name() << " _TGT : " << target_str[r_target_fsm.read()]
783 << std::endl;
784 std::cout << name() << " _SPI : " << spi_str[r_spi_fsm.read()]
785 << " clk_counter " << r_spi_clk_counter.read()
786 << " r_spi_bit_count " << r_spi_bit_count.read()
787 << " r_ctrl_go_bsy " << (int)r_ctrl_go_bsy.read() << std::endl;
788 std::cout << name() << " _SPI : "
789 << " r_spi_clk " << r_spi_clk.read()
790 << " cpol " << r_ctrl_cpol.read()
791 << " cpha " << r_ctrl_cpha.read()
792 << " r_spi_clk_ignore " << r_spi_clk_ignore.read()
793 << " r_txrx 0x" << std::hex
794 << r_txrx[1].read() << " " << r_txrx[0].read()
795 << std::endl;
796 std::cout << name() << " _INI : " << initiator_str[r_initiator_fsm.read()]
797 << " buf = " << std::hex << r_buf_address.read()
798 << " block = " << std::dec << r_block_count.read()
799 << " burst = " << r_burst_count.read()
800 << " word = " << r_words_count.read() <<std::endl;
801}
802
803}} // end namespace
804
805// Local Variables:
806// tab-width: 4
807// c-basic-offset: 4
808// c-file-offsets:((innamespace . 0)(inline-open . 0))
809// indent-tabs-mode: nil
810// End:
811
812// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
813
Note: See TracBrowser for help on using the repository browser.