diff options
229 files changed, 11805 insertions, 10124 deletions
diff --git a/firmware/zpu/apps/txrx_uhd.c b/firmware/zpu/apps/txrx_uhd.c index 975ec58e2..5bf8ca725 100644 --- a/firmware/zpu/apps/txrx_uhd.c +++ b/firmware/zpu/apps/txrx_uhd.c @@ -46,27 +46,47 @@ //virtual registers in the firmware to store persistent values static uint32_t fw_regs[8]; -extern uint16_t dsp0_dst_port, err0_dst_port, dsp1_dst_port; - static void handle_udp_data_packet( struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len ){ - size_t which; - switch(dst.port){ - case USRP2_UDP_DSP0_PORT: + //handle ICMP destination unreachable + if (payload == NULL) switch(src.port){ + case USRP2_UDP_RX_DSP0_PORT: + //the end continuous streaming command + sr_rx_ctrl0->cmd = 1 << 31; //no samples now + sr_rx_ctrl0->time_secs = 0; + sr_rx_ctrl0->time_ticks = 0; //latch the command + break; + + case USRP2_UDP_RX_DSP1_PORT: + //the end continuous streaming command + sr_rx_ctrl1->cmd = 1 << 31; //no samples now + sr_rx_ctrl1->time_secs = 0; + sr_rx_ctrl1->time_ticks = 0; //latch the command + break; + + case USRP2_UDP_TX_DSP0_PORT: + //end async update packets per second + sr_tx_ctrl->cyc_per_up = 0; + break; + + default: return; + } + + //handle an incoming UDP packet + size_t which = 0; + if (payload != 0) switch(dst.port){ + case USRP2_UDP_RX_DSP0_PORT: which = 0; - dsp0_dst_port = src.port; break; - case USRP2_UDP_DSP1_PORT: + case USRP2_UDP_RX_DSP1_PORT: which = 2; - dsp1_dst_port = src.port; break; - case USRP2_UDP_ERR0_PORT: + case USRP2_UDP_TX_DSP0_PORT: which = 1; - err0_dst_port = src.port; break; default: return; @@ -291,7 +311,10 @@ main(void) #endif printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM); printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM); - + + //init readback for firmware minor version number + fw_regs[U2_FW_REG_VER_MINOR] = USRP2_FW_VER_MINOR; + #ifdef BOOTLOADER //load the production FPGA image or firmware if appropriate do_the_bootload_thing(); @@ -305,14 +328,14 @@ main(void) //1) register the addresses into the network stack register_addrs(ethernet_mac_addr(), get_ip_addr()); - pkt_ctrl_program_inspector(get_ip_addr(), USRP2_UDP_DSP0_PORT); + pkt_ctrl_program_inspector(get_ip_addr(), USRP2_UDP_TX_DSP0_PORT); //2) register callbacks for udp ports we service init_udp_listeners(); register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet); - register_udp_listener(USRP2_UDP_DSP0_PORT, handle_udp_data_packet); - register_udp_listener(USRP2_UDP_ERR0_PORT, handle_udp_data_packet); - register_udp_listener(USRP2_UDP_DSP1_PORT, handle_udp_data_packet); + register_udp_listener(USRP2_UDP_RX_DSP0_PORT, handle_udp_data_packet); + register_udp_listener(USRP2_UDP_RX_DSP1_PORT, handle_udp_data_packet); + register_udp_listener(USRP2_UDP_TX_DSP0_PORT, handle_udp_data_packet); #ifdef USRP2P register_udp_listener(USRP2_UDP_UPDATE_PORT, handle_udp_fw_update_packet); #endif diff --git a/firmware/zpu/lib/net_common.c b/firmware/zpu/lib/net_common.c index 2e3257b35..9a3f8c5a5 100644 --- a/firmware/zpu/lib/net_common.c +++ b/firmware/zpu/lib/net_common.c @@ -44,9 +44,6 @@ static const size_t out_buff_size = 2048; static const eth_mac_addr_t BCAST_MAC_ADDR = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; #define MAX_UDP_LISTENERS 6 -//used in the top level application... -uint16_t dsp0_dst_port, err0_dst_port, dsp1_dst_port; - /*********************************************************************** * 16-bit one's complement sum **********************************************************************/ @@ -312,25 +309,13 @@ handle_icmp_packet(struct ip_addr src, struct ip_addr dst, struct udp_hdr *udp = (struct udp_hdr *)(((char *)ip) + IP_HLEN); if (IPH_PROTO(ip) != IP_PROTO_UDP) break; - if (udp->dest == dsp0_dst_port){ - //the end continuous streaming command - sr_rx_ctrl0->cmd = 1 << 31; //no samples now - sr_rx_ctrl0->time_secs = 0; - sr_rx_ctrl0->time_ticks = 0; //latch the command - } - else if (udp->dest == dsp1_dst_port){ - //the end continuous streaming command - sr_rx_ctrl1->cmd = 1 << 31; //no samples now - sr_rx_ctrl1->time_secs = 0; - sr_rx_ctrl1->time_ticks = 0; //latch the command - } - else if (udp->dest == err0_dst_port){ - //end async update packets per second - sr_tx_ctrl->cyc_per_up = 0; + struct listener_entry *lx = find_listener_by_port(udp->src); + if (lx){ + struct socket_address src = make_socket_address(ip->src, udp->src); + struct socket_address dst = make_socket_address(ip->dest, udp->dest); + lx->rcvr(src, dst, NULL, 0); } - //struct udp_hdr *udp = (struct udp_hdr *)((char *)icmp + 28); - //printf("icmp port unr %d\n", udp->dest); putchar('i'); } else { diff --git a/fpga/usrp2/coregen/Makefile.srcs b/fpga/usrp2/coregen/Makefile.srcs index a3a5d826d..5b2bc665a 100644 --- a/fpga/usrp2/coregen/Makefile.srcs +++ b/fpga/usrp2/coregen/Makefile.srcs @@ -24,4 +24,6 @@ fifo_xlnx_512x36_2clk_18to36.v \ fifo_xlnx_512x36_2clk_18to36.xco \ fifo_xlnx_512x36_2clk_prog_full.v \ fifo_xlnx_512x36_2clk_prog_full.xco \ +fifo_xlnx_1Kx18_2clk.v \ +fifo_xlnx_1Kx18_2clk.xco \ )) diff --git a/fpga/usrp2/coregen/coregen.cgp b/fpga/usrp2/coregen/coregen.cgp index dd85a7f50..01d31bf5b 100644 --- a/fpga/usrp2/coregen/coregen.cgp +++ b/fpga/usrp2/coregen/coregen.cgp @@ -1,5 +1,4 @@ -# Date: Fri Oct 15 07:50:19 2010 - +# Date: Fri Jun 10 23:12:37 2011 SET addpads = false SET asysymbol = false SET busformat = BusFormatAngleBracketNotRipped @@ -19,4 +18,3 @@ SET verilogsim = true SET vhdlsim = false SET workingdirectory = /tmp/ -# CRC: 983b9b45 diff --git a/fpga/usrp2/coregen/fifo_generator_ug175.pdf b/fpga/usrp2/coregen/fifo_generator_ug175.pdf Binary files differindex 5fba6029c..2c3e3c200 100644 --- a/fpga/usrp2/coregen/fifo_generator_ug175.pdf +++ b/fpga/usrp2/coregen/fifo_generator_ug175.pdf diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.ngc b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.ngc new file mode 100644 index 000000000..dc9519357 --- /dev/null +++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.ngc @@ -0,0 +1,3 @@ +XILINX-XDB 0.1 STUB 0.1 ASCII +XILINX-XDM V1.4e +$4464g<,[o}e~g`n;"2*413&;$>"9 > %02?*rjx&Uhk"hffn]{hk~X9Br:4R<llj,mcj7<8<1;<=>?4193456789:;<=>?0123456789:;<=>?0123456789:;<=>?0123456789:;<=>?0127?5238;1;4<5>3:3-445<990BB][[:@FGVD:>294:?6??:HLSQQ<FLMXI044?>0d855<NFY__6}|`g^gntqX|axne26:1<12>772@D[YY4rne\ahvsqV~c~h}g_`qpawr;13:5>;5>0;KMTPR=x{elShctx]wlwct`Vdnklzj<883:4c<990BB][[:qplcZ`rdeUdk|h=;94;4238:1EC^ZT;rqkbYa}efTxe|jsi]bwvcu|531<3<:;029MKVR\3zycjQiumn\pmtb{aUeijo{e=;94;7f38;1CXZ_UU8geqgXkfex1??:1<2`>762F__\XZ5re]geqgXkfex1??:1<2`>762F__\XZ5ws]geqgXkfex1??:1<26>712@D[YY4KI@>21?699;1::7GAPTV9@LD;9<0;2<=4178LQQVR\3NDM1?::1<27>712F__\XZ5DN@?50<76880=54FNQWW>aoi48=1<3?;;0:9KPRW]]0ocxz31683:4=5<28;<=<42932?7<NFY__6IG_A=394;763;0BB][[:EKSF97=87;97?4@UURVP?BHXH6:6=0>2:09KPRW]]0OC]L31;2=0>5799n0?~<?01dd000*=81?86;;543821=18J:97;<=;7;7?3?>>=1=5L?=;7A7?3EDK;1=I?58F594BC@631804=:481236>>5923?74>?939:21=>>?3?7L<NA59BE7G?3HNO^L2?>99B@ATF48437LJKR@>1:==FLMXJ0>07;@FGVD:3611JHI\N<4<;?DBCZH6=255NDEPB828?3HNO^L27>`9B@ATF400;255NDEPB8<8?3HNO^O2?>99B@ATE48437LJKRC>1:==FLMXI0>07;@FGVG:3611JHI\M<4<;?DBCZK6=255NDEPA828?3HNO^O27>`9B@ATE400;255NDEPA8<8>3HYRBNQ]EF68FDGF;2H^>55MUR]JJCI63J>0OL6N2:AF57=D@LI@SAGLEOQF[Q_WM;1HE95LLJC7?FJLJ:1H@_74CNONMQRBL8>0OB\J_FGMAWGSAFDTECH@7:AQADRBL81O86J:8108@L0<L@K7<394DHC?55803MCJ0<?17:FJE9756>1OEL2>3?58@LG;9=427IGN<0794;1<L@K7=809;EKB84813MCJ0?09;EKB86813MCJ0909;EKB80813MCJ0;09;EKB82813MCJ0509;EKB8<813MCI0=08;EKA8469?2NBN1?>>69GMG:6:7=0HDL312<4?AOE48>556JFB=36>5803MCI0<;16:FJF979>2NBN1<16:FJF959>2NBN1:16:FJF939>2NBN1816:FJF919>2NBN1616:FJF9?9?2NB\L2?>89GMUG;93:5;6JFP@>2:2=CAYH7<374DHRA84<76>1OE]L31?48@JG;87=0HBO311<4?AIF48;5;6J@A=31:2=CGH6:?394DNC?518>3MEJ0<;50?58@JG;9<4=7IAN<0<5?AIF4;4=7IAN<2<5?AIF4=4=7IAN<4<5?AIF4?4=7IAN<6<5?AIF414=7IAN<8<5?AIE494<7IAM<02=3>BHJ5;:2:5KOC>26;1<LFH7=>08;EMA842912NDN1?::1<4?AIE48?5:6J@B=3=2>BHJ585:6J@B=1=2>BHJ5>5:6J@B=7=2>BHJ5<5:6J@B=5=2>BHJ525:6J@B=;=3>BHXH6;245KOQC?5?69?2ND\L2>>69GKUD;8730HB^M<083:2=CGYH7=3?4E59FE1633LKH<>5JN@18AKD53O297KJ<;GF@0>@CKL>0JIM_3:DGT1=ALYO?7KH8F49Eeiub92M87J@K1:K1?L653@;97D<=;H1;?LHN\YU;<55FNHVS[57?3@DBX]Q?299JJLRWW9937D@FTQ]30==NF@^[S=;7;HLJPUY7>11BBDZ__15:?LHN\Z^JXH94IOKW[5603@DBXR>>7:KMMQY7:>1BBDZP0258MKOSW9><7D@FT^263>OIA]U;::5FNHV\421<AGC_S=68;HLJPZ6>?2CEEYQ?A69JJLRX8K=0ECG[_1A4?LHN\V:O;6GAIU]3A2=NF@^T<K94IOKW[4603@DBXR?>7:KMMQY6:>1BBDZP1258MKOSW8><7D@FT^363>OIA]U:::5FNHV\521<AGC_S<68;HLJPZ7>?2CEEYQ>A69JJLRX9K=0ECG[_0A4?LHN\V;O;6GAIU]2A2=NF@^T=K94IOKW[7603@DBXR<>7:KMMQY5:>1BBDZP2258MKOSW;><7D@FT^063>OIA]U9::5FNHV\621<AGC_S?68;HLJPZ4>?2CEEYQ=A69JJLRX:K=0ECG[_3A4?LHN\V8O;6GAIU]1A2=NF@^T>K94IOKW[6603@DBXR=>7:KMMQY4:>1BBDZP3258MKOSW:><7D@FT^163>OIA]U8::5FNHV\721<AGC_S>68;HLJPZ5>?2CEEYQ<A69JJLRX;K=0ECG[_2A4?LHN\V9O;6GAIU]0A2=NF@^T?K84IOKW[D0<AGC_SO=4IOT0?LIE:2FB>6B@6:NLEACC?2FDKDMNL59OQQ733E__>;5CUU0\@1=K]]9=7A[[3^F5?ISS;VF?7A[[479OQQ2XL?1GYY:PL49NWBII=2G^TNWl;LcikwPbzzcdbn5BiomqR`ttafd97C?<;O330>H68<>0B<>94:L2422<F8:386@>0818J4733G;:<95A1037?K76:=1E=<=;;O3201=I98??7C?>659M54133G;:495A10;0?K75<2D:>=:4N0020>H6:;>0B<<<4:L2612<F882?6@>359M56633G;8=95A1207?K74;=1E=>:;;O3011=I9:<?7C?<759M56>33G;85>5A1568J425<2D:8>:4N0670>H6<<>0B<:94:L2022<F8>386@>4818J4333G;><95A1437?K72::1E=;=4N050?K7?;2D:5?5A229M655<F;;87C<=3:L176=I:<90B?9<;O137>H49:1E?>=4N277?K529:1E?;=4N250?K5?<2D84<=4N2;1?K243G>;?6@;139M27=I?;1E4>5A8518J=343G2<?6@7939M=6=I19l0BOQMURRJJZVUGYY<7CK[WNPH0>HHFL;0C?5@K09S0>VFZ]k0\D@PBTQJ@]d<X@DTNX]AALG0?UTB92[n7_OBB04\W4>X[82:7^?<;RKN[FIKD@YBCCQLHDAH2>UH][IN;6]]V@N\E2=TZ_KGSO:4SRPB0>UTZK>0XT^J339V4*aun'xm#jmw.bnh|*Kg{UyhR~ats]dgZ~hz9:;<R\jstnw564<]9%l~k }f.e`|+ekcq%Ftb|Pre]sjqtXojUsc>?00]Qavsk|8997X> gsd-vc)`kq$h`fv Mymq[wbXxg~ySjmPxnp3454XZly~`y?<2:W3+bta&{l$knv!cmi{+H~hzVxoS}`{r^e`[}iu89:8S_k|umv277=R8&myj#|i/fa{*fjlp&GscQ}d^rmpwY`kVrd~=>?4^Pfwpjs9:80Y=!hrg,qb*adp'iggu!Bxnp\vaYwf}xTknQwos2340YUmzgx<==;T2,cw`)zo%lou lljz,I}iuW{nT|cz}_fa\|jt789<T^h}zlu306>S7'nxm"h gbz-gim'Drd~R|k_qlwvZadWqey<=>8_Sgpqir6;;1^<"i}f/pe+be&jf`t"Cwos]q`Zvi|{UloRv`r123<ZTb{|f=><4U1-dvc(un&mht#mcky-N|jtX{U{by|Pgb]{kw6789UYi~{ct011?P6(o{l%~k!hcy,`hn~(EqeySz|Ppovq[beXpfx;<=?PRdqvhq74:2_;#j|i.sd,cf~)keas#@v`r^uq[uhszVmhSua}0121[Wct}e~:??5Z0.eqb+ta'nis"nbdx.O{kwYpzVzexQhc^zlv567;VXnxb{1208Q5)`zo$yj"ilx/aoo})JpfxT{Qnup\cfYg{:;<9Q]erwop4553\:$kh!rg-dg}(ddbr$Aua}_vp\tkruWniTtb|?017\V`urd};8>6[?/fpe*w`(ojr%oaew/LzlvZquWyd~Ril_ymq4561W[oxyaz>339V4*aun'xm#jmw.bnh|*Kg{U|~R~ats]dgZ~hz9:;;R\jstnw564<]9%l~k }f.e`|+ekcq%Ftb|Pws]sjqtXojUsc>?09]Qavsk|88:7X> gsd-vc)`kq$h`fv re]sjqtXj`d7<3<>;T2,cw`)zo%lou lljz,vaYwf}xTnd`31?02?P6(o{l%~k!hcy,`hn~(zmU{by|Pbhl?6;463\:$kh!rg-dg}(ddbr$~iQnup\flh;;78:7X> gsd-vc)`kq$h`fv re]sjqtXj`d783<>;T2,cw`)zo%lou lljz,vaYwf}xTnd`35?02?P6(o{l%~k!hcy,`hn~(zmU{by|Pbhl?2;463\:$kh!rg-dg}(ddbr$~iQnup\flh;?78:7X> gsd-vc)`kq$h`fv re]sjqtXj`d743<>;T2,cw`)zo%lou lljz,vaYwf}xTnd`39?03?P6(o{l%~k!hcy,`hn~(zmU{by|Pbhl\476<]9%l~k }f.e`|+ekcq%yhR~ats]amkY6:91^<"i}f/pe+be&jf`t"|k_qlwvZdnfV89<6[?/fpe*w`(ojr%oaew/sf\tkruWkceS><?;T2,cw`)zo%lou lljz,vaYwf}xTnd`P4328Q5)`zo$yj"ilx/aoo})ulVzexQmio]665=R8&myj#|i/fa{*fjlp&xoS}`{r^`jjZ0582_;#j|i.sd,cf~)keas#jPpovq[goiW>8;7X> gsd-vc)`kq$h`fv re]sjqtXj`dT4?>4U1-dvc(un&mht#mcky-q`Zvi|{UiecQ6279V4*aun'xm#jmw.bnh|*tcWyd~Rlfn^zlv5678;=0Y=!hrg,qb*adp'iggu!}d^rmpwYeagUsc>?01312>S7'nxm"h gbz-gim'{nT|cz}_ckm[}iu89::>:5Z0.eqb+ta'nis"nbdx.pg[uhszVhbbRv`r12354413\:$kh!rg-dg}(ddbr$~iQnup\flhXpfx;<=<=7:W3+bta&{l$knv!cmi{+wbXxg~ySoga_ymq45659;<0Y=!hrg,qb*adp'iggu!}d^rmpwYeagUsc>?0204?P6(o{l%~k!hcy,`hn~(zmU{by|Pbhl\|jt78999>;5Z0.eqb+ta'nis"nbdx.pg[uhszVhbbRv`r123071<]9%l~k }f.e`|+ekcq%yhR~ats]amkYg{:;<9?=6:W3+bta&{l$knv!cmi{+wbXxg~ySoga_ymq4562:>1^<"i}f/pe+be&jf`t"|k_qlwvZdnfVrd~=>?5005?P6(o{l%~k!hcy,`hn~(zmU{by|Pbhl\|jt789<946[?/fpe*w`(ojr%oaew/sf\tkruWkceSua}012554403\:$kh!rg-dg}(ddbr$~iQnup\flhXpfx;<=8=2c9V4*aun'xm#jmw.bnh|*tcWyd~Rlfn^zlv567>Vhoh=<9;T2,cw`)zo%lou lljz,vaYwf}xTnd`Pxnp34515?2_;#j|i.sd,cf~)keas#jPpovq[goiWqey<=>81348Q5)`zo$yj"ilx/aoo})ulVzexQmio]{kw67818<7X> gsd-vc)`kq$h`fv re]sjqtXj`dTtb|?01:265=R8&myj#|i/fa{*fjlp&xoS}`{r^e`858582_;#j|i.sd,cf~)keas#jPpovq[be;978;7X> gsd-vc)`kq$h`fv re]sjqtXoj692?>4U1-dvc(un&mht#mcky-q`Zvi|{Ulo1=1219V4*aun'xm#jmw.bnh|*tcWyd~Ril<5<14>S7'nxm"h gbz-gim'{nT|cz}_fa?1;473\:$kh!rg-dg}(ddbr$~iQnup\cf:16;:0Y=!hrg,qb*adp'iggu!}d^rmpwY`k5=5>=5Z0.eqb+ta'nis"nbdx.pg[uhszVmh050=0:W3+bta&{l$knv!cmi{+wbXxg~ySjm39?3e?P6(o{l%~k!hcy,`hn~(zmU{by|Pgb]35c=R8&myj#|i/fa{*fjlp&xoS}`{r^e`[47a3\:$kh!rg-dg}(ddbr$~iQnup\cfY59o1^<"i}f/pe+be&jf`t"|k_qlwvZadW:;m7X> gsd-vc)`kq$h`fv re]sjqtXojU?=k5Z0.eqb+ta'nis"nbdx.pg[uhszVmhS8?i;T2,cw`)zo%lou lljz,vaYwf}xTknQ91g9V4*aun'xm#jmw.bnh|*tcWyd~Ril_63e?P6(o{l%~k!hcy,`hn~(zmU{by|Pgb];5c=R8&myj#|i/fa{*fjlp&xoS}`{r^e`[<413\:$kh!rg-dg}(ddbr$~iQnup\cfYf{{ol0=0=6:W3+bta&{l$knv!cmi{+wbXxg~ySjmParpfc979:?1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyij2=>348Q5)`zo$yj"ilx/aoo})ulVzexQhc^cpv`a;;78=7X> gsd-vc)`kq$h`fv re]sjqtXojUjkh<5<12>S7'nxm"h gbz-gim'{nT|cz}_fa\evtbo5?5>;5Z0.eqb+ta'nis"nbdx.pg[uhszVmhSl}}ef>5:70<]9%l~k }f.e`|+ekcq%yhR~ats]dgZgtzlm7;3<9;T2,cw`)zo%lou lljz,vaYwf}xTknQnssgd8=85>2_;#j|i.sd,cf~)keas#jPpovq[beXizxnk171249V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabY7:<1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQ>249V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabY5:<1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQ<249V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabY3:<1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQ:249V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabY1:<1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQ8249V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabY?:<1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQ6289V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabYc95:5>45Z0.eqb+ta'nis"nbdx.pg[uhszVmhSl}}ef]g5979:01^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQk1=0=6<=R8&myj#|i/fa{*fjlp&xoS}`{r^e`[duumnUo=1=1289V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabYc95>5>45Z0.eqb+ta'nis"nbdx.pg[uhszVmhSl}}ef]g5939:01^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQk1=4=6<=R8&myj#|i/fa{*fjlp&xoS}`{r^e`[duumnUo=191289V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabYc9525>45Z0.eqb+ta'nis"nbdx.pg[uhszVmhSl}}ef]g59?9:11^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQk1^21<>S7'nxm"h gbz-gim'{nT|cz}_fa\evtboVn:S<<7;T2,cw`)zo%lou lljz,vaYwf}xTknQnssgd[a7X:;20Y=!hrg,qb*adp'iggu!}d^rmpwY`kVkx~hiPd0]06==R8&myj#|i/fa{*fjlp&xoS}`{r^e`[duumnUo=R:=8:W3+bta&{l$knv!cmi{+wbXxg~ySjmParpfcZb6W<837X> gsd-vc)`kq$h`fv re]sjqtXojUjkh_e3\27><]9%l~k }f.e`|+ekcq%yhR~ats]dgZgtzlmTh<Q8299V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabYc9V2946[?/fpe*w`(ojr%oaew/sf\tkruWniTm~|jg^f2[<423\:$kh!rg-dg}(ddbr$~iQnup\cfYg{:;<=<:;T2,cw`)zo%lou lljz,vaYwf}xTknQwos2344423\:$kh!rg-dg}(ddbr$~iQnup\cfYg{:;<?<:;T2,cw`)zo%lou lljz,vaYwf}xTknQwos2346423\:$kh!rg-dg}(ddbr$~iQnup\cfYg{:;<9<:;T2,cw`)zo%lou lljz,vaYwf}xTknQwos2340423\:$kh!rg-dg}(ddbr$~iQnup\cfYg{:;<;<:;T2,cw`)zo%lou lljz,vaYwf}xTknQwos2342423\:$kh!rg-dg}(ddbr$~iQnup\cfYg{:;<5<>;T2,cw`)zo%lou lljz,swYwf}xTnd`30?02?P6(o{l%~k!hcy,`hn~({U{by|Pbhl?5;463\:$kh!rg-dg}(ddbr${Qnup\flh;:78:7X> gsd-vc)`kq$h`fv ws]sjqtXj`d7?3<>;T2,cw`)zo%lou lljz,swYwf}xTnd`34?02?P6(o{l%~k!hcy,`hn~({U{by|Pbhl?1;463\:$kh!rg-dg}(ddbr${Qnup\flh;>78:7X> gsd-vc)`kq$h`fv ws]sjqtXj`d7;3<>;T2,cw`)zo%lou lljz,swYwf}xTnd`38?02?P6(o{l%~k!hcy,`hn~({U{by|Pbhl?=;473\:$kh!rg-dg}(ddbr${Qnup\flhX8;:0Y=!hrg,qb*adp'iggu!xr^rmpwYeagU:>=5Z0.eqb+ta'nis"nbdx.uq[uhszVhbbR<=0:W3+bta&{l$knv!cmi{+rtXxg~ySoga_203?P6(o{l%~k!hcy,`hn~({U{by|Pbhl\076<]9%l~k }f.e`|+ekcq%|~R~ats]amkY2:91^<"i}f/pe+be&jf`t"y}_qlwvZdnfV<9<6[?/fpe*w`(ojr%oaew/vp\tkruWkceS:<?;T2,cw`)zo%lou lljz,swYwf}xTnd`P8328Q5)`zo$yj"ilx/aoo})pzVzexQmio]:63=R8&myj#|i/fa{*fjlp&}yS}`{r^`jjZ~hz9:;<?94U1-dvc(un&mht#mcky-tvZvi|{UiecQwos234575>2_;#j|i.sd,cf~)keas#z|Ppovq[goiWqey<=>>269V4*aun'xm#jmw.bnh|*quWyd~Rlfn^zlv567988=7X> gsd-vc)`kq$h`fv ws]sjqtXj`dTtb|?01013>S7'nxm"h gbz-gim'~xT|cz}_ckm[}iu89:9=?84U1-dvc(un&mht#mcky-tvZvi|{UiecQwos2346403\:$kh!rg-dg}(ddbr${Qnup\flhXpfx;<===279V4*aun'xm#jmw.bnh|*quWyd~Rlfn^zlv567<;=0Y=!hrg,qb*adp'iggu!xr^rmpwYeagUsc>?05312>S7'nxm"h gbz-gim'~xT|cz}_ckm[}iu89:>>:5Z0.eqb+ta'nis"nbdx.uq[uhszVhbbRv`r12314413\:$kh!rg-dg}(ddbr${Qnup\flhXpfx;<=8=8:W3+bta&{l$knv!cmi{+rtXxg~ySoga_ymq4561988<7X> gsd-vc)`kq$h`fv ws]sjqtXj`dTtb|?01416g=R8&myj#|i/fa{*fjlp&}yS}`{r^`jjZ~hz9:;:Rlkd105?P6(o{l%~k!hcy,`hn~({U{by|Pbhl\|jt789=9;6[?/fpe*w`(ojr%oaew/vp\tkruWkceSua}0124570<]9%l~k }f.e`|+ekcq%|~R~ats]amkYg{:;<5<8;T2,cw`)zo%lou lljz,swYwf}xTnd`Pxnp345>6:91^<"i}f/pe+be&jf`t"y}_qlwvZad4949<6[?/fpe*w`(ojr%oaew/vp\tkruWni7=3<?;T2,cw`)zo%lou lljz,swYwf}xTkn2=>328Q5)`zo$yj"ilx/aoo})pzVzexQhc=1=65=R8&myj#|i/fa{*fjlp&}yS}`{r^e`818582_;#j|i.sd,cf~)keas#z|Ppovq[be;=78;7X> gsd-vc)`kq$h`fv ws]sjqtXoj6=2?>4U1-dvc(un&mht#mcky-tvZvi|{Ulo191219V4*aun'xm#jmw.bnh|*quWyd~Ril<9<14>S7'nxm"h gbz-gim'~xT|cz}_fa?=;7a3\:$kh!rg-dg}(ddbr${Qnup\cfY79o1^<"i}f/pe+be&jf`t"y}_qlwvZadW8;m7X> gsd-vc)`kq$h`fv ws]sjqtXojU9=k5Z0.eqb+ta'nis"nbdx.uq[uhszVmhS>?i;T2,cw`)zo%lou lljz,swYwf}xTknQ;1g9V4*aun'xm#jmw.bnh|*quWyd~Ril_43e?P6(o{l%~k!hcy,`hn~({U{by|Pgb]55c=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[27a3\:$kh!rg-dg}(ddbr${Qnup\cfY?9o1^<"i}f/pe+be&jf`t"y}_qlwvZadW08=7X> gsd-vc)`kq$h`fv ws]sjqtXojUjkh<1<12>S7'nxm"h gbz-gim'~xT|cz}_fa\evtbo5;5>;5Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef>1:70<]9%l~k }f.e`|+ekcq%|~R~ats]dgZgtzlm7?3<9;T2,cw`)zo%lou lljz,swYwf}xTknQnssgd8185>2_;#j|i.sd,cf~)keas#z|Ppovq[beXizxnk1;1279V4*aun'xm#jmw.bnh|*quWyd~Ril_`qqab:16;<0Y=!hrg,qb*adp'iggu!xr^rmpwY`kVkx~hi37?05?P6(o{l%~k!hcy,`hn~({U{by|Pgb]bwwc`4149:6[?/fpe*w`(ojr%oaew/vp\tkruWniTm~|jg=;=60=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnU;>85Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]260=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnU9>85Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]060=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnU?>85Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]660=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnU=>85Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]460=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnU3>85Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]:6<=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnUo=1>1289V4*aun'xm#jmw.bnh|*quWyd~Ril_`qqabYc95;5>45Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]g5949:01^<"i}f/pe+be&jf`t"y}_qlwvZadWhyyijQk1=1=6<=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnUo=1:1289V4*aun'xm#jmw.bnh|*quWyd~Ril_`qqabYc95?5>45Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]g5909:01^<"i}f/pe+be&jf`t"y}_qlwvZadWhyyijQk1=5=6<=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnUo=161289V4*aun'xm#jmw.bnh|*quWyd~Ril_`qqabYc9535>55Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]g5Z6502_;#j|i.sd,cf~)keas#z|Ppovq[beXizxnkRj>_00;?P6(o{l%~k!hcy,`hn~({U{by|Pgb]bwwc`Wm;T>?64U1-dvc(un&mht#mcky-tvZvi|{UloRo|rde\`4Y4:11^<"i}f/pe+be&jf`t"y}_qlwvZadWhyyijQk1^61<>S7'nxm"h gbz-gim'~xT|cz}_fa\evtboVn:S8<7;T2,cw`)zo%lou lljz,swYwf}xTknQnssgd[a7X>;20Y=!hrg,qb*adp'iggu!xr^rmpwY`kVkx~hiPd0]46==R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnUo=R6=8:W3+bta&{l$knv!cmi{+rtXxg~ySjmParpfcZb6W08>7X> gsd-vc)`kq$h`fv ws]sjqtXojUsc>?0106?P6(o{l%~k!hcy,`hn~({U{by|Pgb]{kw67888>7X> gsd-vc)`kq$h`fv ws]sjqtXojUsc>?0306?P6(o{l%~k!hcy,`hn~({U{by|Pgb]{kw678:8>7X> gsd-vc)`kq$h`fv ws]sjqtXojUsc>?0506?P6(o{l%~k!hcy,`hn~({U{by|Pgb]{kw678<8>7X> gsd-vc)`kq$h`fv ws]sjqtXojUsc>?0706?P6(o{l%~k!hcy,`hn~({U{by|Pgb]{kw678>8>7X> gsd-vc)`kq$h`fv ws]sjqtXojUsc>?091;?P6(o{l%~k!hl1,q`*au9'myhn<!rea,IdbcW{nThnQf_`fgwpd789::<>64U1-dvc(un&mg<#|k/fp2*btck;$yhn!Baef\vaYckVcTmij|uc234575;11^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GjhiQ}d^f`[lYflmy~n=>?0060<>S7'nxm"h gm2-va)`z8$l~im=.sf`+HgclVxoSimPi^cg`vse89:;=;=8;T2,cw`)zo%l`= }d.eq5+aulj8%~im M`fg[wbXljUbSljkst`34565;>1^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GjhiQ}d^f`[lYflmy~n=>?0514?P6(o{l%~k!hl1,q`*au9'myhn<!rea,IdbcW{nThnQf_`fgwpd789:=?:5Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"Cnde]q`ZbdW`Ujhi}zb1234=5d3\:$kh!rg-dh5(ul&my=#i}db0-vae(EhnoSjPdb]j[dbc{|h;<=>Pcx>2:6><]9%l~k }f.eo4+tc'nx:"j|kc3,q`f)J{|hThdhi_vp\vaYseyUhu1>1399V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZe~484846[?/fpe*w`(oe:%~i!hr0,dvae5&{nh#@}zb^fjbcYpzVxoSyc_b{?6;5?3\:$kh!rg-dh5(ul&my=#i}db0-vae(EziSigif^uq[wbX|dzTot2<>2:8Q5)`zo$yj"ic0/pg+bt6&nxoo? }db-NwpdXl`lmSz|Pre]wiuYdq5>5?55Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^az808402_;#j|i.sd,ci6)zm%l~< hrea1*wbd'Dy~nRjffg]tvZtcW}g{Snw36?1;?P6(o{l%~k!hl1,q`*au9'myhn<!rea,IvseWmcmjRy}_sf\phvXkp6<2>64U1-dvc(un&mg<#|k/fp2*btck;$yhn!Bst`\`l`aW~xT~iQ{mq]`}9>9;01^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GxyoQkigd\swYulV~f|Rbzt=2=7<=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*Kt}kUoekhPws]q`ZrjxVf~x1?1389V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZjr|585?45Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^nvp959;01^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GxyoQkigd\swYulV~f|Rbzt=6=7<=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*Kt}kUoekhPws]q`ZrjxVf~x1;1389V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZjr|5<5?45Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^nvp919;01^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GxyoQkigd\swYulV~f|Rbzt=:=7<=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*Kt}kUoekhPws]q`ZrjxVf~x171389V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZ~hz5:5?45Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^zlv979;01^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GxyoQkigd\swYulV~f|Rv`r=0=7<=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*Kt}kUoekhPws]q`ZrjxVrd~1=1389V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZ~hz5>5?45Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^zlv939;01^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GxyoQkigd\swYulV~f|Rv`r=4=7<=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*Kt}kUoekhPws]q`ZrjxVrd~191389V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZ~hz525?45Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^zlv9?9;91^<"i}f/pe+bj7&{n$k?!gsf`6+tck&nbjkQxr^pg[qkw494946[?/fpe*w`(oe:%~i!hr0,dvae5&{nh#jPdb]j[54?3\:$kh!rg-dh5(ul&my=#i}db0-vae(zmUooRgP13;8Q5)`zo$yj"ic0/pg+bt6&nxoo? }db-q`ZbdW`U:<?64U1-dvc(un&mg<#|k/fp2*btck;$yhn!}d^f`[lY5:11^<"i}f/pe+bj7&{n$k?!gsf`6+tck&xoSimPi^11<>S7'nxm"h gm2-va)`z8$l~im=.sf`+wbXljUbS9<7;T2,cw`)zo%l`= }d.eq5+aulj8%~im re]ggZoX=;20Y=!hrg,qb*ak8'xo#j|>.fpgg7(ulj%yhRjl_h]56==R8&myj#|i/fn3*wb(o{;%kjl2/pgg*tcWmiTeR9=8:W3+bta&{l$ka>!re-dv4(`zmi9"jl/sf\`fYnW1837X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\=67<]9%l~k }f.eo4+tc'nx:"j|kc3,q`f)ulVnhSdQbuy2347:76:80Y=!hrg,qb*ak8'xo#j|>.fpgg7(ulj%yhRjl_h]nq}678;6;2<==;T2,cw`)zo%l`= }d.eq5+aulj8%~im re]ggZoXe|r;<=<311<07>S7'nxm"h gm2-va)`z8$l~im=.sf`+wbXljUbS`{w012184699:;0Y=!hrg,qb*ak8'xo#j|>.fpgg7(ulj%yhRjl_h]nq}678;6:2><4U1-dvc(un&mg<#|k/fp2*btck;$yhn!}d^f`[lYj}q:;<?2>>012?P6(o{l%~k!hl1,q`*au9'myhn<!rea,vaYckVcTaxv?010?6;553\:$kh!rg-dh5(ul&my=#i}db0-vae(zmUooRgPmtz3454;:7;8=6[?/fpe*w`(oe:%~i!hr0,dvae5&{nh#jPdb]j[hs89:90>0<2:W3+bta&{l$ka>!re-dv4(`zmi9"jl/sf\`fYnWds<=>=<2<274=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*tcWmiTeRczx1236929;;1^<"i}f/pe+bj7&{n$k?!gsf`6+tck&xoSimPi^ov|567:5>5=>:4U1-dvc(un&mg<#|k/fp2*btck;$yhn!}d^f`[lYj}q:;<?2;>0327==R8&myj#|i/fn3*wb(o{;%kjl2/pgg*tcWmiTeRczx123692998;T_Z><1:W3+bta&{l$ka>!re-dv4(`zmi9"jl/sf\`fYnWds<=>=<4<07>S7'nxm"h gm2-va)`z8$l~im=.sf`+wbXljUbS`{w012180869:80Y=!hrg,qb*ak8'xo#j|>.fpgg7(ulj%yhRjl_h]nq}678;6>2?=>;T2,cw`)zo%l`= }d.eq5+aulj8%~im re]ggZoXe|r;<=<36?16?P6(o{l%~k!hl1,q`*au9'myhn<!rea,vaYckVcTaxv?010?2;YT_99:7X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~78987;3=:;T2,cw`)zo%l`= }d.eq5+aulj8%~im re]ggZoXe|r;<=<37?]PS5563\:$kh!rg-dh5(ul&my=#i}db0-vae(zmUooRgPmtz3454;079>7X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~7898743Q\W116?P6(o{l%~k!hl1,q`*au9'myhn<!rea,vaYckVcTaxv?010?<;YT_8927X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~7898743Q\W0]PS5563\:$kh!rg-dh5(ul&my=#i}db0-vae(zmUooRgPmtz3454;17987X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~7898753<>369V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.pg[aeXaVg~t=>?2=;=64YT_99<7X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~7898753<>_RU272=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*tcWmiTeRczx12369?9;9UX[==<;T2,cw`)zo%l`= }d.eq5+aulj8%~im re]ggZoXe|r;<=<39?1276=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*tcWmiTeRczx12369?9;1997X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~7898753:<3:W3+bta&{l$ka>!re-dv4(`zmi9"jl/sf\`fYnWds<=>=<8<7561<]9%l~k }f.eo4+tc'nx:"j|kc3,q`f)ulVnhSdQbuy2347:>6=;T_Z>=a:W3+bta&{l$ka>!re-dv4(un~l#_OB_SF\AKYA_O^:>45Z0.eqb+ta'nf;"j gs3-vcqa|&XJAR\JGNWW[@H6:k1^<"i}f/pe+bj7&{n$k?!rguep*TFEV\J@DJPFVDW54543\:$kh!rg-dh5(ul&my=#|iwgv,gptuWo}mxR}{aug\BVKXNOn:?;5Z0.eqb+ta'nf;"j gs3-vcqa|&i~~Qiwgv\wqgsmVLXARHId0/Jj6><]9%l~k }f.eo4+tc'nx:"hxfu-`qwtXn~lS~zntd]EWHYANm;&Ec?>329V4*aun'xm#jb?.sf,cw7)zo}mx"mzrs]escrX{}kiRH\M^DE`7513\:$kh!rg-dh5(ul&my=#|iwgv,gptuWo}mxR}{aug\BVKXNOn9!D`<8:W3+bta&{l$ka>!re-dv4(un~l#n{}r^dtbqYt|h~nSK]B_GDg6(Oi98837X> gsd-vc)`d9$yh"i}1/pescr(mdzuRhxfu]ef71<]9%l~k }f.eo4+tc'nx:"hxfu-fiur~Wo}mxRg=e:W3+bta&{l$ka>!re-dv4(un~l#hctx]escrXaVey<=>?2g9V4*aun'xm#jb?.sf,cw7)zo}mx"kbpu{\br`sW`Ud~=>?0006?P6(o{l%~k!hl1,q`*au9'xm{kz urgq[sgkam827X> gsd-vc)`d9$yh"i}ar,qwqu(k9%hm|vndv?4;4>3\:$kh!rg-dh5(ul&mym~ }suq,g5)di{xrbhz31?0:?P6(o{l%~k!hl1,q`*auiz$yy} c1-`ewt~fl~7>3<6;T2,cw`)zo%l`= }d.eqev(u{}y$o=!laspzj`r;;78m7X> gsd-vc)`d9$yh"i}ar,qwqu(k9%laxv!glY3Y+aj9'g:>k5Z0.eqb+ta'nf;"j gscp*wus{&i;#jczx/en_4[)ody%a~<i;T2,cw`)zo%l`= }d.eqev(u{}y$o=!hmtz-ch]5U'mf#c|2g9V4*aun'xm#jb?.sf,cwgt&{y"m?/fov|+ajS:W%k`}!mr0e?P6(o{l%~k!hl1,q`*auiz$yy} c1-dip~)odQ?Q#ibs/op66=R8&myj#|i/fn3*wb(o{kx"}{s.a3+s7;87887X> gsd-vc)`d9$yh"i}ar,qwqu(k9%}=1?1229V4*aun'xm#jb?.sf,cwgt&{y"m?/w3?6;443\:$kh!rg-dh5(ul&mym~ }suq,g5)q9595>>5Z0.eqb+ta'nf;"j gscp*wus{&i;#{?34?0a?P6(o{l%~k!hl1,q`*auiz$yy} c1-u5Z6Xign;<=>>2c9V4*aun'xm#jb?.sf,cwgt&{y"m?/w3\5Zgil9:;<<<m;T2,cw`)zo%l`= }d.eqev(u{}y$o=!y1^0\ekb789::>o5Z0.eqb+ta'nf;"j gscp*wus{&i;#{?P3^cm`567888i7X> gsd-vc)`d9$yh"i}ar,qwqu(k9%}=R:Paof34566:01^<"i}f/pe+bj7&{n$ko|.sqww*e6'jky~t`jt=2=6<=R8&myj#|i/fn3*wb(o{kx"}{s.a2+fguzpdnx1?1289V4*aun'xm#jb?.sf,cwgt&{y"m>/bcqv|hb|585>45Z0.eqb+ta'nf;"j gscp*wus{&i:#no}rxlfp959:o1^<"i}f/pe+bj7&{n$ko|.sqww*e6'ng~t#ib[1_-ch7)e88m7X> gsd-vc)`d9$yh"i}ar,qwqu(k8%laxv!glY2Y+aj{'gx>k5Z0.eqb+ta'nf;"j gscp*wus{&i:#jczx/en_7[)ody%a~<i;T2,cw`)zo%l`= }d.eqev(u{}y$o<!hmtz-ch]4U'mf#c|2g9V4*aun'xm#jb?.sf,cwgt&{y"m>/fov|+ajS=W%k`}!mr00?P6(o{l%~k!hl1,q`*auiz$yy} c0-u5969::1^<"i}f/pe+bj7&{n$ko|.sqww*e6';7=3<<;T2,cw`)zo%l`= }d.eqev(u{}y$o<!y1=0=66=R8&myj#|i/fn3*wb(o{kx"}{s.a2+s7;;7887X> gsd-vc)`d9$yh"i}ar,qwqu(k8%}=1:12c9V4*aun'xm#jb?.sf,cwgt&{y"m>/w3\4Zgil9:;<<<m;T2,cw`)zo%l`= }d.eqev(u{}y$o<!y1^3\ekb789::>o5Z0.eqb+ta'nf;"j gscp*wus{&i:#{?P2^cm`567888i7X> gsd-vc)`d9$yh"i}ar,qwqu(k8%}=R=Paof34566:k1^<"i}f/pe+bj7&{n$ko|.sqww*e6';T8Road12344473\:$kh!rg-dh5(ul&mym~ }suq,gjkw8;:0Y=!hrg,qb*ak8'xo#j|ns/pppv)dgdz:>45Z0.eqb+ta'nf;"j gscp*wus{&xjaRkbpu{\bgYn;91^<"i}f/pe+bj7&{n$ko|.sqww*tfeVof|ywPfc]j[jt789:8=6[?/fpe*w`(oe:%~i!hr`q-vvrt'{kfShctx]efZoXg{:;<=?>f:W3+bta&{l$ka>!re-qehYqiecoSkyit318Q5)`zo$yj"ic0/pg+wvi|{%Fob{at^alqkr5<2_;#j|i.sd,ci6)zm%y|cz}/LalqkrXkfex<<;;T2,cw`)zo%l`= }d.psjqt(Eje~byQlotlw672<]9%l~k }f.eo4+tc'{zex!BcnwmpZeh}g~8>95Z0.eqb+ta'nf;"j rqlwv*Kdg|dSnaznu610>S7'nxm"h gm2-va)uxg~y#@m`uov\gjsi|<8?7X> gsd-vc)`d9$yh"|nup,Ifirf}Uhcx`{6368Q5)`zo$yj"ic0/pg+wvi|{%Fob{at^alqkr0:=1^<"i}f/pe+bj7&{n$~}`{r.O`kphsWje~by6=4:W3+bta&{l$ka>!re-qtkru'DidyczPcnwmp<4>3\:$kh!rg-dh5(ul&x{by| MbmvjqYdg|dSnw30?0`?P6(o{l%~k!hl1,q`*twf}x$Anaznu]`kphsWjs7<3Q}t3;8Q5)`zo$yj"ic0/pg+wvi|{%Fob{at^alqkrXkp6:2?m4U1-dvc(un&mg<#|k/srmpw)JkfexRm`uov\g|:66Vx>45Z0.eqb+ta'nf;"j rqlwv*Kdg|dSnaznu]`}949:j1^<"i}f/pe+bj7&{n$~}`{r.O`kphsWje~byQly=0=[wr512_;#j|i.sd,ci6)zm%y|cz}/LalqkrXkfexRmv<2<1g>S7'nxm"h gm2-va)uxg~y#@m`uov\gjsi|Vir0>0Pru0:?P6(o{l%~k!hl1,q`*twf}x$Anaznu]`kphsWjs783<l;T2,cw`)zo%l`= }d.psjqt(Eje~byQlotlw[f;<7Uyx?74U1-dvc(un&mg<#|k/srmpw)JkfexRm`uov\g|:26;i0Y=!hrg,qb*ak8'xo#~ats-Ngjsi|VidyczPcx>6:Zts:01^<"i}f/pe+bj7&{n$~}`{r.O`kphsWje~byQly=4=6f=R8&myj#|i/fn3*wb(zyd~"Clotlw[firf}Uhu181_sv1=>S7'nxm"h gm2-va)uxg~y#@m`uov\gjsi|Vir0:0=c:W3+bta&{l$ka>!re-qtkru'DidyczPcnwmpZe~4>4T~y<6;T2,cw`)zo%l`= }d.psjqt(Eje~byQlotlw[f;078h7X> gsd-vc)`d9$yh"|nup,Ifirf}Uhcx`{_b{?<;Yu|;k0Y=!hrg,qb*ak8'xo#~ats-Ngjsi|VidyczPxnp?4;4f3\:$kh!rg-dh5(ul&x{by| MbmvjqYdg|dSua}<0<1e>S7'nxm"h gm2-va)uxg~y#@m`uov\gjsi|Vrd~1<12`9V4*aun'xm#jb?.sf,vuhsz&Ghcx`{_bmvjqYg{682?o4U1-dvc(un&mg<#|k/srmpw)JkfexRm`uov\|jt;<78j7X> gsd-vc)`d9$yh"|nup,Ifirf}Uhcx`{_ymq8085i2_;#j|i.sd,ci6)zm%y|cz}/LalqkrXkfexRv`r=4=6d=R8&myj#|i/fn3*wb(zyd~"Clotlw[firf}Usc28>3c8Q5)`zo$yj"ic0/pg+wvi|{%Fob{at^alqkrXpfx743<n;T2,cw`)zo%l`= }d.psjqt(Eje~byQlotlw[}iu4049h6[?/fpe*w`(oe:%~i!}povq+Heh}g~Tob{at^zlv9?9W{~:j6[?/fpe*w`(oe:%~i!}povq+firf}6;2<h4U1-dvc(un&mg<#|k/srmpw)dg|d0<0>f:W3+bta&{l$ka>!re-qtkru'je~by2=>0d8Q5)`zo$yj"ic0/pg+wvi|{%hcx`{<2<2b>S7'nxm"h gm2-va)uxg~y#naznu>7:4`<]9%l~k }f.eo4+tc'{zex!lotlw8086n2_;#j|i.sd,ci6)zm%y|cz}/bmvjq:168l0Y=!hrg,qb*ak8'xo#~ats-`kphs4>4:j6[?/fpe*w`(oe:%~i!}povq+firf}632<h4U1-dvc(un&mg<#|k/srmpw)dg|d040>e:W3+bta&{l$ka>!re-qtkru'je~byQ?1d9V4*aun'xm#jb?.sf,vuhsz&idyczP10g8Q5)`zo$yj"ic0/pg+wvi|{%hcx`{_33f?P6(o{l%~k!hl1,q`*twf}x$ob{at^12a>S7'nxm"h gm2-va)uxg~y#naznu]75`=R8&myj#|i/fn3*wb(zyd~"m`uov\14c<]9%l~k }f.eo4+tc'{zex!lotlw[37b3\:$kh!rg-dh5(ul&x{by| cnwmpZ16m2_;#j|i.sd,ci6)zm%y|cz}/bmvjqY?9l1^<"i}f/pe+bj7&{n$~}`{r.alqkrX1;80Y=!hrg,qb*ak8'xo#~ats-`kphsWm;7<3<=;T2,cw`)zo%l`= }d.psjqt(kfexRj><0<16>S7'nxm"h gm2-va)uxg~y#naznu]g5949:;1^<"i}f/pe+bj7&{n$~}`{r.alqkrXl8682?<4U1-dvc(un&mg<#|k/srmpw)dg|dSi?34?01?P6(o{l%~k!hl1,q`*twf}x$ob{at^f28085:2_;#j|i.sd,ci6)zm%y|cz}/bmvjqYc95<5>?5Z0.eqb+ta'nf;"j rqlwv*eh}g~Th<28>308Q5)`zo$yj"ic0/pg+wvi|{%hcx`{_e3?<;453\:$kh!rg-dh5(ul&x{by| cnwmpZb64049=6[?/fpe*w`(oe:%~i!}povq+firf}Uo=R>=1:W3+bta&{l$ka>!re-qtkru'je~byQk1^315>S7'nxm"h gm2-va)uxg~y#naznu]g5Z4592_;#j|i.sd,ci6)zm%y|cz}/bmvjqYc9V99=6[?/fpe*w`(oe:%~i!}povq+firf}Uo=R:=1:W3+bta&{l$ka>!re-qtkru'je~byQk1^715>S7'nxm"h gm2-va)uxg~y#naznu]g5Z0592_;#j|i.sd,ci6)zm%y|cz}/bmvjqYc9V=9=6[?/fpe*w`(oe:%~i!}povq+firf}Uo=R6=1:W3+bta&{l$ka>!re-qtkru'je~byQk1^;1=>S7'nxm"h gm2-sw)`hy%{~z|/b3,gdtuqgo0=0=9:W3+bta&{l$ka>!ws-dsdu)z~x#n? c`pq}kcs484956[?/fpe*w`(oe:%{!hw`q-svrt'j;$ol|}yogw878512_;#j|i.sd,ci6){%l{l}!wrvp+f7(khxyuck{<2<1b>S7'nxm"h gm2-sw)`hy%{~z|/b3,chs&ngP<P hm0,n57`<]9%l~k }f.eo4+qu'n}j#y|tr-`5*aj}q$laV?R.fop*hu5n2_;#j|i.sd,ci6){%l{l}!wrvp+f7(ods"jcT2\,div(j{;l0Y=!hrg,qb*ak8'}y#jyns/uppv)d9&mfyu hmZ1^*bkt&dy9j6[?/fpe*w`(oe:%{!hw`q-svrt'j;$k`{w.foX0X(`ez$f?=4U1-dvc(un&mg<#y}/fubw+qt|z%h="x><1<17>S7'nxm"h gm2-sw)`hy%{~z|/b3,r4:66;90Y=!hrg,qb*ak8'}y#jyns/uppv)d9&|:0?0=3:W3+bta&{l$ka>!ws-dsdu)z~x#n? v0>0:75<]9%l~k }f.eo4+qu'n}j#y|tr-`5*p64=49n6[?/fpe*w`(oe:%{!hw`q-svrt'j;$z<Q?_`lg45679;h0Y=!hrg,qb*ak8'}y#jyns/uppv)d9&|:S<Qnne234575j2_;#j|i.sd,ci6){%l{l}!wrvp+f7(~8U9Sl`k012357d<]9%l~k }f.eo4+qu'n}j#y|tr-`5*p6W:Ujbi>?0131f>S7'nxm"h gm2-sw)`hy%{~z|/b3,r4Y3Whdo<=>?13;8Q5)`zo$yj"ic0/uq+bqf{'}xx~!l2.abvwim}6;2?74U1-dvc(un&mg<#y}/fubw+qt|z%h>"mnrs{maq:66;30Y=!hrg,qb*ak8'}y#jyns/uppv)d:&ij~waeu>1:7?<]9%l~k }f.eo4+qu'n}j#y|tr-`6*efz{seiy2<>3d8Q5)`zo$yj"ic0/uq+bqf{'}xx~!l2.enq}(`eR:V"jc>.l31b>S7'nxm"h gm2-sw)`hy%{~z|/b0,chs&ngP=P hmr,nw7`<]9%l~k }f.eo4+qu'n}j#y|tr-`6*aj}q$laV<R.fop*hu5n2_;#j|i.sd,ci6){%l{l}!wrvp+f4(ods"jcT3\,div(j{;l0Y=!hrg,qb*ak8'}y#jyns/uppv)d:&mfyu hmZ6^*bkt&dy9?6[?/fpe*w`(oe:%{!hw`q-svrt'j8$z<2?>318Q5)`zo$yj"ic0/uq+bqf{'}xx~!l2.t28485;2_;#j|i.sd,ci6){%l{l}!wrvp+f4(~8692?=4U1-dvc(un&mg<#y}/fubw+qt|z%h>"x><2<17>S7'nxm"h gm2-sw)`hy%{~z|/b0,r4:36;h0Y=!hrg,qb*ak8'}y#jyns/uppv)d:&|:S=Qnne234575j2_;#j|i.sd,ci6){%l{l}!wrvp+f4(~8U:Sl`k012357d<]9%l~k }f.eo4+qu'n}j#y|tr-`6*p6W;Ujbi>?0131f>S7'nxm"h gm2-sw)`hy%{~z|/b0,r4Y4Whdo<=>?13`8Q5)`zo$yj"ic0/uq+bqf{'}xx~!l2.t2[1Yffm:;<=?=0:W3+bta&{l$ka>!ws-dsdu)z~x#nabp003?P6(o{l%~k!hl1,tv*apiz$|y} cnos67><]9%l~k }f.eo4+qu'n}j#y|tr-qehYa}efTjoQf249V4*aun'xm#jb?.vp,crgt&~y"|nm^dvhiYn:j1^<"i}f/pe+bj7&~x$kzo|.vqww*tfeVl~`aQf_np34565l2_;#j|i.sd,ci6){%l{l}!wrvp+wgjWog`RgPos234574k2_;#j|i.sd,ci6){%l{im>.vf`a}r(EhnoSz|Pd`vb[firf}UbSljk0123555d3\:$kh!rg-dh5(pz&m|hn?!weaf|q)JimnT{Qkauc\gjsi|VcTmij?012266e<]9%l~k }f.eo4+qu'n}oo< xdbg{p*KflmU|~Rjnt`]`kphsW`Ujhi>?01377f=R8&myj#|i/fn3*rt(o~nh=#ykcdzw+HgclV}ySio{a^alqkrXaVkoh=>?0040f>S7'nxm"h gm2-sw)`mi:"zjleyv,IdbcW~xThlzn_bmvjqYnWhno<=>?22`8Q5)`zo$yj"ic0/uq+bqck8$|hnkwt.Ob`aYpzVnjxlQlotlw[lYflm:;<=:<b:W3+bta&{l$ka>!ws-dsae6&~nhiuz M`fg[rtXlh~jSnaznu]j[dbc89:;:>l4U1-dvc(un&mg<#y}/fugg4(pljosx"Cnde]tvZbf|hUhcx`{_h]b`a67892?<6[?/fpe*w`(oe:%{!hwea2*rbdmq~$Aljk_vp\`drfWje~byQf_`fg4567Wjs7=3:?;T2,cw`)zo%l`= xr.et`f7)minty!Baef\swYci}kTob{at^k\eab789:Tot26>548Q5)`zo$yj"ic0/uq+bqck8$|hnkwt.Ob`aYpzVnjxlQlotlw[lYflm:;<=Qly=;=74YT_8>97X> gsd-vc)`d9$|~"ixdb3-saebp}%FmijPws]geqgXkfexRgPaef3456Xkp6229?;5:W3+bta&{l$ka>!ws-dsae6&~nhiuz M`fg[rtXlh~jSnaznu]j[dbc89:;Snw39?]a`a2312_;#j|i.sd,ci6){%l{im>.vf`a}r(EhnoSz|Pd`vb[firf}UbSljk0123[}iu484:=RGAV^277>S7'nxm"h gm2-sw)`mi:"zjleyv,IdbcW~xThlzn_bmvjqYnWhno<=>?_ymq87869=90Y=!hrg,qb*ak8'}y#jykc0,t`fc|&GjhiQxr^fbpdYdg|dSdQnde2345Yg{682<?;3:W3+bta&{l$ka>!ws-dsae6&~nhiuz M`fg[rtXlh~jSnaznu]j[dbc89:;Sua}<5<2561<]9%l~k }f.eo4+qu'n}oo< xdbg{p*Kt}kUoekhPws]q`ZrjxVir0=0<7:W3+bta&{l$ka>!ws-dsae6&~nhiuz Mrwa[aoanV}ySjPtlr\g|:66:=0Y=!hrg,qb*ak8'}y#jykc0,t`fc|&GxyoQkigd\swYulV~f|Rmv<3<03>S7'nxm"h gm2-sw)`mi:"zjleyv,IvseWmcmjRy}_sf\phvXkp682>94U1-dvc(un&mg<#y}/fugg4(pljosx"C|uc]gmc`X{UyhRzbp^az8184?2_;#j|i.sd,ci6){%l{im>.vf`a}r(EziSigif^uq[wbX|dzTot2:>258Q5)`zo$yj"ic0/uq+bqck8$|hnkwt.OpqgYcaolT{Q}d^vntZe~4?48;6[?/fpe*w`(oe:%{!hwea2*rbdmq~$A~{m_ekebZquW{nTx`~Pcx>4:61<]9%l~k }f.eo4+qu'n}oo< xdbg{p*Kt}kUoekhPws]q`ZrjxVir050<8:W3+bta&{l$ka>!ws-dsae6&~nhiuz Mrwa[aoanV}ySjPtlr\hpr;87937X> gsd-vc)`d9$|~"ixdb3-saebp}%FxlPdhde[rtXzmUa}Qcuu>2:6><]9%l~k }f.eo4+qu'n}oo< xdbg{p*Kt}kUoekhPws]q`ZrjxVf~x1<1399V4*aun'xm#jb?.vp,crbd9'}oohv{/LqvfZbnnoU|~R|k_uos[iss4:4846[?/fpe*w`(oe:%{!hwea2*rbdmq~$A~{m_ekebZquW{nTx`~Pltv?0;5?3\:$kh!rg-dh5(pz&m|hn?!weaf|q)J{|hThdhi_vp\vaYseyUgyy2:>2:8Q5)`zo$yj"ic0/uq+bqck8$|hnkwt.OpqgYcaolT{Q}d^vntZjr|5<5?55Z0.eqb+ta'nf;"z| gvf`5+qcklr#@}zb^fjbcYpzVxoSyc_mww828402_;#j|i.sd,ci6){%l{im>.vf`a}r(EziSigif^uq[wbX|dzT`xz38?1;?P6(o{l%~k!hl1,tv*aplj;%{imjxu-NwpdXl`lmSz|Pre]wiuYk}}622>64U1-dvc(un&mg<#y}/fugg4(pljosx"C|uc]gmc`X{UyhRzbp^zlv969;11^<"i}f/pe+bj7&~x$kzjl1/ugg`~s'Dy~nRjffg]tvZtcW}g{Sua}<0<0<>S7'nxm"h gm2-sw)`mi:"zjleyv,IvseWmcmjRy}_sf\phvXpfx7>3=7;T2,cw`)zo%l`= xr.et`f7)minty!Bst`\`l`aW~xT~iQ{mq]{kw:46:20Y=!hrg,qb*ak8'}y#jykc0,t`fc|&GxyoQkigd\swYulV~f|Rv`r=6=7==R8&myj#|i/fn3*rt(o~nh=#ykcdzw+HurjVnbjkQxr^pg[qkwWqey080<8:W3+bta&{l$ka>!ws-dsae6&~nhiuz Mrwa[aoanV}ySjPtlr\|jt;>7937X> gsd-vc)`d9$|~"ixdb3-saebp}%FxlPdhde[rtXzmUa}Qwos>4:6><]9%l~k }f.eo4+qu'n}oo< xdbg{p*Kt}kUoekhPws]q`ZrjxVrd~161399V4*aun'xm#jb?.vp,crbd9'}oohv{/LqvfZbnnoU|~R|k_uos[}iu4049j6[?/fpe*w`(oe:%{!hwea2*rbdmq~$hdhi_vp\vaYsey6;2?h4U1-dvc(un&mg<#y}/fugg4(pljosx"y}_ecweZeh}g~TeR>=f:W3+bta&{l$ka>!ws-dsae6&~nhiuz ws]geqgXkfexRgP1228Q5)`zo$yj"ic0/uq+bqck8$|hnkwt.uq[agsiVidyczPi^336c=R8&myj#|i/fn3*rt(o~nh=#ykcdzw+rtXlh~jSnaznu]j[74a3\:$kh!rg-dh5(pz&m|hn?!weaf|q)pzVnjxlQlotlw[lY4:o1^<"i}f/pe+bj7&~x$kzjl1/ugg`~s'~xThlzn_bmvjqYnW=8m7X> gsd-vc)`d9$|~"ixdb3-saebp}%|~Rjnt`]`kphsW`U>>k5Z0.eqb+ta'nf;"z| gvf`5+qcklr#z|Pd`vb[firf}UbS;<i;T2,cw`)zo%l`= xr.et`f7)minty!xr^fbpdYdg|dSdQ82g9V4*aun'xm#jb?.vp,crbd9'}oohv{/vp\`drfWje~byQf_90e?P6(o{l%~k!hl1,tv*aplj;%{imjxu-tvZbf|hUhcx`{_h]:7==R8&myj#|i/fn3*rt(o~nh=#ykcdzw+rtXlh~jSnaznu]j[dbc89:;0<0<8:W3+bta&{l$ka>!ws-dsae6&~nhiuz ws]geqgXkfexRgPaef3456;:7937X> gsd-vc)`d9$|~"ixdb3-saebp}%|~Rjnt`]`kphsW`Ujhi>?01>0:6><]9%l~k }f.eo4+qu'n}oo< xdbg{p*quWmkmRm`uov\mZgcl9:;<1:1399V4*aun'xm#jb?.vp,crbd9'}oohv{/vp\`drfWje~byQf_`fg45674<4856[?/fpe*w`(oe:%{!hwea2*rbdmq~${Qkauc\gjsi|VcTmij?012?1;7402_;#j|i.sd,ci6){%l{im>.vf`a}r({UomyoPcnwmpZoXimn;<=>36?1:?P6(o{l%~k!hl1,tv*aplj;%{imjxu-tvZbf|hUhcx`{_h]b`a67896=2<=7;T2,cw`)zo%l`= xr.et`f7)minty!xr^fbpdYdg|dSdQnde2345:06:30Y=!hrg,qb*ak8'}y#jykc0,t`fc|&}ySio{a^alqkrXaVkoh=>?0=5=56><]9%l~k }f.eo4+qu'n}oo< xdbg{p*quWmkmRm`uov\mZgcl9:;<161389V4*aun'xm#jb?.vp,crbd9'}oohv{/vp\`drfWje~byQf_`fg4567414:?55Z0.eqb+ta'nf;"z| gvf`5+qcklr#z|Pd`vb[firf}UbSljk01238<8382_;#j|i.sd,ci6){%l{im>.vf`a}r({UomyoPcnwmpZoXimn;<=>39?]PS5YT_9;o7X> gsd-vc)`d9$|~"|nm^uq[`hXa8887X> gsd-vc)`d9$|~"ynup,Ifirf}Uhcx`{259V4*aun'xm#jb?.vp,suhsz&Ghcx`{_bmvjq75<2_;#j|i.sd,ci6){%||cz}/LalqkrXkfex?<;;T2,cw`)zo%l`= xr.usjqt(Eje~byQlotlw772<]9%l~k }f.eo4+qu'~zex!BcnwmpZeh}g~?>95Z0.eqb+ta'nf;"z| wqlwv*Kdg|dSnaznu710>S7'nxm"h gm2-sw)pxg~y#@m`uov\gjsi|?8?7X> gsd-vc)`d9$|~"ynup,Ifirf}Uhcx`{7368Q5)`zo$yj"ic0/uq+rvi|{%Fob{at^alqkr?:=1^<"i}f/pe+bj7&~x${}`{r.O`kphsWje~by7=9:W3+bta&{l$ka>!ws-ttkru'DidyczPcnwmpZe~4949o6[?/fpe*w`(oe:%{!xpovq+Heh}g~Tob{at^az858Xz}827X> gsd-vc)`d9$|~"ynup,Ifirf}Uhcx`{_b{?5;4d3\:$kh!rg-dh5(pz&}{by| MbmvjqYdg|dSnw31?]qp7?<]9%l~k }f.eo4+qu'~zex!BcnwmpZeh}g~Tot2=>3a8Q5)`zo$yj"ic0/uq+rvi|{%Fob{at^alqkrXkp692R|{289V4*aun'xm#jb?.vp,suhsz&Ghcx`{_bmvjqYdq595>n5Z0.eqb+ta'nf;"z| wqlwv*Kdg|dSnaznu]`}959W{~956[?/fpe*w`(oe:%{!xpovq+Heh}g~Tob{at^az8185k2_;#j|i.sd,ci6){%||cz}/LalqkrXkfexRmv<5<\vq4>3\:$kh!rg-dh5(pz&}{by| MbmvjqYdg|dSnw35?0`?P6(o{l%~k!hl1,tv*qwf}x$Anaznu]`kphsWjs793Q}t3;8Q5)`zo$yj"ic0/uq+rvi|{%Fob{at^alqkrXkp6=2?m4U1-dvc(un&mg<#y}/vrmpw)JkfexRm`uov\g|:16Vx>45Z0.eqb+ta'nf;"z| wqlwv*Kdg|dSnaznu]`}919:j1^<"i}f/pe+bj7&~x${}`{r.O`kphsWje~byQly=5=[wr512_;#j|i.sd,ci6){%||cz}/LalqkrXkfexRmv<9<1g>S7'nxm"h gm2-sw)pxg~y#@m`uov\gjsi|Vir050Pru0b?P6(o{l%~k!hl1,tv*qwf}x$Anaznu]`kphsWqey0=0=a:W3+bta&{l$ka>!ws-ttkru'DidyczPcnwmpZ~hz5;5>l5Z0.eqb+ta'nf;"z| wqlwv*Kdg|dSnaznu]{kw:56;k0Y=!hrg,qb*ak8'}y#z~ats-Ngjsi|VidyczPxnp?7;4f3\:$kh!rg-dh5(pz&}{by| MbmvjqYdg|dSua}<5<1e>S7'nxm"h gm2-sw)pxg~y#@m`uov\gjsi|Vrd~1;12`9V4*aun'xm#jb?.vp,suhsz&Ghcx`{_bmvjqYg{6=2?o4U1-dvc(un&mg<#y}/vrmpw)JkfexRm`uov\|jt;?78j7X> gsd-vc)`d9$|~"ynup,Ifirf}Uhcx`{_ymq8=85i2_;#j|i.sd,ci6){%||cz}/LalqkrXkfexRv`r=;=6a=R8&myj#|i/fn3*rt(yd~"Clotlw[firf}Usc26>^pw5c=R8&myj#|i/fn3*rt(yd~"m`uov?4;7a3\:$kh!rg-dh5(pz&}{by| cnwmp9799o1^<"i}f/pe+bj7&~x${}`{r.alqkr;:7;m7X> gsd-vc)`d9$|~"ynup,gjsi|595=k5Z0.eqb+ta'nf;"z| wqlwv*eh}g~783?i;T2,cw`)zo%l`= xr.usjqt(kfex1;11g9V4*aun'xm#jb?.vp,suhsz&idycz36?3e?P6(o{l%~k!hl1,tv*qwf}x$ob{at=5=5c=R8&myj#|i/fn3*rt(yd~"m`uov?<;7a3\:$kh!rg-dh5(pz&}{by| cnwmp9?99l1^<"i}f/pe+bj7&~x${}`{r.alqkrX88o0Y=!hrg,qb*ak8'}y#z~ats-`kphsW8;n7X> gsd-vc)`d9$|~"ynup,gjsi|V8:i6[?/fpe*w`(oe:%{!xpovq+firf}U8=h5Z0.eqb+ta'nf;"z| wqlwv*eh}g~T8<k4U1-dvc(un&mg<#y}/vrmpw)dg|dS8?j;T2,cw`)zo%l`= xr.usjqt(kfexR8>e:W3+bta&{l$ka>!ws-ttkru'je~byQ81d9V4*aun'xm#jb?.vp,suhsz&idyczP80g8Q5)`zo$yj"ic0/uq+rvi|{%hcx`{_801?P6(o{l%~k!hl1,tv*qwf}x$ob{at^f28585:2_;#j|i.sd,ci6){%||cz}/bmvjqYc95;5>?5Z0.eqb+ta'nf;"z| wqlwv*eh}g~Th<2=>308Q5)`zo$yj"ic0/uq+rvi|{%hcx`{_e3?7;453\:$kh!rg-dh5(pz&}{by| cnwmpZb64=49>6[?/fpe*w`(oe:%{!xpovq+firf}Uo=1;1239V4*aun'xm#jb?.vp,suhsz&idyczPd0>5:74<]9%l~k }f.eo4+qu'~zex!lotlw[a7;?7897X> gsd-vc)`d9$|~"ynup,gjsi|Vn:050=2:W3+bta&{l$ka>!ws-ttkru'je~byQk1=;=64=R8&myj#|i/fn3*rt(yd~"m`uov\`4Y7:81^<"i}f/pe+bj7&~x${}`{r.alqkrXl8U:><5Z0.eqb+ta'nf;"z| wqlwv*eh}g~Th<Q=209V4*aun'xm#jb?.vp,suhsz&idyczPd0]064=R8&myj#|i/fn3*rt(yd~"m`uov\`4Y3:81^<"i}f/pe+bj7&~x${}`{r.alqkrXl8U>><5Z0.eqb+ta'nf;"z| wqlwv*eh}g~Th<Q9209V4*aun'xm#jb?.vp,suhsz&idyczPd0]464=R8&myj#|i/fn3*rt(yd~"m`uov\`4Y?:81^<"i}f/pe+bj7&~x${}`{r.alqkrXl8U2>?5Z0.eqb+ta'nf;"z| wqlwv*eh}g~Th?2?>308Q5)`zo$yj"ic0/uq+rvi|{%hcx`{_e0?5;453\:$kh!rg-dh5(pz&}{by| cnwmpZb54;49>6[?/fpe*w`(oe:%{!xpovq+firf}Uo>1=1239V4*aun'xm#jb?.vp,suhsz&idyczPd3>7:74<]9%l~k }f.eo4+qu'~zex!lotlw[a4;=7897X> gsd-vc)`d9$|~"ynup,gjsi|Vn90;0=2:W3+bta&{l$ka>!ws-ttkru'je~byQk2=5=67=R8&myj#|i/fn3*rt(yd~"m`uov\`7:?6;80Y=!hrg,qb*ak8'}y#z~ats-`kphsWm8753<>;T2,cw`)zo%l`= xr.usjqt(kfexRj=_102?P6(o{l%~k!hl1,tv*qwf}x$ob{at^f1[4463\:$kh!rg-dh5(pz&}{by| cnwmpZb5W;8:7X> gsd-vc)`d9$|~"ynup,gjsi|Vn9S><>;T2,cw`)zo%l`= xr.usjqt(kfexRj=_502?P6(o{l%~k!hl1,tv*qwf}x$ob{at^f1[0463\:$kh!rg-dh5(pz&}{by| cnwmpZb5W?8:7X> gsd-vc)`d9$|~"ynup,gjsi|Vn9S:<>;T2,cw`)zo%l`= xr.usjqt(kfexRj=_902?P6(o{l%~k!hl1,tv*qwf}x$ob{at^f1[<713\:$kh!rg-nah)cg|~TeR>>6:W3+bta&{l$ahc dnww[lY69>1^<"i}f/pe+hcj'me~xRgP1134?P6(o{l%~k!bel-gkprXaV;:=:5Z0.eqb+ta'dof#iazt^k\57703\:$kh!rg-nah)cg|~TeR?<169V4*aun'xm#`kb/emvpZoX9=;<7X> gsd-vc)jmd%ocxzPi^3652=R8&myj#|i/lgn+air|VcT=;?8;T2,cw`)zo%fi`!kotv\mZ709?1^<"i}f/pe+hcj'me~xRgP2048Q5)`zo$yj"cjm.flqqYnW:;=7X> gsd-vc)jmd%ocxzPi^622>S7'nxm"h mdo,`jssW`U>=;5Z0.eqb+ta'dof#iazt^k\240<]9%l~k }f.ofi*bh}}UbS:?9;T2,cw`)zo%fi`!kotv\mZ>6>2_;#j|i.sd,i`k(lfSdQ6189V4*aun'xm#`kb/emvpZkbe5:5=l5Z0.eqb+ta'dof#iazt^ofi97768k0Y=!hrg,qb*kbe&ndyyQbel>25;7f3\:$kh!rg-nah)cg|~Tahc313<2e>S7'nxm"h mdo,`jssWdof0<=11`9V4*aun'xm#`kb/emvpZkbe5;?2<o4U1-dvc(un&gna"j`uu]nah:6=7;j7X> gsd-vc)jmd%ocxzPmdo?5386i2_;#j|i.sd,i`k(lfS`kb<05=5<=R8&myj#|i/lgn+air|Vgna1?1189V4*aun'xm#`kb/emvpZkbe585=45Z0.eqb+ta'dof#iazt^ofi959901^<"i}f/pe+hcj'me~xRcjm=6=5<=R8&myj#|i/lgn+air|Vgna1;1189V4*aun'xm#`kb/emvpZkbe5<5=45Z0.eqb+ta'dof#iazt^ofi919901^<"i}f/pe+hcj'me~xRcjm=:=5<=R8&myj#|i/lgn+air|Vgna1716d9V4*aun'xm#`kb/f`n*bdjo'miajo!nfg`g+djo&hggRcjm^efj`tf|fx$zlbfd/appw)uidfdc}U?]/pbi+t(~;Uecd`ft/pbi*bw91r:4#|nm0`8Q5)`zo$yj"cjm.vntZtfeVxoSh`>c:W3+bta&{l$ahc tlr\vdkXzmUnb<?<;T2,cw`)zo%ym`Q}d^gm52=R8&myj#|i/scn[wc`g|~Tic?<;T2,cw`)zo%ym`Qxr^gm5a=R8&myj#|i/sqwfim(zmUyyQnssgd65=R8&myj#|i/sqwfim(zmUyyQnssgd[a7582_;#j|i.sd,vvredb%yhR||t^cpv`aXl;;h7X> gsd-vc)u{}hgg"|k_sqw[fijj8n0Y=!hrg,qb*tt|kf`#jPrrv\gjke98o0Y=!hrg,qb*tt|kf`#jPrrv\v`a;87;n7X> gsd-vc)u{}hgg"|k_sqw[wc`484:i6[?/fpe*w`(zz~i`f!}d^pppZtbo585=i5Z0.eqb+ta'{ynae re]qwqYumnU;=i5Z0.eqb+ta'{ynae re]qwqYumnU:=i5Z0.eqb+ta'{ynae re]qwqYumnU9=i5Z0.eqb+ta'{ynae ws]qwqYf{{ol>=5Z0.eqb+ta'{ynae ws]qwqYf{{olSi?=0:W3+bta&{l$~~zmlj-tvZtt|Vkx~hiPd33`?P6(o{l%~k!}su`oo*quW{ySnabb0f8Q5)`zo$yj"||tcnh+rtXzz~Tobcm10g8Q5)`zo$yj"||tcnh+rtXzz~T~hi30?3f?P6(o{l%~k!}su`oo*quW{ySkh<0<2`>S7'nxm"h rrvahn)pzVxxxR|jg^22`>S7'nxm"h rrvahn)pzVxxxR|jg^3b?PUBZVKGEL]l;TQFVZPN[@HGI>5YCB;8RLCPW]S[I>5XE@18S@De3^XBXHQIISQWg>QUA]OTABJJ_@a8SWOSMVGDHHQM1e9[MIOIP$RON->!1!QWQG&7&8*J_NGF5:ZLVF_13QY_@DL8;YQW[BHC?2RXXRXLCc9[[FIUMVCEJB84Xe`\Ma`<PmbT\gbVdppmjh682RoaRCnjnpUawungg;;7Ujb_LkmkwPbzzcdbn5nllmppZcjx}si7lbborv\bpjk>2hjof{d:`bgnswWdkygh|<;bnh`>bf|hUhcx`{(1+g?agsiVidycz'1(g8`drfWje~by&>0(f8`drfWje~by&=)e9geqgXkfex%=&d:fbpdYdg|d$9'k;ecweZeh}g~#9$j4d`vb[firf}"=%i5kauc\gjsi|!="h6jnt`]`kphs 1#o7io{a^alqkr/1 n0hlzn_bmvjq:768:0hlzn_bmvjq:683:5;6jmiugqv3=cag";%;5kio*2-2=cag":<$94dhl+54/03mce$<<&7:fjj-74!>1oec&>4(58`lh/9<#<7iga(04*3>bnf!;<%;5kio*1-3=cag"8%;5kio*7-3=cag">%;5kio*5-3=cag"<%;5kio*;-3=cag"2%;5kio>3:2=cag6:<394dhl?54803mce0<<17:fjj9746>1oec2>4?58`lh;9<4<7iga<04==>bnf5;<6=08;ekm8419>2nbb1?16:fjj949>2nbb1=16:fjj929>2nbb1;16:fjj909>2nbb1916:fjj9>9>2nbb1717:flqq.7!>1ocxz'1(:8`jss 8:"46j`uu*25,><lf$<<&8:flqq.6; 20hb{{(06*<>bh}}":9$64dnww,40.02ndyy&>7(58`jss ;#<7iazt)1*3>bh}}"?%:5kotv+1,1<lf$;'8;emvp-1.?2ndyy&7)69gkpr/1 =0hb{{<1<;?air|5;;255kotv?548?3me~x1?=>99gkpr;9:437iazt=37:==cg|~7=807;emvp9716h1ocxz31683:==cg|~7=:08;emvp979?2ndyy2=>69gkpr;;7=0hb{{<5<4?air|5?5;6j`uu>5:2=cg|~7;394dnww8=803me~x1718:ggmc4iom?0i`~{y208bl`hWnoeio{os]u0Z5+(Qcgecv/CNPF$Bcim{kc.>0/3-46733ocmcRvcny]2O}7?W;igg><4fhdl[}jipV;@t<6P2bnh(coagVmnbh|ntnp\r1Y4$GEEI!@@ND1`=>`nnfUs`cvP1Jz2<Z4ddb&mekaPgdlfvdrhzV|?S>"tc^jbwZoi|Vigg0>#c^jbwZuu{}7; nQ}d^dqat;6$jUcm~Q}d^fbpdYdg|d1<"l_ekm[roc|a7:4!mPh`q\swYci}kTob{at<3/gZ`rdeUm`li|_sqw[sgk58&hSdcldofjqgsafdTxt~j=3.`[pubWlgiiijjd^pfc86+kV}ySk|jq<3/gZstmVndyyQ}su?2(fYrfmoyjaax_mmt95*dWakxSbxjrgnls86+kVzyiaand^nbp`hdq4:'oRj`uu]tmaro582'oRc|gnl\rdj:9%iT~iQkeqvk9465<%iTdl}Puoffvcjh4:'oRfns^coijusWog`0>#c^jbwZtt|4;'oRjnt`]`kphsW~coxe3>1-a\lduX{Ujof3?,b]vw`Ybkj7; nQlololjZekgja6<!mPws]bgnYkg~7; nQ}d^rmpwYpam~c1<>#c^wpaZ`pn}UomyoPcnwmp87+kVbjRocmnqw[`kw|p7; nQ}d^fbpdYdg|dSzgkti?25)eXgoyjaax_mmt95*dW~xT|cz}_vkgpm;68%iT|ah_dosp|Ysqyo6<!mPws]geqgXkfexRyfduj>54*dWyxn`bok_sgdw87+kVndyyQ}su]uei;7$jUcm~Qkauc\gjsi|4:'oR~}of]eqijX|axneQaefcwaZpfd4;;>?"l_vp\``vs`4;;>9"l_qplcZcjx}sTxe|jsi]mabgsmV|j`0;#c^rqkbYbey~rSyf}erj\evubz}U}ma3;,b]kevYqieco1="l_qplcZ`rdeUdk|h^cpw`tsWkg1<>=3-aliuiimg~Tblcj=gkekZ~kfqU:Gu?7_3aoo)eX~hfbhRb`w<2/gZvuadUmekaPtxrf94m91&hS}|`g^dvhiYsqyo6<!mPmdolv|Ysqyo6=!s=e:djbjYdgrT=Fv>8^0`hnYaaoeTkh`jr`vlvZp3W:UsyQ>4:dvhi1<ag~Toae7;oe`fpokl11dzh|ilnub?uthoVof|yw>4:rqkbYbey~rSyf}erj+4,733yxdkRkbpu{\pmtb{a":%<:4psmd[`kw|pUdk|h)0*51=wzfmTi`~{y^vkv`uo :#:86~}of]fiur~W}byi~f'4(37?uthoVof|ywPtipfwm.2!8>0|ah_dosp|Ys`{oxd%8&159svjaXmdzuRzgrdqk,2/6<2zycjQjmqvz[qnumzb#4$?;;qplcZcjx}sTxe|jsi*:-40<x{elShctx]wlwct`531<3?m;qplcZcjx}sTxe|jsi]bwvcu|!:"=o5rne\ahvsqV~c~h}g_`qpawr/9 ;i7}|`g^gntqX|axneQnsrgqp-4.9k1{~biPelrw}ZrozlycSl}|esv+7,7e3yxdkRkbpu{\pmtb{aUj~k}t)6*5g=wzfmTi`~{y^vkv`uoWhyxiz'5(3a?uthoVof|ywPtipfwmYf{zoyx%8&1c9svjaXmdzuRzgrdqk[dutm{~#;$?m;qplcZcjx}sTxe|jsi]bwvcu|!2"=o5rne\ahvsqV~c~h}g_`qpawr/1 ;o7}|`g^gntqX|axneQnsrgqp9?=87;i7}|`g^gntqX|axneQaefcwa-6.9k1{~biPelrw}ZrozlycSckhaug+5,7e3yxdkRkbpu{\pmtb{aUeijo{e)0*5g=wzfmTi`~{y^vkv`uoWgolmyk'3(3a?uthoVof|ywPtipfwmYimnki%:&1c9svjaXmdzuRzgrdqk[kc`i}o#9$?m;qplcZcjx}sTxe|jsi]mabgsm!<"=o5rne\ahvsqV~c~h}g_ogdeqc/? ;i7}|`g^gntqX|axneQaefcwa->.9k1{~biPelrw}ZrozlycSckhaug+=,7c3yxdkRkbpu{\pmtb{aUeijo{e=;94;?<x{elSk{cl018twi`Wog`Rzgrdqk,5/6;2zycjQiumn\pmtb{a":%<=4psmd[cskdV~c~h}g(3+27>vugnUmyabPtipfwm.4!890|ah_gwohZrozlyc$9'>3:rqkbYa}efTxe|jsi*6-45<x{elSk{cl^vkv`uo ?#:?6~}of]eqijX|axne&8)018twi`Wog`Rzgrdqk,=/6;2zycjQiumn\pmtb{a"2%<;4psmd[cskdV~c~h}g<883:4g<x{elSk{cl^vkv`uoWhyxiz'0(3b?uthoVl~`aQ{hsgplZgt{lx$<'>a:rqkbYa}efTxe|jsi]bwvcu|!8"=l5rne\bpjkW}byi~fParqfvq.4!8k0|ah_gwohZrozlycSl}|esv+0,7f3yxdkRhzlm]wlwct`Vkxh|{(4+2e>vugnUmyabPtipfwmYf{zoyx%8&1`9svjaXn|fgSyf}erj\evubz}"<%<o4psmd[cskdV~c~h}g_`qpawr/0 ;j7}|`g^dvhiYs`{oxdRo|sdpw,</6k2zycjQiumn\pmtb{aUj~k}t=;94;7f3yxdkRhzlm]wlwct`Vdnklzj(1+2e>vugnUmyabPtipfwmYimnki%?&1`9svjaXn|fgSyf}erj\j`af|l"9%<o4psmd[cskdV~c~h}g_ogdeqc/; ;j7}|`g^dvhiYs`{oxdR`jg`vf,1/6i2zycjQiumn\pmtb{aUeijo{e)7*5d=wzfmTjxbc_ujqavnXflmjxh&9)0c8twi`Wog`Rzgrdqk[kc`i}o#;$?n;qplcZ`rdeUdk|h^lfcdrb 1#:m6~}of]eqijX|axneQaefcwa-?.9j1{~biPftno[qnumzbTbhintd>:>5813{nToae>0:pg[agsiVidycz'0(33?wbXlh~jSnaznu*2-47<zmUomyoPcnwmp-77!8:0~iQkauc\gjsi|!8"==5}d^fbpdYdg|d$>'>0:pg[agsiVidycz'4(33?wbXlh~jSnaznu*6-46<zmUomyoPcnwmp-0.991yhRjnt`]`kphs >#:<6|k_ecweZeh}g~#4$??;sf\`drfWje~by&6)028vaYci}kTob{at=2=56=ulVnjxlQlotlw846=87;:7jPd`vb[firf}6:<3??;sf\`drfWje~by2>>028vaYci}kTob{at=0=55=ulVnjxlQlotlw868682xoSio{a^alqkr;<7;;7jPd`vb[firf}6>2<>4re]geqgXkfex181119q`Zbf|hUhcx`{<6<24>tcWmkmRm`uov?<;773{nThlzn_bmvjq:>6<1yhRka6:pg[wus;2xxx:5|bhvfvw2<{{y86z}ud;8qkbbzofd{85yamkg2>quWhi`:6y}_bnh55=pzVnjxlQlotlw,5/682}ySio{a^alqkr/9 ;:7z|Pd`vb[firf}":<$??;vp\`drfWje~by&=)028swYci}kTob{at)1*55=pzVnjxlQlotlw,1/682}ySio{a^alqkr/= ;;7z|Pd`vb[firf}"=%<>4ws]geqgXkfex%9&119tvZbf|hUhcx`{(9+24>quWmkmRm`uov+=,773~xThlzn_bmvjq:76890{Qkauc\gjsi|5;;6=0>1:uq[agsiVidycz311<24>quWmkmRm`uov?5;773~xThlzn_bmvjq:568:0{Qkauc\gjsi|595==5xr^fbpdYdg|d090>0:uq[agsiVidycz35?33?rtXlh~jSnaznu>5:46<{UomyoPcnwmp919991|~Rjnt`]`kphs414:<6y}_ecweZeh}g~753;4ws]fj3=pzVxxxpNOpeg2?EF93L187?tS4g90ad=03;8>ij>2;1;37?|f==h6<5a46f90>"3?h0?;95rS4a90ad=03;8>ij>2;1;37?<[8;=69k;:18277bc9;084:<n;R7`>1c3290:??jk1380<24e3m>oi7>51;3xW0c=<mh147?<2ef26?5??;30zY?75;295?7=9l>p_8k54e`9<?74:mn:>7=773;8 10b28;<7[:8b;0xq444281~=?:50:'52b=:;1i8ik50;62>6<39rB?:n5U528745=9;0:57?7:|&2<d<3ll1/8:754ef8m0252900c8:j:18'52`==<20b<9j:198k031290/=:h554:8j41b2810c8;::18'52`==<20b<9j:398k033290/=:h554:8j41b2:10c8;<:18'52`==<20b<9j:598k035290/=:h554:8j41b2<10c8;>:18'52`==<20b<9j:798k037290/=:h554:8j41b2>10c8:i:18'52`==<20b<9j:998k02c290/=:h554:8j41b2010c8:l:18'52`==<20b<9j:`98k04c290/=:h55258j41b2910c8=::18'52`==:=0b<9j:098k053290/=:h55258j41b2;10c8=<:18'52`==:=0b<9j:298k055290/=:h55258j41b2=10c8=>:18'52`==:=0b<9j:498k057290/=:h55258j41b2?10c8<i:18'52`==:=0b<9j:698k04b290/=:h55258j41b2110c8<l:18'52`==:=0b<9j:898k04e290/=:h55258j41b2h10e88<:188k1c52900c9jl:188m02e2900e8:;:188k1da290/=:h54e28j41b2910c9lj:18'52`=<m:0b<9j:098k1dc290/=:h54e28j41b2;10c9ll:18'52`=<m:0b<9j:298k1de290/=:h54e28j41b2=10c9ln:18'52`=<m:0b<9j:498k1d>290/=:h54e28j41b2?10c9l7:18'52`=<m:0b<9j:698k1e0290/=:h54e28j41b2110c9m9:18'52`=<m:0b<9j:898k1e2290/=:h54e28j41b2h10c9m;:18'52`=<m:0b<9j:c98k1e4290/=:h54e28j41b2j10c9m=:18'52`=<m:0b<9j:e98k1e6290/=:h54e28j41b2l10c9m?:18'52`=<m:0b<9j:g98k1d0290/=:h54e28j41b28:07b:m6;29 41a2=n;7c?8e;32?>o31h0;6)?8f;6bf>h6?l0;76g;9883>!70n3>jn6`>7d82?>o3110;6)?8f;6bf>h6?l0976g;9683>!70n3>jn6`>7d80?>o31?0;6)?8f;6bf>h6?l0?76g;9483>!70n3>jn6`>7d86?>o31=0;6)?8f;6bf>h6?l0=76g;9283>!70n3>jn6`>7d84?>o3i;0;6)?8f;6bf>h6?l0376g;a083>!70n3>jn6`>7d8:?>o3i90;6)?8f;6bf>h6?l0j76g;9g83>!70n3>jn6`>7d8a?>o31l0;6)?8f;6bf>h6?l0h76g;9e83>!70n3>jn6`>7d8g?>o31j0;6)?8f;6bf>h6?l0n76g;9c83>!70n3>jn6`>7d8e?>o31;0;6)?8f;6bf>h6?l0:<65f48394?"6?o0?mo5a16g954=<a<8j6=44b54g>5<6290;wE:9c:&2<d<3>m1d=:m50;9~ff7=83;1<7>tH54`?!7?i3i:7bm?:188yg35290257?m6;3f0~N3>j1Q9>4>6za956<6:3;;6<?5e;3:>g<603l1h7?>:0195<<6:3i1=54>0;d9a?b=j3w/=5o54d38 4742kl0(8954ed8 0b=<l:0(<98:05a?l33;3:17b;?8;29?l33>3:17b:8e;29?j3313:17d:71;29?l2aj3:1(<9i:5d`?k70m3:07d:ia;29 41a2=lh7c?8e;38?l2a13:1(<9i:5d`?k70m3807d:i8;29 41a2=lh7c?8e;18?l2a?3:1(<9i:5d`?k70m3>07d:i6;29 41a2=lh7c?8e;78?l2a=3:1(<9i:5d`?k70m3<07d:i4;29 41a2=lh7c?8e;58?l2a;3:1(<9i:5d`?k70m3207d:i2;29 41a2=lh7c?8e;;8?l33:3:17b:j5;29?j33m3:1(<9i:47;?k70m3:07b;:6;29 41a2<?37c?8e;38?j32=3:1(<9i:47;?k70m3807b;:4;29 41a2<?37c?8e;18?j32;3:1(<9i:47;?k70m3>07b;:2;29 41a2<?37c?8e;78?j3293:1(<9i:47;?k70m3<07b;:0;29 41a2<?37c?8e;58?j33n3:1(<9i:47;?k70m3207b;;d;29 41a2<?37c?8e;;8?j33k3:1(<9i:47;?k70m3k07b;=d;29 41a2<9<7c?8e;28?j34=3:1(<9i:414?k70m3;07b;<4;29 41a2<9<7c?8e;08?j34;3:1(<9i:414?k70m3907b;<2;29 41a2<9<7c?8e;68?j3493:1(<9i:414?k70m3?07b;<0;29 41a2<9<7c?8e;48?j35n3:1(<9i:414?k70m3=07b;=e;29 41a2<9<7c?8e;:8?j35k3:1(<9i:414?k70m3307b;=b;29 41a2<9<7c?8e;c8?l3503:1(<9i:40:?k70m3:07d;=7;29 41a2<827c?8e;38?l35>3:1(<9i:40:?k70m3807d;=5;29 41a2<827c?8e;18?l35<3:1(<9i:40:?k70m3>07d;=3;29 41a2<827c?8e;78?l35:3:1(<9i:40:?k70m3<07d;=1;29 41a2<827c?8e;58?l3583:1(<9i:40:?k70m3207d;>f;29 41a2<827c?8e;;8?l31;3:17b:75;29 41a2=2m7c?8e;28?j2?l3:1(<9i:5:e?k70m3;07b:7c;29 41a2=2m7c?8e;08?j2?j3:1(<9i:5:e?k70m3907b:7a;29 41a2=2m7c?8e;68?j2?13:1(<9i:5:e?k70m3?07b:78;29 41a2=2m7c?8e;48?j2??3:1(<9i:5:e?k70m3=07b:76;29 41a2=2m7c?8e;:8?j2?<3:1(<9i:5:e?k70m3307b:73;29 41a2=2m7c?8e;c8?j2b:3:17b:kc;29?l36:3:1(<9i:430?k70m3:07d;>1;29 41a2<;87c?8e;38?l3683:1(<9i:430?k70m3807d;?f;29 41a2<;87c?8e;18?l37m3:1(<9i:430?k70m3>07d;?d;29 41a2<;87c?8e;78?l37k3:1(<9i:430?k70m3<07d;?b;29 41a2<;87c?8e;58?l37i3:1(<9i:430?k70m3207d;?9;29 41a2<;87c?8e;;8?l33j3:17d:j3;29?l2?:3:17d;94;29?j33=3:17b;;a;29?j20n3:17b;;8;29?l33<3:17b:mf;29 41a2=n;7c?8e;28?j2em3:1(<9i:5f3?k70m3;07b:md;29 41a2=n;7c?8e;08?j2ek3:1(<9i:5f3?k70m3907b:mb;29 41a2=n;7c?8e;68?j2ei3:1(<9i:5f3?k70m3?07b:m9;29 41a2=n;7c?8e;48?j2e03:1(<9i:5f3?k70m3=07b:l7;29 41a2=n;7c?8e;:8?j2d>3:1(<9i:5f3?k70m3307b:l5;29 41a2=n;7c?8e;c8?j2d<3:1(<9i:5f3?k70m3h07b:l3;29 41a2=n;7c?8e;a8?j2d:3:1(<9i:5f3?k70m3n07b:l1;29 41a2=n;7c?8e;g8?j2d83:1(<9i:5f3?k70m3l07b:m7;29 41a2=n;7c?8e;33?>i3j?0;6)?8f;6g4>h6?l0:=65f4g294?"6?o0?j<5a16g94>=n<ll1<7*>7g87b4=i9>o1=65f4dg94?"6?o0?j<5a16g96>=n<ln1<7*>7g87b4=i9>o1?65f4da94?"6?o0?j<5a16g90>=n<lh1<7*>7g87b4=i9>o1965f4dc94?"6?o0?j<5a16g92>=n<l31<7*>7g87b4=i9>o1;65f4d:94?"6?o0?j<5a16g9<>=n<l=1<7*>7g87b4=i9>o1565f48c94?"6?o0?mo5a16g94>=n<031<7*>7g87eg=i9>o1=65f48:94?"6?o0?mo5a16g96>=n<0=1<7*>7g87eg=i9>o1?65f48494?"6?o0?mo5a16g90>=n<0?1<7*>7g87eg=i9>o1965f48694?"6?o0?mo5a16g92>=n<091<7*>7g87eg=i9>o1;65f4`094?"6?o0?mo5a16g9<>=n<h;1<7*>7g87eg=i9>o1565f4`294?"6?o0?mo5a16g9e>=n<0l1<7*>7g87eg=i9>o1n65f48g94?"6?o0?mo5a16g9g>=n<0n1<7*>7g87eg=i9>o1h65f48a94?"6?o0?mo5a16g9a>=n<0h1<7*>7g87eg=i9>o1j65f48094?"6?o0?mo5a16g955=<a=3:6=4+16d90dd<f8=n6<?4;h6;4?6=3`?:h7>5$05e>07b3g;<i7>4;h72g?6=,8=m68?j;o34a?7<3`?:n7>5$05e>07b3g;<i7<4;h72e?6=,8=m68?j;o34a?5<3`?:57>5$05e>07b3g;<i7:4;h72<?6=,8=m68?j;o34a?3<3`?:;7>5$05e>07b3g;<i784;h722?6=,8=m68?j;o34a?1<3`?:97>5$05e>07b3g;<i764;h720?6=,8=m68?j;o34a??<3`?;:7>5$05e>0603g;<i7>4;h731?6=,8=m68>8;o34a?7<3`?;87>5$05e>0603g;<i7<4;h737?6=,8=m68>8;o34a?5<3`?;>7>5$05e>0603g;<i7:4;h735?6=,8=m68>8;o34a?3<3`?;<7>5$05e>0603g;<i784;h6eb?6=,8=m68>8;o34a?1<3`>mi7>5$05e>0603g;<i764;h6e`?6=,8=m68>8;o34a??<3f>n:7>5;n6:4?6=3`?9m7>5;c643?6=93:1<v*>8`8`5>N3??1C8;m4ob294?=zj==36=4>:183!7?i3>=h6F;779K03e<g8=h6=44}c66=?6=;3:1<v*>8`8a<>N3??1C8;m4H428 4462<><7)mi:39j11<722c>j7>5;n3;5?6=3th?:94?:283>5}#91k1n55G4648L10d3A?;7)?=1;773>"dn380e8:50;9j1c<722e:4<4?::a00>=8391<7>t$0:b>g><@===7E:9c:J64>"6:80>8:5+cg81?l332900e8h50;9l5=7=831vn98=:186>5<7s-;3m7lk;I642>N3>j1C9=5+1339111<,jl1>6g:4;29?l312900e8h50;9j5=6=831d=5?50;9~f10429086=4?{%3;e?d?3A><:6F;6b9K15=#9;;19994$bd96>o2<3:17d;i:188k4>62900qo::7;291?6=8r.:4l4md:J733=O<?i0D8>4$002>0203-im6?5f5583>>o2>3:17d;i:188m4>72900c<6>:188yg2193:187>50z&2<d<ek2B?;;5G47a8 f`=:2c>87>5;h7e>5<<a82;6=44o0:2>5<<uk>=<7>54;294~"60h0io6F;779K03e<,jl1>6g:4;29?l3a2900e<6?:188k4>62900qo::f;290?6=8r.:4l4mc:J733=O<?i0(nh52:k60?6=3`?m6=44i0:3>5<<g82:6=44}c65e?6=<3:1<v*>8`8ag>N3??1C8;m4$bd96>o2<3:17d;i:188m4>72900c<6>:188yg2113:187>50z&2<d<ek2B?;;5G47a8 f`=:2c>87>5;h7e>5<<a82;6=44o0:2>5<<uk9;>7>54;294~"60h0io6F;779K03e<,jl1;6g:4;29?l3a2900e<6?:188k4>62900qo<6e;291?6=8r.:4l4mb:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=n91:1<75`19394?=zj;3m6=4::183!7?i3hi7E:86:J72f=#ko097d;;:188m0d=831b9k4?::k2<5<722e:4<4?::a6d7=83?1<7>t$0:b>gd<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17d?70;29?j7?93:17pl=a383>0<729q/=5o5bc9K020<@=<h7)mi:39j11<722c>n7>5;h7e>5<<a82;6=44o0:2>5<<uk8j?7>55;294~"60h0in6F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9j5=6=831d=5?50;9~f7g3290>6=4?{%3;e?de3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66g>8183>>i6080;66sm2`794?3=83:p(<6n:c`8L1113A>=o6*lf;08m02=831b9o4?::k6b?6=3`;3<7>5;n3;5?6=3th9m;4?:483>5}#91k1no5G4648L10d3-im6?5f5583>>o2j3:17d;i:188m4>72900c<6>:188yg4f?3:197>50z&2<d<ej2B?;;5G47a8 f`=:2c>87>5;h7a>5<<a<l1<75f19294?=h91;1<75rb3c;>5<2290;w)?7a;`a?M20>2B?:n5+cg81?l332900e8l50;9j1c<722c:4=4?::m2<4<722wi>l>50;794?6|,82j6ol4H555?M21k2.hj7<4i4694?=n=k0;66g:f;29?l7?83:17b?71;29?xd4?l0;694?:1y'5=g=jj1C8:84H54`?!ea2;1b994?::k6b?6=3`;3<7>5;n3;5?6=3th8;i4?:583>5}#91k1nn5G4648L10d3-im6?5f5583>>o2n3:17d?70;29?j7?93:17pl<b183>1<729q/=5o5b89K020<@=<h7)mi:39j11<722c>n7>5;h7e>5<<g82:6=44}c1a5?6=<3:1<v*>8`8a=>N3??1C8;m4$bd96>o2<3:17d;m:188m0`=831d=5?50;9~f6d4290?6=4?{%3;e?d>3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66a>8083>>{e;k>1<7:50;2x 4>f2k30D999;I65g>"dn380e8:50;9j1g<722c>j7>5;n3;5?6=3th8n84?:583>5}#91k1n45G4648L10d3-im6?5f5583>>o2j3:17d;i:188k4>62900qo=m6;290?6=8r.:4l4m9:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=h91;1<75rb2`4>5<3290;w)?7a;`:?M20>2B?:n5+cg81?l332900e8l50;9j1c<722e:4<4?::a7g>=83>1<7>t$0:b>g?<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17b?71;29?xd4j00;694?:1y'5=g=j01C8:84H54`?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk9im7>54;294~"60h0i56F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9l5=7=831vn>l=:187>5<7s-;3m7l6;I642>N3>j1/ok4=;h77>5<<a<h1<75f5g83>>i6080;66sm29;94?5=83:p(<6n:03:?M20>2B?:n5+cg800>od;3:17dm;:188k41f2900qo<70;290?6=8r.:4l4>239K020<@=<h7d;7:188m37=831b=5=50;9l52g=831vn?7<:180>5<7s-;3m7:85:J733=O<?i0e8650;9j542=831d=:o50;9~f7>f29086=4?{%3;e?7612B?;;5G47a8 f`=;=1bo>4?::k`0?6=3f;<m7>5;|`1<4<72=0;6=u+19c9574<@===7E:9c:k6<?6=3`<:6=44i0:0>5<<g8=j6=44}c0:0?6=;3:1<v*>8`8730=O<><0D98l;h7;>5<<a8;?6=44o05b>5<<uk83n7>53;294~"60h0:=45G4648L10d3-im6>:4ib194?=nk=0;66a>7`83>>{e:181<7:50;2x 4>f28897E:86:J72f=n=10;66g91;29?l7?;3:17b?8a;29?xd51<0;6>4?:1y'5=g=<>?0D999;I65g>o203:17d?>4;29?j70i3:17pl=8b83>6<729q/=5o510;8L1113A>=o6*lf;17?le42900en:50;9l52g=831vn?6<:187>5<7s-;3m7?=2:J733=O<?i0e8650;9j24<722c:4>4?::m23d<722wi>4850;194?6|,82j699:;I642>N3>j1b954?::k251<722e:;l4?::a6=b=8391<7>t$0:b>47>3A><:6F;6b9'gc<4<2ch?7>5;ha7>5<<g8=j6=44}c0;0?6=<3:1<v*>8`8267=O<><0D98l;h7;>5<<a?;1<75f19194?=h9>k1<75rb3;4>5<4290;w)?7a;641>N3??1C8;m4i4:94?=n98>1<75`16c94?=zj;2n6=4<:183!7?i3;:56F;779K03e<,jl1?95fc283>>od<3:17b?8a;29?xd50<0;694?:1y'5=g=9;80D999;I65g>o203:17d8>:188m4>42900c<9n:188yg4>03:1?7>50z&2<d<3?<1C8:84H54`?l3?2900e<?;:188k41f2900qo<7f;297?6=8r.:4l4>189K020<@=<h7)mi:268mf5=831bo94?::m23d<722wi>5850;694?6|,82j6<<=;I642>N3>j1b954?::k55?6=3`;3?7>5;n34e?6=3th9544?:283>5}#91k18:;4H555?M21k2c>47>5;h320?6=3f;<m7>5;|`1=5<72:0;6=u+19c954?<@===7E:9c:&`b?533`i86=44ib694?=h9>k1<75rb3:4>5<3290;w)?7a;316>N3??1C8;m4i4:94?=n>80;66g>8283>>i6?h0;66sm28c94?5=83:p(<6n:556?M20>2B?:n5f5983>>o69=0;66a>7`83>>{e:0;1<7=50;2x 4>f28;27E:86:J72f=#ko0886gl3;29?le32900c<9n:188yg4?03:187>50z&2<d<6:;1C8:84H54`?l3?2900e;?50;9j5=5=831d=:o50;9~f7?e29086=4?{%3;e?20=2B?;;5G47a8m0>=831b=<:50;9l52g=831vn?7=:180>5<7s-;3m7?>9:J733=O<?i0(nh5359jg6<722ch87>5;n34e?6=3th95n4?:283>5}#91k18:;4H555?M21k2c>47>5;h320?6=3f;<m7>5;|`0=g<72:0;6=u+19c954?<@===7E:9c:&`b?533`i86=44ib694?=h9>k1<75rb2;1>5<3290;w)?7a;316>N3??1C8;m4i4:94?=n>80;66g>8283>>i6?h0;66sm3`794?5=83:p(<6n:556?M20>2B?:n5f5983>>o69=0;66a>7`83>>{e;0i1<7=50;2x 4>f28;27E:86:J72f=#ko0886gl3;29?le32900c<9n:188yg5>;3:187>50z&2<d<6:;1C8:84H54`?l3?2900e;?50;9j5=5=831d=:o50;9~f6g129086=4?{%3;e?20=2B?;;5G47a8m0>=831b=<:50;9l52g=831vn>7k:180>5<7s-;3m7?>9:J733=O<?i0(nh5359jg6<722ch87>5;n34e?6=3th8594?:583>5}#91k1=?<4H555?M21k2c>47>5;h42>5<<a8286=44o05b>5<<uk9j;7>53;294~"60h0?;85G4648L10d3`?36=44i037>5<<g8=j6=44}c1:a?6=;3:1<v*>8`825<=O<><0D98l;%ae>62<aj91<75fc583>>i6?h0;66sm38794?2=83:p(<6n:001?M20>2B?:n5f5983>>o193:17d?73;29?j70i3:17pl<a983>6<729q/=5o54678L1113A>=o6g:8;29?l76<3:17b?8a;29?xd41o0;6>4?:1y'5=g=9830D999;I65g>"dn39?7dm<:188mf2=831d=:o50;9~f6?1290?6=4?{%3;e?75:2B?;;5G47a8m0>=831b:<4?::k2<6<722e:;l4?::a7d?=8391<7>t$0:b>1123A><:6F;6b9j1=<722c:=94?::m23d<722wi?l>50;194?6|,82j6<?6;I642>N3>j1/ok4<4:k`7?6=3`i?6=44o05b>5<<uk92;7>54;294~"60h0:>?5G4648L10d3`?36=44i7394?=n9191<75`16c94?=zj:kj6=4<:183!7?i3><96F;779K03e<a<21<75f10694?=h9>k1<75rb2c2>5<4290;w)?7a;32=>N3??1C8;m4$bd971=nk:0;66gl4;29?j70i3:17pl<9983>1<729q/=5o51308L1113A>=o6g:8;29?l062900e<6<:188k41f2900qo=nb;297?6=8r.:4l4;749K020<@=<h7d;7:188m4732900c<9n:188yg5f:3:1?7>50z&2<d<6901C8:84H54`?!ea2:>0en=50;9jg1<722e:;l4?::a7<?=83>1<7>t$0:b>4453A><:6F;6b9j1=<722c==7>5;h3;7?6=3f;<m7>5;|`0ef<72:0;6=u+19c9023<@===7E:9c:k6<?6=3`;:87>5;n34e?6=3th8m>4?:283>5}#91k1=<74H555?M21k2.hj7=;;ha0>5<<aj>1<75`16c94?=zj:3j6=4;:183!7?i3;9>6F;779K03e<a<21<75f6083>>o60:0;66a>7`83>>{e;hn1<7=50;2x 4>f2==>7E:86:J72f=n=10;66g>1583>>i6?h0;66sm3`694?5=83:p(<6n:03:?M20>2B?:n5+cg800>od;3:17dm;:188k41f2900qo=ne;297?6=8r.:4l4;749K020<@=<h7d;7:188m4732900c<9n:188yg4b:3:187>50z&2<d<6:;1C8:84H54`?l3?2900e;?50;9j5=5=831d=:o50;9~f7c6290?6=4?{%3;e?75:2B?;;5G47a8m0>=831b:<4?::k2<6<722e:;l4?::a6`6=83>1<7>t$0:b>4453A><:6F;6b9j1=<722c==7>5;h3;7?6=3f;<m7>5;|`1`c<72=0;6=u+19c9574<@===7E:9c:k6<?6=3`<:6=44i0:0>5<<g8=j6=44}c0ga?6=<3:1<v*>8`8267=O<><0D98l;h7;>5<<a?;1<75f19194?=h9>k1<75rb3d6>5<3290;w)?7a;316>N3??1C8;m4i4:94?=n>80;66g>8283>>i6?h0;66sm2g694?2=83:p(<6n:001?M20>2B?:n5f5983>>o193:17d?73;29?j70i3:17pl=f283>1<729q/=5o51308L1113A>=o6g:8;29?l062900e<6<:188k41f2900qo<i2;290?6=8r.:4l4>239K020<@=<h7d;7:188m37=831b=5=50;9l52g=831vn?h>:187>5<7s-;3m7?=2:J733=O<?i0e8650;9j24<722c:4>4?::m23d<722wi?8j50;694?6|,82j6<<=;I642>N3>j1b954?::k55?6=3`;3?7>5;n34e?6=3th89n4?:583>5}#91k1=?<4H555?M21k2c>47>5;h42>5<<a8286=44o05b>5<<uk9>n7>54;294~"60h0:>?5G4648L10d3`?36=44i7394?=n9191<75`16c94?=zj:?j6=4;:183!7?i3;9>6F;779K03e<a<21<75f6083>>o60:0;66a>7`83>>{e;<31<7:50;2x 4>f28897E:86:J72f=n=10;66g91;29?l7?;3:17b?8a;29?xd4?90;694?:1y'5=g=9;80D999;I65g>o203:17d8>:188m4>42900c<9n:188yg51n3:187>50z&2<d<6:;1C8:84H54`?l3?2900e;?50;9j5=5=831d=:o50;9~f60b290?6=4?{%3;e?75:2B?;;5G47a8m0>=831b:<4?::k2<6<722e:;l4?::a73b=83>1<7>t$0:b>4453A><:6F;6b9j1=<722c==7>5;h3;7?6=3f;<m7>5;|`02f<72=0;6=u+19c9574<@===7E:9c:k6<?6=3`<:6=44i0:0>5<<g8=j6=44}c3a4?6=<3:1<v*>8`8a=>N3??1C8;m4$bd96>o2<3:17d;m:188m0`=831d=5?50;9~f4ga290?6=4?{%3;e?d>3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66a>8083>>{e9ho1<7:50;2x 4>f2k30D999;I65g>"dn380e8:50;9j1g<722c>j7>5;n3;5?6=3th:mi4?:583>5}#91k1n45G4648L10d3-im6?5f5583>>o2j3:17d;i:188k4>62900qo?nc;290?6=8r.:4l4m9:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=h91;1<75rb0ca>5<3290;w)?7a;`:?M20>2B?:n5+cg81?l332900e8l50;9j1c<722e:4<4?::a5dg=83>1<7>t$0:b>g?<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17b?71;29?xd6i00;694?:1y'5=g=j01C8:84H54`?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;j47>54;294~"60h0i56F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9l5=7=831vn<o8:187>5<7s-;3m7l6;I642>N3>j1/ok4=;h77>5<<a<h1<75f5g83>>i6080;66sm20f94?2=83:p(<6n:c;8L1113A>=o6*lf;08m02=831b9o4?::k6b?6=3f;3=7>5;|`15f<72=0;6=u+19c9f<=O<><0D98l;%ae>7=n==0;66g:b;29?l3a2900c<6>:188yg46j3:187>50z&2<d<e12B?;;5G47a8 f`=:2c>87>5;h7a>5<<a<l1<75`19394?=zj;;j6=4;:183!7?i3h27E:86:J72f=#ko097d;;:188m0d=831b9k4?::m2<4<722wi><750;694?6|,82j6o74H555?M21k2.hj7<4i4694?=n=k0;66g:f;29?j7?93:17pl=1983>1<729q/=5o5b89K020<@=<h7)mi:39j11<722c>n7>5;h7e>5<<g82:6=44}c023?6=<3:1<v*>8`8a=>N3??1C8;m4$bd96>o2<3:17d;m:188m0`=831d=5?50;9~f771290?6=4?{%3;e?d>3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66a>8083>>{e:8?1<7:50;2x 4>f2k30D999;I65g>"dn380e8:50;9j1g<722c>j7>5;n3;5?6=3th9=94?:583>5}#91k1n45G4648L10d3-im6?5f5583>>o2j3:17d;i:188k4>62900qo<9d;290?6=8r.:4l4m9:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=h91;1<75rb34`>5<3290;w)?7a;`:?M20>2B?:n5+cg81?l332900e8l50;9j1c<722e:4<4?::a63d=83>1<7>t$0:b>g?<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17b?71;29?xd5>h0;694?:1y'5=g=j01C8:84H54`?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8=57>54;294~"60h0i56F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9l5=7=831vn?87:187>5<7s-;3m7l6;I642>N3>j1/ok4=;h77>5<<a<h1<75f5g83>>i6080;66sm27594?2=83:p(<6n:c;8L1113A>=o6*lf;08m02=831b9o4?::k6b?6=3f;3=7>5;|`123<72=0;6=u+19c9f<=O<><0D98l;%ae>7=n==0;66g:b;29?l3a2900c<6>:188yg41=3:187>50z&2<d<e12B?;;5G47a8 f`=:2c>87>5;h7a>5<<a<l1<75`19394?=zj;<?6=4;:183!7?i3h27E:86:J72f=#ko097d;;:188m0d=831b9k4?::m2<4<722wi>=>50;694?6|,82j6o74H555?M21k2.hj7<4i4694?=n=k0;66g:f;29?j7?93:17pl>fg83>1<729q/=5o5b89K020<@=<h7)mi:39j11<722c>n7>5;h7e>5<<g82:6=44}c3ea?6=<3:1<v*>8`8a=>N3??1C8;m4$bd96>o2<3:17d;m:188m0`=831d=5?50;9~f4`c290?6=4?{%3;e?d>3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66a>8083>>{e9oi1<7:50;2x 4>f2k30D999;I65g>"dn380e8:50;9j1g<722c>j7>5;n3;5?6=3th:jo4?:583>5}#91k1n45G4648L10d3-im6?5f5583>>o2j3:17d;i:188k4>62900qo?ia;290?6=8r.:4l4m9:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=h91;1<75rb0d:>5<3290;w)?7a;`:?M20>2B?:n5+cg81?l332900e8l50;9j1c<722e:4<4?::a5c>=83>1<7>t$0:b>g?<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17b?71;29?xd6n>0;694?:1y'5=g=j01C8:84H54`?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>57>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>47>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>;7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>:7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>97>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>87>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>?7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>>7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>=7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8><7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;no7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;nn7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;nm7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n57>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n47>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n;7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n:7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n97>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n87>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n?7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;o47>54;294~"60h0i56F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9l5=7=831vn<j8:187>5<7s-;3m7l6;I642>N3>j1/ok4=;h77>5<<a<h1<75f5g83>>i6080;66sm1e494?2=83:p(<6n:c;8L1113A>=o6*lf;08m02=831b9o4?::k6b?6=3f;3=7>5;|`2`0<72=0;6=u+19c9f<=O<><0D98l;%ae>7=n==0;66g:b;29?l3a2900c<6>:188yg7c<3:187>50z&2<d<e12B?;;5G47a8 f`=:2c>87>5;h7a>5<<a<l1<75`19394?=zj8n86=4;:183!7?i3h27E:86:J72f=#ko097d;;:188m0d=831b9k4?::m2<4<722wi=i<50;694?6|,82j6o74H555?M21k2.hj7<4i4694?=n=k0;66g:f;29?j7?93:17pl>d083>1<729q/=5o5b89K020<@=<h7)mi:39j11<722c>n7>5;h7e>5<<g82:6=44}c3g4?6=<3:1<v*>8`8a=>N3??1C8;m4$bd96>o2<3:17d;m:188m0`=831d=5?50;9~f4ea290?6=4?{%3;e?d>3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66a>8083>>{e:=?1<7:50;2x 4>f2k30D999;I65g>"dn380e8:50;9j1g<722c>j7>5;n3;5?6=3th9894?:583>5}#91k1n45G4648L10d3-im6?5f5583>>o2j3:17d;i:188k4>62900qo<;3;290?6=8r.:4l4m9:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=h91;1<75rb361>5<3290;w)?7a;`:?M20>2B?:n5+cg81?l332900e8l50;9j1c<722e:4<4?::a617=83>1<7>t$0:b>g?<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17b?71;29?xd5<90;694?:1y'5=g=j01C8:84H54`?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk88j7>54;294~"60h0i56F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9l5=7=831vn?=j:187>5<7s-;3m7l6;I642>N3>j1/ok4=;h77>5<<a<h1<75f5g83>>i6080;66sm22f94?2=83:p(<6n:c;8L1113A>=o6*lf;08m02=831b9o4?::k6b?6=3f;3=7>5;|`17f<72=0;6=u+19c9f<=O<><0D98l;%ae>7=n==0;66g:b;29?l3a2900c<6>:188yg5383:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm32d94?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk98h7>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a76e=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo=<e;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e;:h1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c10e?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi?>650;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg54?3:197>50z&2<d<el2B?;;5G47a8 f`=?2c>87>5;h75>5<<a<l1<75f19294?=h91;1<75rb21:>5<2290;w)?7a;`b?M20>2B?:n5+cg81?l332900e8850;9j1g<722c>j7>5;n3;5?6=3th8>o4?:283>5}#91k18:;4H555?M21k2c>47>5;h320?6=3f;<m7>5;|`06d<72:0;6=u+19c9023<@===7E:9c:k6<?6=3`;:87>5;n34e?6=3th8>=4?:583>5}#91k1=?<4H555?M21k2c>47>5;h42>5<<a8286=44o05b>5<<uk9957>53;294~"60h0?;85G4648L10d3`?36=44i037>5<<g8=j6=44}c12a?6=<3:1<v*>8`8267=O<><0D98l;h7;>5<<a?;1<75f19194?=h9>k1<75rb20;>5<4290;w)?7a;641>N3??1C8;m4i4:94?=n98>1<75`16c94?=zj:;h6=4;:183!7?i3;9>6F;779K03e<a<21<75f6083>>o60:0;66a>7`83>>{e;;=1<7=50;2x 4>f2==>7E:86:J72f=n=10;66g>1583>>i6?h0;66sm30c94?2=83:p(<6n:001?M20>2B?:n5f5983>>o193:17d?73;29?j70i3:17pl<2783>6<729q/=5o54678L1113A>=o6g:8;29?l76<3:17b?8a;29?xd4910;694?:1y'5=g=9;80D999;I65g>o203:17d8>:188m4>42900c<9n:188yg55=3:1?7>50z&2<d<3?<1C8:84H54`?l3?2900e<?;:188k41f2900qo=>6;290?6=8r.:4l4>239K020<@=<h7d;7:188m37=831b=5=50;9l52g=831vn><;:180>5<7s-;3m7:85:J733=O<?i0e8650;9j542=831d=:o50;9~f673290?6=4?{%3;e?75:2B?;;5G47a8m0>=831b:<4?::k2<6<722e:;l4?::a775=8391<7>t$0:b>1123A><:6F;6b9j1=<722c:=94?::m23d<722wi?<<50;694?6|,82j6<<=;I642>N3>j1b954?::k55?6=3`;3?7>5;n34e?6=3th8>?4?:283>5}#91k18:;4H555?M21k2c>47>5;h320?6=3f;<m7>5;|`055<72=0;6=u+19c9574<@===7E:9c:k6<?6=3`<:6=44i0:0>5<<g8=j6=44}c160?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi?8=50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg52:3:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm34394?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk9><7>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a71`=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo=;e;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e;=n1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c17g?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi?9l50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg4c:3:187>50z&2<d<e12B?;;5G47a8 f`=:2c>87>5;h7a>5<<a<l1<75`19394?=zj;im6=4;:183!7?i3h27E:86:J72f=#ko097d;;:188m0d=831b9k4?::m2<4<722wi>i750;694?6|,82j6o74H555?M21k2.hj7<4i4694?=n=k0;66g:f;29?j7?93:17pl=d783>1<729q/=5o5bb9K020<@=<h7)mi:69j11<722c>j7>5;h3;4?6=3f;3=7>5;|`1`0<72=0;6=u+19c9ff=O<><0D98l;%ae>2=n==0;66g:f;29?l7?83:17b?71;29?xd38=0;684?:1y'5=g=jh1C8:84H54`?!ea2;1b994?::k62?6=3`?i6=44i4d94?=h91;1<75rb520>5<2290;w)?7a;`b?M20>2B?:n5+cg81?l332900e8850;9j1g<722c>j7>5;n3;5?6=3th?<<4?:483>5}#91k1nl5G4648L10d3-im6?5f5583>>o2>3:17d;m:188m0`=831d=5?50;9~f167290>6=4?{%3;e?df3A><:6F;6b9'gc<53`??6=44i4494?=n=k0;66g:f;29?j7?93:17pl;0383>0<729q/=5o5b`9K020<@=<h7)mi:39j11<722c>:7>5;h7a>5<<a<l1<75`19394?=zj:lm6=4::183!7?i3hj7E:86:J72f=#ko097d;;:188m00=831b9o4?::k6b?6=3f;3=7>5;|`0b`<72<0;6=u+19c9fd=O<><0D98l;%ae>7=n==0;66g:6;29?l3e2900e8h50;9l5=7=831vn>hl:186>5<7s-;3m7lk;I642>N3>j1/ok48;h77>5<<a<<1<75f5g83>>o6090;66a>8083>>{e;oh1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c1e`?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi?hh50;194?6|,82j699:;I642>N3>j1b954?::k251<722e:;l4?::a7`c=8391<7>t$0:b>1123A><:6F;6b9j1=<722c:=94?::m23d<722wi?h:50;694?6|,82j6<<=;I642>N3>j1b954?::k55?6=3`;3?7>5;n34e?6=3th8ii4?:283>5}#91k18:;4H555?M21k2c>47>5;h320?6=3f;<m7>5;|`0a7<72=0;6=u+19c9574<@===7E:9c:k6<?6=3`<:6=44i0:0>5<<g8=j6=44}c1fg?6=;3:1<v*>8`8730=O<><0D98l;h7;>5<<a8;?6=44o05b>5<<uk9n<7>54;294~"60h0:>?5G4648L10d3`?36=44i7394?=n9191<75`16c94?=zj:oi6=4<:183!7?i3><96F;779K03e<a<21<75f10694?=h9>k1<75rb2ff>5<3290;w)?7a;316>N3??1C8;m4i4:94?=n>80;66g>8283>>i6?h0;66sm3dc94?5=83:p(<6n:556?M20>2B?:n5f5983>>o69=0;66a>7`83>>{e;mi1<7:50;2x 4>f28897E:86:J72f=n=10;66g91;29?l7?;3:17b?8a;29?xd4m00;6>4?:1y'5=g=<>?0D999;I65g>o203:17d?>4;29?j70i3:17pl<d`83>1<729q/=5o51308L1113A>=o6g:8;29?l062900e<6<:188k41f2900qo=j8;297?6=8r.:4l4;749K020<@=<h7d;7:188m4732900c<9n:188yg5c03:187>50z&2<d<6:;1C8:84H54`?l3?2900e;?50;9j5=5=831d=:o50;9~f6c029086=4?{%3;e?20=2B?;;5G47a8m0>=831b=<:50;9l52g=831vn>j9:187>5<7s-;3m7?=2:J733=O<?i0e8650;9j24<722c:4>4?::m23d<722wi?h850;194?6|,82j699:;I642>N3>j1b954?::k251<722e:;l4?::a7a2=83>1<7>t$0:b>4453A><:6F;6b9j1=<722c==7>5;h3;7?6=3f;<m7>5;|`754<72<0;6=u+19c9fd=O<><0D98l;%ae>7=n==0;66g:6;29?l3e2900e8h50;9l5=7=831vn9>i:186>5<7s-;3m7lk;I642>N3>j1/ok48;h77>5<<a<<1<75f5g83>>o6090;66a>8083>>{e<8:1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c626?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi8<=50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg26>3:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm40694?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk>:97>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a041=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo:>8;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e<;i1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c61f?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi8?o50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg2513:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm43:94?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk>9;7>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a070=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo:=5;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e<;>1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c617?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi8>850;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg24=3:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm42694?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk>8?7>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a064=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo:<1;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e<::1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c61b?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi8>k50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg24l3:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm42a94?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk>8n7>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a06g=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo:<9;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e<:21<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c603?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi8?k50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg25l3:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm47494?5=83:p(<6n:03:?M20>2B?:n5+cg817>od;3:17dm;:188k41f2900qo::b;297?6=8r.:4l4>189K020<@=<h7)mi:318mf5=831bo94?::m23d<722wi><h50;194?6|,82j6<?6;I642>N3>j1/ok4=5:k`7?6=3`i?6=44o05b>5<<uk;i>7>53;294~"60h0:=45G4648L10d3-im6?;4ib194?=nk=0;66a>7`83>>{e90i1<7=50;2x 4>f28;27E:86:J72f=#ko0996gl3;29?le32900c<9n:188yg7>j3:1?7>50z&2<d<6901C8:84H54`?!ea2;?0en=50;9jg1<722e:;l4?::a5<g=8391<7>t$0:b>47>3A><:6F;6b9'gc<5=2ch?7>5;ha7>5<<g8=j6=44}c3:=?6=;3:1<v*>8`825<=O<><0D98l;%ae>73<aj91<75fc583>>i6?h0;66sm18:94?5=83:p(<6n:03:?M20>2B?:n5+cg811>od;3:17dm;:188k41f2900qo?67;297?6=8r.:4l4>189K020<@=<h7)mi:378mf5=831bo94?::m23d<722wi=4850;194?6|,82j6<?6;I642>N3>j1/ok4=5:k`7?6=3`i?6=44o05b>5<<uk;297>53;294~"60h0:=45G4648L10d3-im6?;4ib194?=nk=0;66a>7`83>>{e90>1<7=50;2x 4>f28;27E:86:J72f=#ko0996gl3;29?le32900c<9n:188yg7>;3:1?7>50z&2<d<6901C8:84H54`?!ea2;?0en=50;9jg1<722e:;l4?::a5<4=8391<7>t$0:b>47>3A><:6F;6b9'gc<5=2ch?7>5;ha7>5<<g8=j6=44}c3:5?6=;3:1<v*>8`825<=O<><0D98l;%ae>73<aj91<75fc583>>i6?h0;66sm18294?5=83:p(<6n:03:?M20>2B?:n5+cg811>od;3:17dm;:188k41f2900qo?7f;297?6=8r.:4l4>189K020<@=<h7)mi:378mf5=831bo94?::m23d<722wi=5k50;194?6|,82j6<?6;I642>N3>j1/ok4=5:k`7?6=3`i?6=44o05b>5<<uk;3h7>53;294~"60h0:=45G4648L10d3-im6?;4ib194?=nk=0;66a>7`83>>{e91i1<7=50;2x 4>f28;27E:86:J72f=#ko0996gl3;29?le32900c<9n:188yg7?j3:1?7>50z&2<d<6901C8:84H54`?!ea2;?0en=50;9jg1<722e:;l4?::a677=83>1<7>t$0:b>47e3A><:6F;6b9'gc<4>2ch?7>5;ha7>5<<aj?1<75`16c94?=zj8h?6=4;:183!7?i3;:n6F;779K03e<,jl1?;5fc283>>od<3:17dm::188k41f2900qo<k1;290?6=8r.:4l4>1c9K020<@=<h7)mi:3f8mf5=831bo94?::k`1?6=3f;<m7>5;|`166<72<0;6=u+19c954c<@===7E:9c:&`b?4>3`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl>b783>0<729q/=5o510g8L1113A>=o6*lf;0:?le42900en:50;9jg0<722ch:7>5;n34e?6=3th9h54?:483>5}#91k1=<k4H555?M21k2.hj7;:;ha0>5<<aj>1<75fc483>>od>3:17b?8a;29?xd5l=0;684?:1y'5=g=98o0D999;I65g>"dn38j7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`0g<<72:0;6=u+19c954?<@===7E:9c:&`b?443`i86=44ib694?=h9>k1<75rb3ag>5<3290;w)?7a;32f>N3??1C8;m4$bd962=nk:0;66gl4;29?le22900c<9n:188yg45=3:1?7>50z&2<d<6901C8:84H54`?!ea2;?0en=50;9jg1<722e:;l4?::a5g>=8391<7>t$0:b>47>3A><:6F;6b9'gc<5=2ch?7>5;ha7>5<<g8=j6=44}c013?6=<3:1<v*>8`825g=O<><0D98l;%ae>60<aj91<75fc583>>od=3:17b?8a;29?xd6jh0;694?:1y'5=g=98h0D999;I65g>"dn39=7dm<:188mf2=831bo84?::m23d<722wi>?750;794?6|,82j6<?j;I642>N3>j1/ok4=9:k`7?6=3`i?6=44ib794?=nk?0;66a>7`83>>{e9ki1<7;50;2x 4>f28;n7E:86:J72f=#ko0956gl3;29?le32900en;50;9jg3<722e:;l4?::a6fe=83?1<7>t$0:b>47b3A><:6F;6b9'gc<5<2ch?7>5;ha7>5<<aj?1<75fc783>>i6?h0;66sm44194?5=83:p(<6n:03:?M20>2B?:n5+cg8a6>od;3:17dm;:188k41f2900qo=8a;291?6=8r.:4l4>1d9K020<@=<h7)mi:278mf5=831bo94?::k`1?6=3`i=6=44o05b>5<<uk9=;7>55;294~"60h0:=h5G4648L10d3-im6>;4ib194?=nk=0;66gl5;29?le12900c<9n:188yg4an3:197>50z&2<d<69l1C8:84H54`?!ea2:?0en=50;9jg1<722ch97>5;ha5>5<<g8=j6=44}c0fg?6==3:1<v*>8`825`=O<><0D98l;%ae>63<aj91<75fc583>>od=3:17dm9:188k41f2900qo=89;291?6=8r.:4l4>1d9K020<@=<h7)mi:278mf5=831bo94?::k`1?6=3`i=6=44o05b>5<<uk9=:7>55;294~"60h0:=h5G4648L10d3-im6>;4ib194?=nk=0;66gl5;29?le12900c<9n:188yg4am3:197>50z&2<d<69l1C8:84H54`?!ea2:?0en=50;9jg1<722ch97>5;ha5>5<<g8=j6=44}c0ff?6==3:1<v*>8`825`=O<><0D98l;%ae>63<aj91<75fc583>>od=3:17dm9:188k41f2900qo<na;291?6=8r.:4l4>1d9K020<@=<h7)mi:338mf5=831bo94?::k`1?6=3`i=6=44o05b>5<<uk9<47>55;294~"60h0:=h5G4648L10d3-im6>;4ib194?=nk=0;66gl5;29?le12900c<9n:188yg51=3:197>50z&2<d<69l1C8:84H54`?!ea2:?0en=50;9jg1<722ch97>5;ha5>5<<g8=j6=44}c0e`?6==3:1<v*>8`825`=O<><0D98l;%ae>63<aj91<75fc583>>od=3:17dm9:188k41f2900qo<ja;291?6=8r.:4l4>1d9K020<@=<h7)mi:278mf5=831bo94?::k`1?6=3`i=6=44o05b>5<<uk9<;7>55;294~"60h0:=h5G4648L10d3-im6>;4ib194?=nk=0;66gl5;29?le12900c<9n:188yg51<3:197>50z&2<d<69l1C8:84H54`?!ea2:?0en=50;9jg1<722ch97>5;ha5>5<<g8=j6=44}c0eg?6==3:1<v*>8`825`=O<><0D98l;%ae>63<aj91<75fc583>>od=3:17dm9:188k41f2900qo<j9;291?6=8r.:4l4>1d9K020<@=<h7)mi:278mf5=831bo94?::k`1?6=3`i=6=44o05b>5<<uk9;87>54;294~"60h0:=o5G4648L10d3-im6o94ib194?=nk=0;66gl5;29?j70i3:17pl<8183>0<729q/=5o510g8L1113A>=o6*lf;72?le42900en:50;9jg0<722ch:7>5;n34e?6=3th8;;4?:483>5}#91k1=<k4H555?M21k2.hj7=:;ha0>5<<aj>1<75fc483>>od>3:17b?8a;29?xd4>:0;684?:1y'5=g=98o0D999;I65g>"dn39>7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`1bg<72<0;6=u+19c954c<@===7E:9c:&`b?523`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl=e983>0<729q/=5o510g8L1113A>=o6*lf;16?le42900en:50;9jg0<722ch:7>5;n34e?6=3th9>n4?:283>5}#91k1=<74H555?M21k2.hj7=;;ha0>5<<aj>1<75`16c94?=zj8hm6=4<:183!7?i3;:56F;779K03e<,jl1?95fc283>>od<3:17b?8a;29?xd5:o0;694?:1y'5=g=98h0D999;I65g>"dn3837dm<:188mf2=831bo84?::m23d<722wi=n<50;694?6|,82j6<?m;I642>N3>j1/ok4=8:k`7?6=3`i?6=44ib794?=h9>k1<75rb312>5<2290;w)?7a;32a>N3??1C8;m4$bd972=nk:0;66gl4;29?le22900en850;9l52g=831vn?<m:186>5<7s-;3m7?>e:J733=O<?i0(nh5369jg6<722ch87>5;ha6>5<<aj<1<75`16c94?=zj8i?6=4::183!7?i3;:i6F;779K03e<,jl1?:5fc283>>od<3:17dm::188mf0=831d=:o50;9~f4db290>6=4?{%3;e?76m2B?;;5G47a8 f`=;>1bo>4?::k`0?6=3`i>6=44ib494?=h9>k1<75rb3cf>5<4290;w)?7a;32=>N3??1C8;m4$bd966=nk:0;66gl4;29?j70i3:17pl<8g83>6<729q/=5o510;8L1113A>=o6*lf;06?le42900en:50;9l52g=831vn?l?:187>5<7s-;3m7?>b:J733=O<?i0(nh51b9jg6<722ch87>5;ha6>5<<g8=j6=44}c1:4?6=<3:1<v*>8`825g=O<><0D98l;%ae>7d<aj91<75fc583>>od=3:17b?8a;29?xd5j;0;684?:1y'5=g=98o0D999;I65g>"dn38=7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`0=4<72<0;6=u+19c954c<@===7E:9c:&`b?4d3`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl=b583>1<729q/=5o510`8L1113A>=o6*lf;10?le42900en:50;9jg0<722e:;l4?::a7f6=8391<7>t$0:b>47>3A><:6F;6b9'gc<5=2ch?7>5;ha7>5<<g8=j6=44}c1`6?6=<3:1<v*>8`825g=O<><0D98l;%ae>7d<aj91<75fc583>>od=3:17b?8a;29?xd4k=0;684?:1y'5=g=98o0D999;I65g>"dn38h7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`1f<<72<0;6=u+19c954c<@===7E:9c:&`b?073`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl=bc83>0<729q/=5o510g8L1113A>=o6*lf;1:?le42900en:50;9jg0<722ch:7>5;n34e?6=3th9nl4?:483>5}#91k1=<k4H555?M21k2.hj7l<;ha0>5<<aj>1<75fc483>>od>3:17b?8a;29?xd5jj0;684?:1y'5=g=98o0D999;I65g>"dn3<;7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`1f`<72<0;6=u+19c954c<@===7E:9c:&`b?073`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl=c883>1<729q/=5o510`8L1113A>=o6*lf;48mf5=831bo94?::k`1?6=3f;<m7>5;|`0<f<72<0;6=u+19c954c<@===7E:9c:&`b?553`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl<2083>7<729q/=5o510:8L1113A>=o6*lf;3b?le42900c<9n:188yg56n3:1>7>50z&2<d<6911C8:84H54`?!ea28k0en=50;9l52g=831vn>?k:181>5<7s-;3m7?>8:J733=O<?i0(nh51`9jg6<722e:;l4?::a74d=8381<7>t$0:b>47?3A><:6F;6b9'gc<6i2ch?7>5;n34e?6=3th8=44?:383>5}#91k1=<64H555?M21k2.hj7?n;ha0>5<<g8=j6=44}c123?6=:3:1<v*>8`825==O<><0D98l;%ae>4g<aj91<75`16c94?=zj:;>6=4=:183!7?i3;:46F;779K03e<,jl1=l5fc283>>i6?h0;66sm30194?4=83:p(<6n:03;?M20>2B?:n5+cg82e>od;3:17b?8a;29?xd4980;6?4?:1y'5=g=9820D999;I65g>"dn3;j7dm<:188k41f2900qo=j5;296?6=8r.:4l4>199K020<@=<h7)mi:0c8mf5=831d=:o50;9~f6c429096=4?{%3;e?7602B?;;5G47a8 f`=9h1bo>4?::m23d<722wi?h?50;094?6|,82j6<?7;I642>N3>j1/ok4>a:k`7?6=3f;<m7>5;|`0`c<72;0;6=u+19c954><@===7E:9c:&`b?7f3`i86=44o05b>5<<uk9oh7>52;294~"60h0:=55G4648L10d3-im6<o4ib194?=h9>k1<75rb2fa>5<5290;w)?7a;32<>N3??1C8;m4$bd95d=nk:0;66a>7`83>>{e;m31<7<50;2x 4>f28;37E:86:J72f=#ko0:m6gl3;29?j70i3:17pl<d683>7<729q/=5o510:8L1113A>=o6*lf;3b?le42900c<9n:188yg5c=3:1>7>50z&2<d<6911C8:84H54`?!ea28k0en=50;9l52g=831vn><l:181>5<7s-;3m7?>8:J733=O<?i0(nh51`9jg6<722e:;l4?::a7c6=8381<7>t$0:b>47?3A><:6F;6b9'gc<6i2ch?7>5;n34e?6=3th9o>4?:483>5}#91k1=<k4H555?M21k2.hj7==;ha0>5<<aj>1<75fc483>>od>3:17b?8a;29?xd5jm0;684?:1y'5=g=98o0D999;I65g>"dn3hn7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`1ef<72<0;6=u+19c954c<@===7E:9c:&`b?553`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl=b983>0<729q/=5o510g8L1113A>=o6*lf;0e?le42900en:50;9jg0<722ch:7>5;n34e?6=3th9ol4?:483>5}#91k1=<k4H555?M21k2.hj7==;ha0>5<<aj>1<75fc483>>od>3:17b?8a;29?xd5jo0;684?:1y'5=g=98o0D999;I65g>"dn3997dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`1g=<72<0;6=u+19c954c<@===7E:9c:&`b?d33`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl<8c83>6<729q/=5o510;8L1113A>=o6*lf;13?le42900en:50;9l52g=831vn>m9:186>5<7s-;3m7?>e:J733=O<?i0(nh52b9jg6<722ch87>5;ha6>5<<aj<1<75`16c94?=zj:i<6=4::183!7?i3;:i6F;779K03e<,jl1>n5fc283>>od<3:17dm::188mf0=831d=:o50;9~f7e1290>6=4?{%3;e?76m2B?;;5G47a8 f`=;11bo>4?::k`0?6=3`i>6=44ib494?=h9>k1<75rb3a3>5<2290;w)?7a;32a>N3??1C8;m4$bd96c=nk:0;66gl4;29?le22900en850;9l52g=831vn>6n:186>5<7s-;3m7?>e:J733=O<?i0(nh5339jg6<722ch87>5;ha6>5<<aj<1<75`16c94?=zj:2n6=4=:183!7?i3;:>6F;779K03e<aj81<75`16c94?=zj=?:6=494;294~"60h0:4?5G4648L10d3S?86lu6:`820?7228n1=h4>6;3e>41=:90v(<>j:59'55`=<2.h;7:4$b:90>"d13>0(no54:&`f?2<,ji186*>8780?!7??390(i>54:&g5?2<,m8186*k3;68 a2=<2.o97:4$e490>"c?3>0(i654:&g=?2<,mk186*kb;68 ae=<2.oh7:4$eg90>"cn3>0(h>54:&f5?2<,l8186*j3;68 `2=<2.n97:4$d490>"b?3>0(h654:&f=?2<,lk186*jb;68 `e=<2.nh7:4$dg90>"bn3>0(k>54:&e5?2<,o8186*i3;68 c2=<2.m97:4$g490>"a?3>0(k654:&e=?2<,ok186*ib;68 ce=<2.mh7:4$gg90>"an3>0(<>?:59'557=<2.:<?4;;%337?2<,8:?695+11790>"68?0?7)??7;68 46?2=1/==754:&24d<33-;;n7:4$02`>1=#99n186*;728734=#km0?7)?74;34=>"699087)?>1;18 1152==:7)mj:59j1<<722c>m7>5;h`6>5<<ak<1<75f19:94?=n9131<75f47d94?=n<>:1<75f4583>!70n3>87c?8e;28?l25290/=:h5429m52c=921b8<4?:%34b?243g;<i7<4;h63>5<#9>l18>5a16g97>=n;o0;6)?8f;60?k70m3>07d=j:18'52`=<:1e=:k55:9j7a<72-;<j7:<;o34a?0<3`9h6=4+16d906=i9>o1;65f3c83>!70n3>87c?8e;:8?l5f290/=:h5429m52c=121b8k4?:%34b?2b3g;<i7>4;h6g>5<#9>l18h5a16g95>=n<j0;6)?8f;6f?k70m3807d:m:18'52`=<l1e=:k53:9j0d<72-;<j7:j;o34a?2<3`>26=4+16d90`=i9>o1965f4983>!70n3>n7c?8e;48?l20290/=:h54d9m52c=?21b8;4?:%34b?2b3g;<i764;h66>5<#9>l18h5a16g9=>=n>00;6)?8f;4;?k70m3:07d88:18'52`=>11e=:k51:9j23<72-;<j787;o34a?4<3`<>6=4+16d92==i9>o1?65f6583>!70n3<37c?8e;68?l04290/=:h5699m52c==21b;?4?:%34b?0?3g;<i784;h52>5<#9>l1:55a16g93>=n?90;6)?8f;4;?k70m3207d8i:18'52`=>11e=:k59:9j2`<72-;<j787;o34a?g<3`<o6=4+16d92==i9>o1n65f6b83>!70n3<37c?8e;a8?l0e290/=:h5699m52c=l21b:l4?:%34b?0?3g;<i7k4;h41>5<#9>l1:55a16g9b>=n?h0;6)?8f;5:?k70m3:07d97:18'52`=?01e=:k51:9j32<72-;<j796;o34a?4<3`==6=4+16d93<=i9>o1?65f7483>!70n3=27c?8e;68?l13290/=:h5789m52c==21b4>4?:%34b?1>3g;<i784;h:1>5<#9>l1;45a16g93>=n080;6)?8f;5:?k70m3207d6?:18'52`=?01e=:k59:9j3c<72-;<j796;o34a?g<3`=n6=4+16d93<=i9>o1n65f7e83>!70n3=27c?8e;a8?l1d290/=:h5789m52c=l21b;o4?:%34b?1>3g;<i7k4;h50>5<#9>l1;45a16g9b>=n0?0;6)?8f;:6?k70m3:07d6;:18'52`=0<1e=:k51:9j<<<72-;<j767;o34a?6<3`2<6=4+16d9<==i9>o1=65`9083>!70n33;7c?8e;28?j>a290/=:h5919m52c=921d4h4?:%34b??73g;<i7<4;n:g>5<#9>l15=5a16g97>=h0j0;6)?8f;;3?k70m3>07b6m:18'52`=191e=:k55:9l=d<72-;<j77?;o34a?0<3f326=4+16d9=5=i9>o1;65`9983>!70n33;7c?8e;:8?j?0290/=:h5919m52c=121d5;4?:%34b??73g;<i7o4;n;6>5<#9>l15=5a16g9f>=h1=0;6)?8f;;3?k70m3i07b7<:18'52`=191e=:k5d:9l=7<72-;<j77?;o34a?c<3f2j6=4+16d9=5=i9>o1j65`ad83>!70n3ko7c?8e;28?jgd290/=:h5ae9m52c=921dm?4?:%34b?g63g;<i7>4;nc3>5<#9>l1m<5a16g95>=h1o0;6)?8f;c2?k70m3807b7j:18'52`=i81e=:k53:9l=a<72-;<j7o>;o34a?2<3f3h6=4+16d9e4=i9>o1965`ac83>!70n3k:7c?8e;48?jgf290/=:h5a09m52c=?21dm44?:%34b?g63g;<i764;nc;>5<#9>l1m<5a16g9=>=hi>0;6)?8f;c2?k70m3k07bo9:18'52`=i81e=:k5b:9le0<72-;<j7o>;o34a?e<3fk?6=4+16d9e4=i9>o1h65`a283>!70n3k:7c?8e;g8?j?e290/=:h5a09m52c=n21dn<4?:%34b?d73g;<i7>4;nce>5<#9>l1n=5a16g95>=zj;in6=4;:183!7?i3;:m6F;779K03e<,jl1>85fc283>>od<3:17b?>5;29?j70i3:17pl=b483>0<729q/=5o510a8L1113A>=o6*lf;0f?le42900en:50;9jg0<722e:=84?::m23d<722wi>nl50;794?6|,82j6<?l;I642>N3>j1/ok4<1:k`7?6=3`i?6=44ib794?=h98?1<75`16c94?=zj;h=6=49:183!7?i3;:j6F;779K03e<,jl1=o5fc283>>od<3:17dm::188mf0=831d=<;50;9l52g=831vn?m;:187>5<7s-;3m7?>d:J733=O<?i0(nh5309jg6<722ch87>5;ha6>5<<g8;>6=44}c0`1?6==3:1<v*>8`8265=O<><0D98l;%ae>64<aj91<75fc583>>od=3:17dm9:188k4722900qo=l8;291?6=8r.:4l4>1b9K020<@=<h7)mi:238mf5=831bo94?::k`1?6=3f;:97>5;n34e?6=3th9o<4?:483>5}#91k1=?>4H555?M21k2.hj7==;ha0>5<<aj>1<75fc483>>od>3:17b?>5;29?xd5k>0;6;4?:1y'5=g=98l0D999;I65g>"dn3?0en=50;9jg1<722ch97>5;ha5>5<<g8;>6=44o05b>5<<uz??>7>56z\607=::m;1o8522e:9g3=::m>1o;522bf9g0=::ji1o85rs5:f>5<1:rT?5=5Q46d8Z02f3W??46P;7d9]113<V=o>7S;;9:\7a3=Y=920R96:;_6;`>X30j1U85l4^5:b?[2?12T?455Q4958Z1>13W>386P;829>021=k9168;<55g9>001==o168;?55g9>036==o1688h55g9>03g==o168;755g9>6<c=91:01?7i:0:3?84f93;3<63=a382<5=::h91=5>4=3c7>4>7348j97?70:?1e3<60916>l95192897g?282;70<n0;3;4>;5m;0==63=e0855>;5m90==63=dg855>;5ll0==63=f4855>;5n=0==63=f2855>;5n;0==63=f0855>;4=m0==63<5b855>;4=k0==63<5`855>;4=00==63<71855>;4>o0==63<6d855>;4>m0==63<6b855>;4:90==63<1d855>;49j0==63<1`855>;4910==63<17855>;49=0==63<13855>;4990==63<e5855>;4m;0==63<e1855>;4ll0==63<db855>;4lh0==63<d9855>;4l?0==63<d5855>;3=80:45524439026<5=?:6:o4=572>2><5=?:6:94=572>20<5=?:6:;4=572>22<5=?:65=4=572>=4<5=?:65?4=572>=6<5=?:6:h4=572>2c<5=?:6:j4=572>2e<5=?:6:l4=572>25<5=?:6574=572>=1<uz??87>53z\601=:<?81=5>4=574>4>73ty?hn4?:3y]0ae<5;n=6<6>;|q626<72:qU9;=4=2a:>f2<5:2;6n;4}r71e?6=>>qU9?o4=57:>02<5=?368:4=574>02<5=<:68:4=543>02<5=?m68:4=221>02<5;3n68:4=3;e>02<5;k:68:4=3c1>02<5;k868:4=3c7>02<5;k>68:4=3c5>02<5;k<68:4=3c;>02<5;k;68:4=33g>02<5;;h68:4=33a>02<5;;j68:4=33:>02<5;;368:4=334>02<5;;=68:4=336>02<5;;?68:4=34g>02<5;<h68:4=34a>02<5;<j68:4=34:>02<5;<368:4=344>02<5;<=68:4=346>02<5;<?68:4=37:>02<5;?368:4=374>02<5;?=68:4=376>02<5;??68:4=370>02<5;?968:4=372>02<5;?;68:4=0f;>02<58n<68:4=0f5>02<58n>68:4=0f7>02<58n868:4=0f1>02<58n:68:4=0f3>02<58im68:4=263>02<5:9m68:4=21g>02<5:9h68:4=21f>02<5:9i68:4=21b>02<5:9368:4=214>02<5:9268:4=277>02<5:?868:4=271>02<5:?:68:4=273>02<5:>m68:4=26f>02<5:>o68:4=26`>02<5:>i68:4=3f1>02<5;im68:4=3f:>02<5;n=68:4=3f6>02<5=9=68:4=516>02<5=9?68:4=510>02<5=9968:4=512>02<5=9;68:4=50e>02<5=9n68:4=51g>02<5=9h68:4=51a>02<5=9j68:4=51:>02<5=9368:4=514>02<5=8n68:4=50g>02<5=?:68o4}r6f6?6=:rT?i?5236g95=7<uz??n7>55`y]11d<5=<?68:4=541>02<5=<868:4=54b>02<5=<268:4=25f>02<5:=o68:4=2`3>02<5:h:68:4=2`0>02<5:h?68:4=2`6>02<5:h=68:4=2`4>02<5:h368:4=2`:>02<5:hj68:4=2`1>02<58h;68:4=0ce>02<58kn68:4=0cg>02<58kh68:4=0ca>02<58kj68:4=0c:>02<58k368:4=0c4>02<5;:;68:4=0de>02<58ln68:4=0dg>02<58lh68:4=0da>02<58lj68:4=0d:>02<58l368:4=0d4>02<58oh68:4=0ga>02<58oj68:4=0g:>02<58o368:4=0g4>02<58o=68:4=0g6>02<58o?68:4=0g0>02<5;>>68:4=367>02<5;>868:4=361>02<5;>:68:4=363>02<5;9m68:4=31f>02<5;9o68:4=31`>02<5=:?68:4=520>02<5=::68:4=523>02<5=:968:4=2de>02<5:ln68:4=2d`>02<5:li68:4=2dg>02<5=;:68:4=52e>02<5=;;68:4=531>02<5=;868:4=535>02<5=;?68:4=536>02<5=;<68:4=53;>02<5=8h68:4=50a>02<5=8j68:4=50:>02<5=8368:4=504>02<5=8=68:4=506>02<5=8?68:4=500>02<5=?:6874}r76=?6=:rT>8h523c095=7<uz?=>7>52z\613=:;kk1=5?4}r755?6=:rT>98523c;95=7<uz?=<7>52z\611=:;k21=5?4}r76b?6=:rT>9>523c595=7<uz?>i7>52z\617=:;k<1=5?4}r76`?6=:rT>9<523c795=7<uz?>o7>52z\615=:;k>1=5?4}r76f?6=:rT>8k523c195=7<uz?>m7>52z\60a=:;k;1=5?4}r763?6=:rT>8n523c295=7<uz>o=7>52z\7fc=:<:<1=5?4}r6`b?6=:rT?nh5242795=7<uz>hi7>52z\7fa=:<:>1=5?4}r6``?6=:rT?nn5242195=7<uz>ho7>52z\7fg=:<:81=5?4}r6`f?6=:rT?nl5242395=7<uz>hm7>52z\7f<=:<::1=5?4}r6`=?6=:rT?n55243d95=7<uz>om7>52z\7g2=:<:o1=5?4}r6g=?6=:rT?o;5242f95=7<uz>o47>52z\7g0=:<:i1=5?4}r6g3?6=:rT?o95242`95=7<uz>o:7>52z\7g6=:<:k1=5?4}r6g1?6=:rT?o?5242;95=7<uz>o87>52z\7g4=:<:21=5?4}r6g7?6=:rT?o=5242595=7<uz>o>7>52z\7f2=:<;o1=5?4}r6`<?6=:rT?n;5243f95=7<uz?847>52z\66a=::h:1=5?4}r775?6=:rT>?8522`:95=7<uz??<7>52z\671=::h=1=5?4}r70b?6=:rT>?>522`495=7<uz?8i7>52z\677=::h?1=5?4}r70`?6=:rT>?<522`695=7<uz?8o7>52z\675=::h91=5?4}r70f?6=:rT>>k522`095=7<uz?8m7>52z\66`=::h;1=5?4}r70=?6=:rT>>n5228d95=7<uz?8:7>52z\66g=::0o1=5?4}r6bg?6=:rT?5l524439<3=z{=kj6=4={_6:=>;3=80=56s|4`;94?4|V=3370::1;44?xu3i10;6?uQ485891362?<0q~:n7;296~X31?1688?5649~w1g12909wS:65:?714<1<2wx8l;50;0xZ1?334>>=78<;|q7e1<72;qU84=4=572>24<uz>i97>52z\7e7=:<<;1;<5rs5`7>5<5sW>j=63;508;0>{t<k91<7<t^5c3?82293=;7p};b383>7}Y<0l019;>:7d8yv2e93:1>vP;9d9>007=>l1v9l?:181[2>l27?9<49d:p0d`=838pR97l;<665?0d3ty?mh4?:3y]0<d<5=?:6;l4}r6b`?6=:rT?5?5244392d=z{=k86=4={_6:5>;3=80=>6s|13794?c|5==36<9l;<0;4?3?3482?7;7;<1:6?3?349j97;7;<0ga?3?348m=7;7;<16=?3?349=o7;7;<116?3?349:<7;7;<1f2?3?349o87;7;<665?d23ty?954?:2y>00?==o168865193891302<<0q~::9;296~;3=00:4<5244`9g6=z{=<86=4<{<650?3a34>=>7;9;<657?7?92wx8;:50;0x9103282:70:96;a0?xu3=>0;6>u244:91c=:<<=1=5?4=57a>f2<uz>=>7>53z?727<608168;=55g9>030=k=1v9;n:18782193;3<63;6182<5=:<<l1=5>4=57a>41f3ty?9h4?:3;x9106282:70=?2;3;4>;51l0>n63=9g86f>;5i80>n63=a386f>;5i:0>n63=a586f>;5i<0>n63=a786f>;5i>0>n63=a986f>;5i90>n63<4186f>;4;o0>n63<3e86f>;4;j0>n63<3d86f>;4;k0>n63<3`86f>;4;10>n63<3682<5=:;:319o5234691g=:;<919o5234091g=:;<;19o5234291g=:;=l19o5235g91g=:;=n19o5235a91g=:;=h19o522e091g=::jl19o522e;91g=::m<1=5>4=3f6>4>7348jm7m;;<0a2?e3348h;7m<;|q71a<72;3p198?:0:2?846l3?i70<>c;7a?846j3?i70<>a;7a?84613?i70<>8;7a?846?3?i70<>6;7a?846=3?i70<>4;7a?841l3?i70<9c;7a?841j3?i70<9a;7a?84113?i70<98;7a?841?3?i70<96;7a?841=3?i70<94;7a?84213?i70<:8;7a?842?3?i70<:6;7a?842=3?i70<:4;7a?842;3?i70<:2;7a?84293?i70<:0;7a?87c03?i70?k7;7a?87c>3?i70?k5;7a?87c<3?i70?k3;7a?87c:3?i70?k1;7a?87c83?i70?lf;7a?xu3=j0;6<;t=57e>4>634>8:7;m;<601?3e34>887;m;<607?3e34>8>7;m;<605?3e34>8<7;m;<61b?3e34>8i7;m;<60`?3e34>8o7;m;<60f?3e34>8m7;m;<60=?3e34>847;m;<603?3e34>9i7;m;<61`?3e34>>?7m;;<665?7?12wx8;;50;1x910f282;70:99;3;4>;3>?0:;l5rs54;>5<5kr7?:l4>809>72c=91:01>9k:0:3?85e83?i70=m1;7a?85e;3?i70=m4;7a?85e=3?i70=m6;7a?85e?3?i70=m8;7a?85e13?i70=ma;7a?85e:3?i70:?4;7a?827;3?i70:?1;7a?82783?i70:?2;7a?85an3?i70=ie;7a?85ak3;3<63<fc86f>;4nm0>n63;1086f>;38o0:4=5240291g=:<8819o5240191g=:<8<19o5240691g=:<8?19o5240591g=:<8219o5243a91g=:<;h19o5243c91g=:<;319o5243:91g=:<;=19o5243491g=:<;?19o5243691g=:<;919o5rs544>5<51r7?:44>809>5g6==k16=lh55c9>5dc==k16=lj55c9>5de==k16=ll55c9>5dg==k16=l755c9>5d>==k16=l955c9>656==k16=kh55c9>5cc==k16=kj55c9>5ce==k16=kl55c9>5cg==k16=k755c9>5c>==k16=k955c9>5`e==k16=hl55c9>5`g==k16=h755c9>5`>==k16=h955c9>5`0==k16=h;55c9>5`2==k16=h=55c9>613==k16>9:55c9>615==k16>9<55c9>617==k16>9>55c9>66`==k16>>k55c9>66b==k16>>m55c9~w6642909w0=?2;7e?857<3;<m6s|31094?5|5::96<6>;<0g0?e4348ho7m<;|q1e<<72;q6>4k55g9>6dg=9>k0q~<nd;296~;51o0>j63=ad823d=z{;km6=4={<0b5?3a348i<7?8a:p6g7=838p1?o=:4d897d528=j7p}=b283>7}::h919k522c6952g<uz8i;7>52z?1e1<2n279n44>7`9~w7df2909w0<n5;7e?84ei3;<m6s|2ca94?4|5;k=68h4=3``>41f3ty9nh4?:3y>6d1==o16>ok516c8yv4d:3:1>v3=a986b>;5k10:;l5rs3ca>5<5s48j<7;i;<0bg?70i2wx?:h50;1x961b2<l01>9k:4d896>728=j7p}<7e83>6}:;>n1=5?4=2a:>f5<5:2;6n:4}r1bb?6=:r78n=4:f:?0e0<6?h1v>lm:18185e93?m70=7e;34e>{t;ki1<7<t=2`0>0`<5:2m6<9n;|q0fa<72;q6?o:55g9>7<6=9>k0q~=me;296~;4j<0>j63<90823d=z{:hm6=4={<1a2?3a349h<7?8a:p7f7=838p1>l8:4d896e528=j7p}<c283>7}:;k219k523b6952g<uz9h97>52z?0f<<2n278o;4>7`9~w6e02909w0=ma;7e?85d?3;<m6s|39c94?4|5:h968h4=2:b>41f3ty9<l4?:4y>6=?=k:16>5>5609>642=91;01?hm:b4897c?2j<0q~=;1;291~;5000h863<4c82<4=:9091o9522d:9g0=:<<;1885rs3::>5<4s48357?8a:?1<5<60:16>4=51068yv4?83:1?v3=81823d=::1;1955228691==z{;3o6=4={<0:7?70i279ml4l6:p65d=83?p1?6n:b1897>62?;01??::0:2?84aj3i?70<j8;a7?xu4<;0;6;u229c9g1=:;=i1=5?4=0;0>f5<58396n:4=3g;>f5<5=?:6984}r0;e?6=;r794l4>7`9>6=7=91901?7;:037?xu5080;6>u2293952g<5;296864=3;6>0><uz8<j7>58z?1=1<6?h16>lk5c29>6g6=k<16>o<5c79>6g>=k:16>o;5c29>6g0=k?16>n?5c29~w76d290>w0<7b;a0?84?:3<:70<>6;3;5>;5nj0h:63=e88`2>{t;=91<78t=3:a>f2<5:>o6<6>;<3:6?e434;2=7m;;<0f=?e234>>=7:8;|q1<g<72:q6>5l516c897>5282870<65;320>{t:181<7=t=3:1>41f3483?7;7;<0:2?3?3ty9;o4?:8y>6<3=9>k01?l?:b6897d52j901?m<:b7897d?2j>01?l::b6897e32j901?m::b1897e62j>0q~<?d;291~;50j0h?63=82855>;59>0:4<522ga9g1=::l31o95rs267>5<1s483o7m;;<17a?7?927:5<4l3:?2=5<d<279i44l3:?714<302wx>5m50;1x97>d28=j70<73;3;7>;51?0:=95rs3:0>5<4s483?7?8a:?1<1<202795:4:8:p62e=832p1?79:05b?84e:3i?70<l3;a7?84e03i>70<m5;a6?84d<3i?70<l5;a7?84d93i>7p}=0d83>0}::1n1o>52296924=::821=5?4=3dg>f0<5;oj6n84}r171?6=>r794i4l4:?00c<60816=4>5c29>5=`=k=16>ho5c49>007=<01v?6k:18084?l3;<m63=8582<6=::0=1=<:4}r0;0?6=;r79494>7`9>6=3==116>465599~w71c2902w0<67;34e>;5j=0h863=bc8`1>;5k:0h?63=be8`1>;5j10h:63=c58`1>;5k<0h963=c08`2>{t:9l1<7;t=3:f>f5<5;2>6;?4=33:>4>6348mh7m;;<0fe?e33ty88;4?:7y>6=c=k=16?8>5193894>a2j901<6j:b6897cf2j9019;>:5c8yv4?m3:1?v3=8d823d=::1?1=5=4=3;;>4733ty9484?:2y>6=3=9>k01?69:4:897?>2<20q~<8e;29=~;5110:;l522c;9g6=::kh1o9522cc9g1=::kn1o9522bc9g1=::j:1o8522b`9g0=::j?1o;5rs333>5<2s483j7m<;<0;2?06348:m7?71:?1b`<d>279io4l6:p711=83<p1?6i:b689636282:70?7e;a0?87?l3i?70<jb;a6?82293>i7p}=8g83>6}::1l1=:o4=3:5>4>4348257?>4:p6=0=839p1?69:05b?84??3?370<6a;7;?xu5?>0;6:u228;952g<5;hj6n=4=3`g>f5<5;ij6n=4=3`e>f2<5;i;6n:4=3aa>f2<uz8:=7>55z?1=5<d;2794:491:?15g<60816>kk5c59>6`d=k=1v>:7:18584>83i?70=:2;3;5>;60m0h?63>8b8`0>;5mk0h?63;5087g>{t:0:1<7=t=3;3>41f3483;7?73:?1=d<69=1v?68:18084??3;<m63=8986<>;51k0>46s|26:94?0|5;3j6<9n;<0ag?e4348h57m<;<0ab?e4348h<7m<;<0`f?e43ty9=?4?:4y>6<7=k:16>565609>64e=91;01?hi:b4897cd2j<0q~=;9;292~;5180h863<5282<4=:91i1o>5219`9g1=::li1o85244390a=z{;3:6=4<{<0:5?70i279454>829>6<d=98>0q~<78;296~;5010:;l5228a91==z{;=26=4:{<0:f?70i279nh4l3:?1g<<d<279mn4l3:?1g3<d<2wx><=50;6x97?52j901??k:0:2?84an3i?70<jc;a7?xu4<h0;6;u22809g1=:9m219k5234695=7<582i6n=4=3g`>f5<5=?:69h4}r0:6?6=:r795?4>7`9>6<e=98>0q~<8a;290~;51j0:;l522b;9g0=::hi1o9522b:9g6=z{=;26=4:{<1:f?e43492>78>;<617?7?927:5n4l4:?714<4i2wx=4j50;6x96?e2j>01<o8:0:2?850>3i=70=93;a5?xu41k0;6>u238`952g<5:396<6<;<1b1?76<2wx?4<50;1x96?528=j70=63;7;?85f>3?37p}>9d83>1}:;0i1o>521`:95=7<5:==6n:4=240>f2<uz>:m7>56z?0=f<d<2785>491:?761<60816=4m5c29>5<d=k=1688?53c9~w6?d2908w0=6c;34e>;41:0:4>523`49542<uz92?7>53z?0=6<6?h16?4:5599>7d1==11v>66:18585f>3;<m63<8g8`0>;4190h963<908`2>;40j0h?63<8d8`6>{t90l1<7:t=2;g>f5<58k26<6>;<143?e1349=87m9;|q75g<72?q6?4j5c59>7<2=>8168?;5193894?e2j901<7n:b6891362:i0q~=6d;297~;41m0:;l5238695=5<5:k<6<?;;|q0=1<72:q6?4:516c896?22<201>o7:4:8yv5?=3:19v3<a6823d=:;1l1o>523829g6=:;0;1o>5239a9g1=z{8k;6=4;{<1:a?e434;jm7?71:?032<d<278:94l4:p04e=83<p1>7j:b6896?22?;019<9:0:2?87>i3i870?69;a7?822939o7p}<9d83>6}:;0o1=:o4=2;6>4>4349j47?>4:p7<3=839p1>7::05b?85>>3?370=n9;7;?xu40?0;69u23`:952g<5:3;6n:4=2;2>f3<5:2h6n;4}r3b5?6=<r785k4l3:?2eg<60816?:65c79>733=k?1v9?k:18585>n3i?70=66;42?825?3;3=63>988`7>;6110h863;5080a>{t;0l1<7=t=2;e>41f3492:7?73:?0e<<69=1v>79:18085>>3;<m63<9686<>;4ih0>46s|39594?5|5:k26<9n;<1:5?e33493o7m9;|q75`<72?q6?l>5c29>7<1=>8168?65193894??2j901<78:b6891362:l0q~?n2;290~;4i90h863>ab82<4=:;>21o9523779g1=z{:k;6=4<{<1b4?70i2785:4>829>7dg=98>0q~=67;297~;41>0:;l5238:91==:;hh1955rs2:;>5<1s49jm7?8a:?0g5<d;278o?4l3:?0g1<d;2784o4l3:?0g=<d;2wx8<h50;4x96g62j901>77:738914>282:70?67;a0?87>>3i?70::1;63?xu6i:0;69u23`39g1=:9hn1=5?4=25:>f0<5:<=6n84}r1b5?6=;r78m<4>7`9>7<>=91901>om:037?xu4110;6>u238:952g<5:326864=2c`>0><uz93=7>55z?0eg<6?h16?n<5c59>7f2=k<16?5l5c59>7f>=k=1v9<?:18585f:3i870=69;42?825i3;3=63>978`7>;61<0h863;50875>{t9h>1<7:t=2c1>f2<58kn6<6>;<14=?e3349=:7m;;|q0e7<72:q6?l<516c896?>282870=nc;320>{t;031<7=t=2;:>41f3492m7;7;<1b`?3?3ty84?4?:5y>7de=9>k01>m;:b6896e12j901>m7:b78yv2593:1:v3<a28`7>;41h0==63;2c82<4=:90?1o>521869g1=:<<;18?5rs0c6>5<3s49j?7m;;<3bb?7?9278;l4l6:?022<d>2wx?l=50;1x96g428=j70=6a;3;7>;4im0:=95rs2;b>5<5s492m7?8a:?0e`<202wx?5=50;6x96gc28=j70=l6;a7?85d?3i870=7a;a0?xu3:;0;68u23`69g6=::=?19k5243a95=7<583?6n=4=572>12<uz;j:7>54z?0e1<d<27:n=4>809>72g=k=16?;95c59~w6g32909w0=n4;34e>;4il0:=95rs2:7>5<4s49ji7?8a:?0g2<d<2784l4l4:p6ab=838p1?k=:4:897c628=j7p}=e683>7}::l81=5=4=3g`>41f3ty8<=4?:3y>6`4=9>k01>>;:b78yv4ck3:1>v3=e086<>;5m90:;l5rs3g5>5<5s48n=7?73:?1ag<6?h1v?jm:18184b83?370<kf;34e>{t:l?1<7<t=3g3>4>4348nm7?8a:p6ag=838p1?ji:4:897bb28=j7p}=e583>7}::ml1=5=4=3g:>41f3ty9i>4?:3y>6ac=91901?k7:05b?xu5n90;6?u22g791==::o>1=:o4}r0ee?6=:r79j84>829>6c`=9>k0q~=?1;296~;5n<0:;l523169g6=z{;om6=4={<0e0?3?348m?7?8a:p6c?=838p1?h;:0:0?84am3;<m6s|2dg94?4|5;l86864=3d1>41f3ty9j54?:3y>6c5=91901?hk:05b?xu5mm0;6?u22g091==::o;1=:o4}r0e3?6=:r79j?4>829>6ce=9>k0q~<i6;296~;5n80:4>522g`952g<uz9>47>52z?01a<202789n4>7`9~w6052909w0=:d;3;7>;4>>0:;l5rs25a>5<5s49>h7?8a:?0<5<d;2wx?8950;0x963d2<201>;m:05b?xu4>80;6?u234a95=5<5:<=6<9n;|q013<72;q6?8l5599>70g=9>k0q~=90;296~;4=k0:4>52377952g<uz9>97>52z?01d<20278944>7`9~w63a2909w0=:a;3;7>;4>=0:;l5rs27f>5<5s49>57?73:?026<6?h1v>8m:18185083?370=9f;34e>{t;>?1<7<t=253>4>4349<m7?8a:p72e=838p1>9?:05b?85?83i=7p}<6`83>7}:;?l1955237g952g<uz9<87>52z?02c<60:16?:7516c8yv5113:1>v3<6d86<>;4>m0:;l5rs250>5<5s49=i7?73:?03=<6?h1v>87:181851l3?370=9c;34e>{t;>81<7<t=24g>4>4349<;7?8a:p727=838p1>8l:0:0?850>3;<m6s|1g494?3|58h;68h4=323>4>634;i>7m;;<3a0?e434;i:7m:;|q2f4<72;q6=lh55g9>5g4=9>k0q~?m3;296~;6il0>j63>b5823d=z{8h>6=49{<3b`?3a34;i:7?8a:?2f=<d<27:nl4l3:?2ff<d=27:nh4l6:p5g1=838p1<ol:4d894d?28=j7p}>b883>7}:9hh19k521cc952g<uz;in7>52z?2ed<2n27:nn4>7`9~w4dc2909w0?n9;7e?87en3;<m6s|1b394?4|58k368h4=0a1>41f3ty:o>4?:3y>5d1==o16=n:516c8yv41;3:19v3=1e86b>;5>m0:4<5220d9g1=::;;1o>522319g0=z{;;n6=4={<02g?3a348:j7?8a:p676=838p1??m:4d8974628=j7p}=2383>3}::8k19k52231952g<5;8>6n:4=304>f5<5;826n;4=30a>f0<uz8987>52z?15<<2n279>84>7`9~w7412909w0<>8;7e?845?3;<m6s|23:94?4|5;;<68h4=30:>41f3ty9>l4?:3y>640==o16>?m516c8yv45m3:1>v3=1486b>;5:o0:;l5rs313>5<5s48:87;i;<005?70i2wx>9h50;0x970c2<l01?;6:0:2?xu5<l0;6?u227a91c=::<21=5?4}r056?6=<r79:n4>809>64`=k:16>??5c59>675=k?1v?:k:181841j3?m70<:7;3;5>{t:?;1<7=t=34a>4>63489=7m:;<017?e43ty98n4?:3y>63g==o16>8851938yv4183:1>v3=6`82<4=::;91o95rs36a>5<5s48=57;i;<061?7?92wx>8h50;7x970>282:70<=5;a0?845?3i?70<=9;a5?845j3i>7p}=4`83>7}::?219k5224695=7<uz8>i7>54z?12=<60816>?95c49>67?=k:16>?l5c59~w72>2909w0<97;7e?842;3;3=6s|24f94?5|5;<<6<6>;<01=?e33489n7m<;|q10=<72;q6>;855g9>604=91;0q~<:c;290~;5>?0:4<5223a9g6=::;l1o9522239g0=z{;><6=4={<051?3a348>=7?71:p60d=839p1?8::0:2?845n3i870<<1;a7?xu5<?0;6?u227691c=::<:1=5?4}r06e?6=:r79:94>809>667=k:1v<k=:18184783?m70?jc;3;5>{t9l;1<7<t=0de>0`<58oi6<6>;|q2b0<72=q6=kh5193894d52j901<l;:b6894d12j<0q~?j0;296~;6nl0>j63>e`82<4=z{8l?6=4<{<3ea?7?927:n94l5:?2f3<d;2wx=ih50;0x94`c2<l01<k6:0:2?xu6n:0;6?u21gf95=7<58h=6n:4}r3ga?6=:r7:jn4:f:?2a=<6081v<h=:18687ak3;3=63>b98`7>;6jh0h863>bb8`2>;6jl0h96s|1ef94?4|58li68h4=0g4>4>63ty:j<4?:5y>5cd=91;01<ln:b7894dd2j901<lj:b68yv7ck3:1>v3>f`86b>;6m?0:4<5rs0d3>5<4s4;mm7?71:?2ff<d<27:nh4l3:p5ad=838p1<h6:4d894c2282:7p}>eg83>1}:9o31=5?4=0`e>f5<58i96n:4=0a7>f3<uz;om7>52z?2b=<2n27:i94>809~w4cb2908w0?i8;3;5>;6k;0h?63>c58`0>{t9m31<7<t=0d4>0`<58o86<6>;|q2aa<72;q6=k95193894e32j90q~<<b;296~;5=00>j63=4482<4=z{;9j6=4={<06<?3a348?87?71:p66?=838p1?;8:4d89724282:7p}=3983>7}::<<19k5225095=7<uz88;7>52z?110<2n2798<4>809~w7512909w0<:4;7e?84383;3=6s|22794?4|5;?868h4=31e>4>63ty9?94?:3y>604==o16>>k51938yv44;3:1>v3=5086b>;5;m0:4<5rs311>5<5s48><7;i;<00g?7?92wx=nk50;0x94cd2<l01<j7:0:2?xu6km0;6?u21d`91c=:9m=1=5?4}r3`g?6=:r7:il4:f:?2`3<6081v<mm:18187b13?m70?k5;3;5>{t9jk1<7<t=0g;>0`<58n?6<6>;|q2g<<72;q6=h955g9>5a5=91;0q~?l8;296~;6m?0>j63>d382<4=z{8i<6=4={<3f1?3a34;o=7?71:p5f0=838p1<k;:4d894b7282:7p}>c483>7}:9l919k521bd95=7<uz8;=7>52z?2`2<2n27:4o4>7`9~w7652909w0?k6;7e?87?k3;<m6s|21194?4|58n>68h4=0:g>41f3ty9<94?:3y>5a2==o16=5k516c8yv47=3:1>v3>d286b>;60o0:;l5rs325>5<5s4;o>7;i;<3:4?70i2wx>=950;0x94b62<l01<7>:05b?xu5810;6?u21e291c=:9081=:o4}r03=?6=:r7:ok4:f:?2=6<6?h1v?8j:181843<3?m70?64;34e>{t:?l1<7<t=360>0`<583>6<9n;|q135<72;q6>9<55g9>5<0=9>k0q~<81;296~;5<80>j63>96823d=z{;=96=4={<074?3a34;247?8a:p625=838p1?=i:4d894?>28=j7p}=7583>7}:::o19k5218c952g<uz8<97>52z?17a<2n27:5o4>7`9~w7112909w0<<c;7e?87>k3;<m6s|44694?70s49?<7;9;<10b?313498h7;9;<10g?313498i7;9;<10f?313498m7;9;<10<?313498;7;9;<10=?31349>87;9;<167?31349>>7;9;<165?31349><7;9;<17b?31349?i7;9;<17`?31349?o7;9;<17f?31348ho7?8a:?716<d;278<94l4:p75`=838p1>:?:4d8964e28=j7p}<3783>1}:;=:1=5?4=277>0`<5;lm6n=4=20`>f5<uz9;i7>52z?07c<2n278>l4>7`9~w652290?w0=<f;3;5>;4=:0>j63=fg8`1>;4:80h?6s|31a94?4|5:9o68h4=20;>41f3ty8?>4?:5y>76b=91;01>;>:4d897`b2j?01>?k:b18yv57j3:1>v3<3b86b>;4:>0:;l5rs211>5<3s498o7?71:?015<2n279ji4l3:?05g<d;2wx?=j50;0x965b2<l01><6:05b?xu4;=0;69u232g95=7<5:?968h4=3df>f5<5:;m6n=4}r13e?6=:r78?o4:f:?063<6?h1v>=>:187854j3;3=63<4g86b>;5nm0h963<188`7>{t;931<7<t=21b>0`<5:8>6<9n;|q075<72=q6?>o51938962b2<l01?hl:b1896702j90q~=?7;296~;4;10>j63<22823d=z{:8n6=4;{<10<?7?92788n4:f:?1bg<d;278=>4l3:p750=838p1>=8:4d8964528=j7p}<2e83>1}:;:=1=5?4=26a>0`<5;li6n;4=232>f5<uz9;47>52z?07<<2n278>94>7`9~w64a290?w0=<9;3;5>;4<m0>j63=fb8`1>;49<0h?6s|33294?4|5:8i6864=203>41f3ty8>n4?:3y>77d=98>01><l:05b?xu49l0;6>u233c91==:;;:1955230g952g<uz99=7>53z?06d<69=16??>51918964628=j7p}<1b83>6}:;;31955230g91==:;8i1=:o4}r12b?6=;r78>44>159>74c=91901>?i:05b?xu49h0;6>u233:91==:;8i1955230c952g<uz9:h7>53z?06=<69=16?<m51918967c28=j7p}<1983>6}:;;=1955230c91==:;821=:o4}r12f?6=;r78>:4>159>74g=91901>?m:05b?xu49?0;6>u233491==:;8219552304952g<uz9:57>53z?063<69=16?<651918967>28=j7p}<1583>6}:;;?1955230491==:;8>1=:o4}r123?6=;r78>84>159>740=91901>?8:05b?xu49;0;6>u233691==:;8>19552300952g<uz9:97>53z?061<69=16?<:51918967228=j7p}<1183>6}:;;91955230091==:;8:1=:o4}r127?6=;r78>>4>159>744=91901>?<:05b?xu4980;6>u23309542<5:;;6<6<;<125?70i2wx>i=50;0x97b52<l01?j;:05b?xu5l;0;65u22e095=7<5;n:6n:4=3f;>f3<5;n?6n;4=3ag>f5<5;ih6n:4=3af>f2<5;i<6n84}r0g4?6=;r79ok4:f:?1`<<2n279h<4>7`9~w7ea2903w0<lf;3;5>;5l80h?63=d98`0>;5l=0h863=ce8`0>;5kj0h:63=cd8`7>;5k>0h96s|2e;94?2|5;n26<6>;<0be?e2348i:7m<;<0`3?e33ty9h:4?:2y>6a0==o16>i;55g9>6a>=9>k0q~<k5;296~;5l<0:4<522e:9g6=z{=?=6=4=0z?741<2>27?<>4:6:?744<2>27?<=4:6:?747<2>278jk4:6:?0b`<2>278jn4:6:?0bg<2>278ji4:6:?754<2>27?<k4:6:?755<2>27?=?4:6:?756<2>27?=;4:6:?751<2>27?=84:6:?752<2>27?=54:6:?76f<2>27?>o4:6:?76d<2>27?>44:6:?76=<2>27?>:4:6:?763<2>27?>84:6:?761<2>27?>>4:6:?0g<<6?h1688?547d8yv5c;3:1>v3;0586b>;4mo0:;l5rs2db>5<3s4>;87?71:?75=<2n278;l4l3:?0b5<d;2wx?i<50;0x91642<l01>kj:05b?xu4n00;69u241195=7<5=;<68h4=25b>f3<5:o>6n=4}r1g4?6=:r7?<<4:f:?0af<6?h1v>h8:18782793;3=63;1486b>;4?00h963<e08`7>{t;jl1<7<t=523>0`<5:oi6<9n;|q0b3<72=q68=>5193891732<l01>97:b1896ba2j90q~=k1;296~;38;0>j63<ee823d=z{:l36=4;{<636?7?927?=;4:f:?03<<d;278i>4l3:p7fc=838p1>hi:4d896cf28=j7p}<f483>1}:;ol1=5?4=530>0`<5:=36n;4=2fg>f5<uz9hh7>52z?0b`<2n278i44>7`9~w6`3290?w0=ie;3;5>;39;0>j63<768`7>;4lk0h?6s|3b`94?4|5:lh68h4=2g4>41f3ty8j?4?:5y>7ce=91;019??:4d896112j901>j8:b18yv5di3:1>v3<fc86b>;4m?0:;l5rs2d2>5<3s49mn7?71:?74c<2n278;;4l5:?0`0<d;2wx?nm50;0x96`c2<l01>k7:05b?xu4n:0;69u23gf95=7<5=;:68h4=254>f3<5:n26n=4}r1f0?6=:r78ik4:8:?0a1<6?h1v>h?:18185bn3;:863<f1823d=z{:o96=4<{<1fa?3?349n87;7;<1f6?70i2wx?h;50;1x96cb28;?70=j4;3;7>;4m<0:;l5rs2g3>5<4s49nh7;7;<1f6?3?349n<7?8a:p7`5=839p1>kk:037?85b:3;3?63<e2823d=z{:nn6=4<{<1fg?3?349n<7;7;<1ga?70i2wx?h?50;1x96cd28;?70=j0;3;7>;4m80:;l5rs2f`>5<4s49nn7;7;<1ga?3?349oo7?8a:p7a`=839p1>km:037?85cm3;3?63<dg823d=z{:nj6=4<{<1fe?3?349oo7;7;<1ge?70i2wx?ij50;1x96cf28;?70=kc;3;7>;4lm0:;l5rs2f;>5<4s49n57;7;<1ge?3?349o47?8a:p7ad=839p1>k6:037?85ci3;3?63<dc823d=z{:n=6=4<{<1f<?3?349o47;7;<1g2?70i2wx?i750;1x96c?28;?70=k8;3;7>;4l00:;l5rs2f7>5<4s49n;7;7;<1g2?3?349o87?8a:p7a1=839p1>k8:037?85c>3;3?63<d6823d=z{:n>6=4<{<1f2?76<278h94>829>7a3=9>k0q~:?7;297~;3980:4<5243791c=:;?>1o85rs526>5<4s4>;j7?71:?766<2n278:>4l5:p050=839p19??:0:2?825<3?m70=93;a0?xu3810;6>u240095=7<5=8=68h4=247>f5<uz>;57>53z?756<608168?955g9>733=k<1v9>l:180826>3;3=63;2`86b>;4>?0h?6s|41c94?5|5=;?6<6>;<61<?3a349=97m<;|q74g<72:q68<;51938914>2<l01>89:b78yv27l3:1?v3;1682<4=:<;h19k523759g0=z{=:n6=4<{<62<?7?927?>n4:f:?022<d;2wx88;50;30824>3?=70:<5;75?824<3?=70:<3;75?824:3?=70:<1;75?82483?=70:=f;75?824m3?=70:<d;75?824k3?=70:<b;75?824i3?=70:<9;75?82403?=70:<7;75?825m3?=70:=d;75?84dl3;<m6s|45594?4|5=9=68h4=572>g7<uz>?:7>52z?770<2n27?9<4n2:p013=838p19=;:4d891362h:0q~:;4;296~;3;:0>j63;508:b>{t<=91<7<t=511>0`<5=?:64k4}r676?6=:r7??<4:f:?714<>l2wx89?50;0x91572<l019;>:8a8yv2383:1>v3;2g86b>;3=80jn6s|44294?4|5=9n68h4=572>dg<uz>?j7>52z?77a<2n27?9<4nf:p01c=838p19=l:4d891362h30q~:;d;296~;3;k0>j63;508b<>{t<=i1<7<t=51b>0`<5=?:6l94}r67f?6=:r7??44:f:?714<f>2wx89o50;0x915?2<l019;>:`78yv2313:1>v3;3686b>;3=80j86s|45:94?4|5=8n68h4=572>d5<uz>8j7>52z?76a<2n27?9<46b:p004=838p19;<:05b?82293h=7p}>6483>7}::hk1o>522bg9543<uz89h7>54z?16f<d<279>k4l5:?174<d>279>o4>7`9~w4e7290?w0?mf;a7?87d:3i>70?l4;a5?87em3;<m6s|17194??|5;kn6n:4=3`3>f5<5;h96n;4=3`7>f5<5;h26n;4=3``>f2<5;hn6n:4=3a5>f5<5;i<6<9n;|q22=<72:q6>o:5c49>6gd=k?16>o;516c8yv5?l3:1;v3<c18`0>;4k;0h963<c58`2>;40j0:;l523b49g0=:;j=1o85239c9g0=z{8<i6=4<{<0a=?e3348i47?8a:?1g3<d=2wx=;?50;6x97d>2j<01?ln:b7897e428=j70<nc;a5?xu6>j0;6?u22c`9g6=::j=1=<;4}r36e?6=:r79no4>7`9>6gg=k?1v<8k:18184ek3i>70<md;34e>{t9?>1<7=t=3``>f0<5;ij6<9n;<0`<?e23ty::k4?:3y>6gc=k<16>n>516c8yv71m3:1>v3=bd8`2>;5jo0:;l5rs3a:>5<5s48h57?8a:?1g=<d<2wx=;750;0x97e42j<01?l9:036?xu6>?0;6?u22cf9g3=::k?1=<;4}r30a?6=:r79mn4l5:?1gg<6?h1v<<l:18084di3i>70<mf;a6?84e>3;<m6s|14594?4|5;ij6n84=3a7>4723ty:944?:3y>6g`=k?16>n;51078yv72k3:1>v3=c98`2>;5k?0:;l5rs07e>5<5s493n7?8a:?0g3<d>2wx=;>50;0x96e02j<01>m7:05b?xu6>>0;6?u22b49g3=::jh1=<;4}r356?6=:r79o=4l6:?1g4<69<1v<8n:18185?i3i=70=l8;321>{t;9?1<7<t=3af>41f348i:7m:;|p0de=838pR97n;<71>1?f3->=n7?9e:p0dg=838pR976;<71>1?>3->=n7?9f:p0d?=838pR977;<71>1??3->=n7?80:p0d>=838pR978;<71>1?03->=n7?85:p0d1=838pR979;<71>1?13->=n7?=6:p0d0=838pR97:;<71>1?23->=n7?=c:p0d3=838pR97;;<71>1?33->=n7?<7:p0d2=838pR97<;<71>1?43->=n7?<e:p0g3=838pR9o=;<71>1g53->=n7?;9:p0g2=838pR9o>;<71>1g63->=n7?:2:p0g5=838pR9o?;<71>1g73->=n7?:6:p0g4=838pR97i;<71>1?a3->=n7?:7:p0g7=838pR97j;<71>1?b3->=n7?:8:p0g6=838pR97k;<71>1?c3->=n7?:9:p0d`=838pR97l;<71>1?d3->=n7?:b:p0dc=838pR97m;<71>1?e3->=n7?:c:p0db=838pR97=;<71>1?53->=n7?:d:p0d5=838pR97>;<71>1?63->=n7?:e:p17g=838pR8<n;<71>04f3->=n7?81:p114=838pR8:=;<71>0253->=n7?82:p112=838pR8:;;<71>0233->=n7?83:p11d=838pR8:m;<71>02e3->=n7?84:p135=838pR88<;<71>0043->=n7?86:p0a7=838pR9li;<71>1da3->=n7?=7:p0f`=838pR9lj;<71>1db3->=n7?=8:p0fc=838pR9lk;<71>1dc3->=n7?=9:p0fb=838pR9ll;<71>1dd3->=n7?=a:p0fe=838pR9lm;<71>1de3->=n7?=b:p0fd=838pR9ln;<71>1df3->=n7?=d:p0fg=838pR9l6;<71>1d>3->=n7?=e:p0f?=838pR9l7;<71>1d?3->=n7?=f:p0ag=838pR9m8;<71>1e03->=n7?<0:p0a?=838pR9m9;<71>1e13->=n7?<1:p0a>=838pR9m:;<71>1e23->=n7?<2:p0a1=838pR9m;;<71>1e33->=n7?<3:p0a0=838pR9m<;<71>1e43->=n7?<4:p0a3=838pR9m=;<71>1e53->=n7?<5:p0a2=838pR9m>;<71>1e63->=n7?<6:p0a5=838pR9m?;<71>1e73->=n7?<8:p0a4=838pR9l8;<71>1d03->=n7?<9:p0f>=838pR9l9;<71>1d13->=n7?<a:p0ae=838pR9jl;<71>1bd3->=n7?<b:p0`4=838pR9k=;<71>1c53->=n7?<c:p16>=838pR8<k;<71>04c3->=n7?<d:p117=838pR8=:;<71>0523->=n7?<f:p116=838pR8=;;<71>0533->=n7?;0:p16`=838pR8=<;<71>0543->=n7?;1:p16c=838pR8==;<71>0553->=n7?;2:p16b=838pR8=>;<71>0563->=n7?;3:p16e=838pR8=?;<71>0573->=n7?;4:p16d=838pR8<i;<71>04a3->=n7?;5:p16g=838pR8<j;<71>04b3->=n7?;6:p16?=838pR8<l;<71>04d3->=n7?;7:p160=838pR8<m;<71>04e3->=n7?;8:p10?=838pR8:j;<71>02b3->=n7?;a:p134=838pR8;9;<71>0313->=n7?;b:p137=838pR8;:;<71>0323->=n7?;c:p136=838pR8;;;<71>0333->=n7?;d:p10`=838pR8;<;<71>0343->=n7?;e:p10c=838pR8;=;<71>0353->=n7?;f:p10b=838pR8;>;<71>0363->=n7?:0:p10e=838pR8;?;<71>0373->=n7?:1:p10d=838pR8:i;<71>02a3->=n7?:3:p10g=838pR8:k;<71>02c3->=n7?:4:p101=838pR8:l;<71>02d3->=n7?:5:~jgdd2909wE:9c:mfgb=838pD98l;|laf`<72;qC8;m4}o`ab?6=:rB?:n5rnca3>5<5sA>=o6sabb394?4|@=<h7p`mc383>7}O<?i0qcll3;296~N3>j1vbom;:181M21k2wenn;50;0xL10d3tdio;4?:3yK03e<ughh;7>52zJ72f=zfki36=4={I65g>{ijj31<7<tH54`?xhekh0;6?uG47a8ykddj3:1>vF;6b9~jged2909wE:9c:mffb=838pD98l;|lag`<72;qC8;m4}o``b?6=:rB?:n5rncf3>5<5sA>=o6sabe394?4|@=<h7p`md383>7}O<?i0qclk3;296~N3>j1vboj;:181M21k2weni;50;0xL10d3tdih;4?:3yK03e<ugho;7>52zJ72f=zfkn36=4={I65g>{ijm31<7<tH54`?xhelh0;6?uG47a8ykdcj3:1>vF;6b9~jgbd2909wE:9c:mfab=838pD98l;|la``<72;qC8;m4}o`gb?6=:rB?:n5rncg3>5<5sA>=o6sabd394?4|@=<h7p`me383>7}O<?i0qclj3;296~N3>j1vbok;:181M21k2wenh;50;0xL10d3tdii;4?:3yK03e<ughn;7>52zJ72f=zfko36=4={I65g>{ijl31<7<tH54`?xhemh0;6?uG47a8ykdbj3:1>vF;6b9~jgcd2909wE:9c:mf`b=838pD98l;|laa`<72;qC8;m4}o`fb?6=:rB?:n5rncd3>5<5sA>=o6sabg394?4|@=<h7p`mf383>7}O<?i0qcli3;296~N3>j1vboh;:181M21k2wenk;50;0xL10d3tdij;4?:3yK03e<ughm;7>52zJ72f=zfkl36=4={I65g>{ijo31<7<tH54`?xhenh0;6?uG47a8ykdaj3:1>vF;6b9~jg`d2909wE:9c:m=a?=83;pD98l;|lb5d<728qC8;m4}oc2f?6=9rB?:n5rn`3`>5<6sA>=o6saa0f94?7|@=<h7p`n1d83>4}O<?i0qco>f;295~N3>j1vbl<?:182M21k2wem??50;3xL10d3tdj>?4?:0yK03e<ugk9?7>51zJ72f=zfh8?6=4>{I65g>{ii;?1<7?tH54`?xhf:?0;6<uG47a8ykg5?3:1=vF;6b9~jd4?290:wE:9c:me7?=83;pD98l;|lb6d<728qC8;m4}oc1f?6=9rB?:n5rn`0`>5<6sA>=o6saa3f94?7|@=<h7p`n2d83>4}O<?i0qco=f;295~N3>j1vbl=?:182M21k2wem>?50;3xL10d3tdj??4?:0yK03e<ugk8?7>51zJ72f=zfh9?6=4>{I65g>{ii:?1<7?tH54`?xhf;?0;6<uG47a8ykg4?3:1=vF;6b9~jd5?290:wE:9c:me6?=83;pD98l;|lb7d<728qC8;m4}oc0f?6=9rB?:n5rn`1`>5<6sA>=o6saa2f94?7|@=<h7p`n3d83>4}O<?i0qco<f;295~N3>j1vbl:?:182M21k2wem9?50;3xL10d3tdj8?4?:0yK03e<ugk??7>51zJ72f=zfh>?6=4>{I65g>{ii=?1<7?tH54`?xhf<?0;6<uG47a8ykg3?3:1=vF;6b9~jd2?290:wE:9c:me1?=83;pD98l;|lb0d<728qC8;m4}oc7f?6=9rB?:n5rn`6`>5<6sA>=o6saa5f94?7|@=<h7p`n4d83>4}O<?i0qco;f;295~N3>j1vbl;?:182M21k2wem8?50;3xL10d3tdj9?4?:0yK03e<ugk>?7>51zJ72f=zfh??6=4>{I65g>{ii<?1<7?tH54`?xhf=?0;6<uG47a8ykg2?3:1=vF;6b9~jd3?290:wE:9c:me0?=83;pD98l;|lb1d<728qC8;m4}oc6f?6=9rB?:n5rn`7`>5<6sA>=o6saa4f94?7|@=<h7p`n5d83>4}O<?i0qco:f;295~N3>j1vbl8?:182M21k2wem;?50;3xL10d3tdj:?4?:0yK03e<ugk=?7>51zJ72f=zfh<?6=4>{I65g>{ii??1<7?tH54`?xhf>?0;6<uG47a8ykg1?3:1=vF;6b9~jd0?290:wE:9c:me3?=83;pD98l;|lb2d<728qC8;m4}oc5f?6=9rB?:n5rn`4`>5<6sA>=o6saa7f94?7|@=<h7p`n6d83>4}O<?i0qco9f;295~N3>j1vbl9?:182M21k2wem:?50;3xL10d3tdj;?4?:0yK03e<ugk<?7>51zJ72f=zfh=?6=4>{I65g>{ii>?1<7?tH54`?xhf??0;6<uG47a8ykg0?3:1=vF;6b9~jd1?290:wE:9c:me2?=83;pD98l;|lb3d<728qC8;m4}oc4f?6=9rB?:n5rn`5`>5<6sA>=o6saa6f94?7|@=<h7p`n7d83>4}O<?i0qco8f;295~N3>j1vbl6?:182M21k2wem5?50;3xL10d3tdj4?4?:0yK03e<ugk3?7>51zJ72f=zfh2?6=4>{I65g>{ii1?1<7?tH54`?xhf0?0;6<uG47a8ykg??3:1=vF;6b9~jd>?290:wE:9c:me=?=83;pD98l;|lb<d<728qC8;m4}oc;f?6=9rB?:n5rn`:`>5<6sA>=o6saa9f94?7|@=<h7p`n8d83>4}O<?i0qco7f;295~N3>j1vbl7?:182M21k2wem4?50;3xL10d3tdj5?4?:0yK03e<ugk2?7>51zJ72f=zfh3?6=4>{I65g>{ii0?1<7?tH54`?xhf1?0;6<uG47a8ykg>?3:1=vF;6b9~jd??290:wE:9c:me<?=83;pD98l;|lb=d<728qC8;m4}oc:f?6=9rB?:n5rn`;`>5<6sA>=o6saa8f94?7|@=<h7p`n9d83>4}O<?i0qco6f;295~N3>j1vblo?:182M21k2weml?50;3xL10d3tdjm?4?:0yK03e<ugkj?7>51zJ72f=zfhk?6=4>{I65g>{iih?1<7?tH54`?xhfi?0;6<uG47a8ykgf?3:1=vF;6b9~jdg?290:wE:9c:med?=83;pD98l;|lbed<728qC8;m4}ocbf?6=9rB?:n5rn`c`>5<6sA>=o6saa`f94?7|@=<h7p`nad83>4}O<?i0qconf;295~N3>j1vbll?:182M21k2wemo?50;3xL10d3tdjn?4?:0yK03e<ugki?7>51zJ72f=zfhh?6=4>{I65g>{iik?1<7?tH54`?xhfj?0;6<uG47a8ykge?3:1=vF;6b9~jdd?290:wE:9c:meg?=83;pD98l;|lbfd<728qC8;m4}ocaf?6=9rB?:n5rn```>5<6sA>=o6saacf94?7|@=<h7p`nbd83>4}O<?i0qcomf;295~N3>j1vblm?:182M21k2wemn?50;3xL10d3tdjo?4?:0yK03e<ugkh?7>51zJ72f=zfhi?6=4>{I65g>{iij?1<7?tH54`?xhfk?0;6<uG47a8ykgd?3:1=vF;6b9~jde?290:wE:9c:mef?=83;pD98l;|lbgd<728qC8;m4}oc`f?6=9rB?:n5rn`a`>5<6sA>=o6saabf94?7|@=<h7p`ncd83>4}O<?i0qcolf;295~N3>j1vblj?:182M21k2wemi?50;3xL10d3tdjh?4?:0yK03e<ugko?7>51zJ72f=zfhn?6=4>{I65g>{iim?1<7?tH54`?xhfl?0;6<uG47a8ykgc?3:1=vF;6b9~jdb?290:wE:9c:mea?=83;pD98l;|lb`d<728qC8;m4}ocgf?6=9rB?:n5rn`f`>5<6sA>=o6saaef94?7|@=<h7p`ndd83>4}O<?i0qcokf;295~N3>j1vblk?:182M21k2wemh?50;3xL10d3tdji?4?:0yK03e<ugkn?7>51zJ72f=zfho?6=4>{I65g>{iil?1<7?tH54`?xhfm?0;6<uG47a8ykgb?3:1=vF;6b9~jdc?290:wE:9c:me`?=83;pD98l;|lbad<728qC8;m4}ocff?6=9rB?:n5rn`g`>5<6sA>=o6saadf94?7|@=<h7p`ned83>4}O<?i0qcojf;295~N3>j1vblh?:182M21k2wemk?50;3xL10d3tdjj?4?:0yK03e<ugkm?7>51zJ72f=zfhl?6=4>{I65g>{iio?1<7?tH54`?xhfn?0;6<uG47a8ykga?3:1=vF;6b9~jd`?290:wE:9c:mec?=83;pD98l;|lbbd<728qC8;m4}ocef?6=9rB?:n5rn`d`>5<6sA>=o6saagf94?7|@=<h7p`nfd83>4}O<?i0qcoif;295~N3>j1vbo>?:182M21k2wen=?50;3xL10d3tdi<?4?:0yK03e<ugh;?7>51zJ72f=zfk:?6=4>{I65g>{ij9?1<7?tH54`?xhe8?0;6<uG47a8ykd7?3:1=vF;6b9~jg6?290:wE:9c:mf5?=83;pD98l;|la4d<728qC8;m4}o`3f?6=9rB?:n5rnc2`>5<6sA>=o6sab1f94?7|@=<h7p`m0d83>4}O<?i0qcl?f;295~N3>j1vbo??:182M21k2wen<?50;3xL10d3tdi=?4?:0yK03e<ugh:?7>51zJ72f=zfk;?6=4>{I65g>{ij8?1<7?tH54`?xhe9?0;6<uG47a8ykd6?3:1=vF;6b9~jg7?290:wE:9c:mf4?=83;pD98l;|la5d<728qC8;m4}o`2f?6=9rB?:n5rnc3`>5<6sA>=o6sab0f94?7|@=<h7p`m1d83>4}O<?i0qcl>f;295~N3>j1vbo<?:182M21k2wen??50;3xL10d3tdi>?4?:0yK03e<ugh9?7>51zJ72f=zfk8?6=4>{I65g>{ij;?1<7?tH54`?xhe:?0;6<uG47a8ykd5?3:1=vF;6b9~jg4?290:wE:9c:mf7?=83;pD98l;|la6d<728qC8;m4}o`1f?6=9rB?:n5rnc0`>5<6sA>=o6sab3f94?7|@=<h7p`m2d83>4}O<?i0qcl=f;295~N3>j1vbo=?:182M21k2wen>?50;3xL10d3tdi??4?:0yK03e<ugh8?7>51zJ72f=zfk9?6=4>{I65g>{ij:?1<7?tH54`?xhe;?0;6<uG47a8ykd4?3:1=vF;6b9~jg5?290:wE:9c:mf6?=83;pD98l;|la7d<728qC8;m4}o`0f?6=9rB?:n5rnc1`>5<6sA>=o6sab2f94?7|@=<h7p`m3d83>4}O<?i0qcl<f;295~N3>j1vbo:?:182M21k2wen9?50;3xL10d3tdi8?4?:0yK03e<ugh??7>51zJ72f=zfk>?6=4>{I65g>{ij=?1<7?tH54`?xhe<?0;6<uG47a8ykd3?3:1=vF;6b9~jg2?290:wE:9c:mf1?=83;pD98l;|la0d<728qC8;m4}o`7f?6=9rB?:n5rnc6`>5<6sA>=o6sab5f94?7|@=<h7p`m4d83>4}O<?i0qcl;f;295~N3>j1vbo;?:182M21k2wen8?50;3xL10d3tdi9?4?:0yK03e<ugh>?7>51zJ72f=zfk??6=4>{I65g>{ij<?1<7?tH54`?xhe=?0;6<uG47a8ykd2?3:1=vF;6b9~jg3?290:wE:9c:mf0?=83;pD98l;|la1d<728qC8;m4}o`6f?6=9rB?:n5rnc7`>5<6sA>=o6sab4f94?7|@=<h7p`m5d83>4}O<?i0qcl:f;295~N3>j1vbo8?:182M21k2wen;?50;3xL10d3tdi:?4?:0yK03e<ugh=?7>51zJ72f=zfk<?6=4>{I65g>{ij??1<7?tH54`?xhe>?0;6<uG47a8ykd1?3:1=vF;6b9~jg0?290:wE:9c:mf3?=83;pD98l;|la2d<728qC8;m4}o`5f?6=9rB?:n5rnc4`>5<6sA>=o6sab7f94?7|@=<h7p`m6d83>4}O<?i0qcl9f;295~N3>j1vbo9?:182M21k2wen:?50;3xL10d3tdi;?4?:0yK03e<ugh<?7>51zJ72f=zfk=?6=4>{I65g>{ij>?1<7?tH54`?xhe??0;6<uG47a8ykd0?3:1=vF;6b9~jg1?290:wE:9c:mf2?=83;pD98l;|la3d<728qC8;m4}o`4f?6=9rB?:n5rnc5`>5<6sA>=o6sab6f94?7|@=<h7p`m7d83>4}O<?i0qcl8f;295~N3>j1vbo6?:182M21k2wen5?50;3xL10d3tdi4?4?:0yK03e<ugh3?7>51zJ72f=zfk2?6=4>{I65g>{ij1?1<7?tH54`?xhe0?0;6<uG47a8ykd??3:1=vF;6b9~jg>?290:wE:9c:mf=?=83;pD98l;|la<d<728qC8;m4}o`;f?6=9rB?:n5rnc:`>5<6sA>=o6sab9f94?7|@=<h7p`m8d83>4}O<?i0qcl7f;295~N3>j1vbo7?:182M21k2wen4?50;3xL10d3tdi5?4?:0yK03e<ugh2?7>51zJ72f=zfk3?6=4>{I65g>{ij0?1<7?tH54`?xhe1?0;6<uG47a8ykd>?3:1=vF;6b9~jg??290:wE:9c:mf<?=83;pD98l;|la=d<728qC8;m4}o`:f?6=9rB?:n5rnc;`>5<6sA>=o6sab8f94?7|@=<h7p`m9d83>4}O<?i0qcl6f;295~N3>j1vboo?:182M21k2wenl?50;3xL10d3tdim?4?:0yK03e<ughj?7>51zJ72f=zfkk?6=4>{I65g>{ijh?1<7?tH54`?xhei?0;6<uG47a8ykdf?3:1=vF;6b9~jgg?290:wE:9c:mfd?=83;pD98l;|laed<728qC8;m4}o`bf?6=9rB?:n5rncc`>5<6sA>=o6sab`f94?7|@=<h7p`mad83>4}O<?i0qclnf;295~N3>j1vbol?:182M21k2weno?50;3xL10d3tdin?4?:0yK03e<ughi?7>51zJ72f=zfkh?6=4>{I65g>{ijk?1<7?tH54`?xhej?0;6<uG47a8ykde?3:1=vF;6b9~jgd?290:wE:9c:mfg?=83;pD98l;|lafd<728qC8;m4}o`af?6=9rB?:n5r}|CDF}cm8028>><e6c~DED|8tJK\vsO@
\ No newline at end of file diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.v b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.v new file mode 100644 index 000000000..4737fb1bf --- /dev/null +++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.v @@ -0,0 +1,3819 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 1995-2008 Xilinx, Inc. All rights reserved. +//////////////////////////////////////////////////////////////////////////////// +// ____ ____ +// / /\/ / +// /___/ \ / Vendor: Xilinx +// \ \ \/ Version: K.39 +// \ \ Application: netgen +// / / Filename: fifo_xlnx_1Kx18_2clk.v +// /___/ /\ Timestamp: Fri Jun 10 16:12:12 2011 +// \ \ / \ +// \___\/\___\ +// +// Command : -intstyle ise -w -sim -ofmt verilog /tmp/_cg/fifo_xlnx_1Kx18_2clk.ngc /tmp/_cg/fifo_xlnx_1Kx18_2clk.v +// Device : 3s2000fg456-5 +// Input file : /tmp/_cg/fifo_xlnx_1Kx18_2clk.ngc +// Output file : /tmp/_cg/fifo_xlnx_1Kx18_2clk.v +// # of Modules : 1 +// Design Name : fifo_xlnx_1Kx18_2clk +// Xilinx : /opt/Xilinx/10.1/ISE +// +// Purpose: +// This verilog netlist is a verification model and uses simulation +// primitives which may not represent the true implementation of the +// device, however the netlist is functionally correct and should not +// be modified. This file cannot be synthesized and should only be used +// with supported simulation tools. +// +// Reference: +// Development System Reference Guide, Chapter 23 and Synthesis and Simulation Design Guide, Chapter 6 +// +//////////////////////////////////////////////////////////////////////////////// + +`timescale 1 ns/1 ps + +module fifo_xlnx_1Kx18_2clk ( + rd_en, wr_en, full, empty, wr_clk, rst, rd_clk, wr_data_count, rd_data_count, dout, din +); + input rd_en; + input wr_en; + output full; + output empty; + input wr_clk; + input rst; + input rd_clk; + output [10 : 0] wr_data_count; + output [10 : 0] rd_data_count; + output [17 : 0] dout; + input [17 : 0] din; + + // synthesis translate_off + + wire \BU2/U0/grf.rf/gl0.rd/ram_valid_fwft ; + wire \BU2/N39 ; + wire \BU2/N31 ; + wire \BU2/N37 ; + wire \BU2/N27 ; + wire \BU2/N25 ; + wire \BU2/N21 ; + wire \BU2/N19 ; + wire \BU2/N17 ; + wire \BU2/N11 ; + wire \BU2/N13 ; + wire \BU2/N36 ; + wire \BU2/N381 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>4_470 ; + wire \BU2/N6 ; + wire \BU2/N7 ; + wire \BU2/N35 ; + wire \BU2/N41 ; + wire \BU2/N2 ; + wire \BU2/N40 ; + wire \BU2/N30 ; + wire \BU2/N4 ; + wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ; + wire \BU2/N38 ; + wire \BU2/N33 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006_bdd0 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006_bdd0 ; + wire \BU2/N351 ; + wire \BU2/U0/grf.rf/mem/tmp_ram_rd_en ; + wire \BU2/U0/grf.rf/ram_regout_en ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0>_rt_425 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1>_rt_424 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2>_rt_422 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3>_rt_420 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4>_rt_418 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5>_rt_416 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6>_rt_414 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7>_rt_412 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8>_rt_410 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<9>_rt_408 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count2 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count1 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count3 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count4 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count7 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count5 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count6 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count8 ; + wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count9 ; + wire \BU2/U0/grf.rf/ram_wr_en ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_fb_385 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i_or0000 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid_383 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1-In ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2-In ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0>_rt_378 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1>_rt_377 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2>_rt_375 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3>_rt_373 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4>_rt_371 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5>_rt_369 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6>_rt_367 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7>_rt_365 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8>_rt_363 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<9>_rt_361 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count2 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count1 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count3 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count4 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count7 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count5 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count6 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count8 ; + wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count9 ; + wire \BU2/U0/grf.rf/ram_rd_en ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0008 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0007 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0006 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0005 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0004 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0003 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0002 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0001 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0000 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0008 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0007 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0006 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0005 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0004 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0003 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0002 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0001 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0000 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0008 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0007 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0005 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0004 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0003 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0001 ; + wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0000 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0008 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0007 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0005 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0004 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0003 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0001 ; + wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0000 ; + wire \BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp2 ; + wire \BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp1 ; + wire \BU2/U0/grf.rf/gl0.rd/gras.rsts/comp1 ; + wire \BU2/U0/grf.rf/gl0.rd/gras.rsts/comp0 ; + wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000016 ; + wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000014 ; + wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000012 ; + wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 ; + wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ; + wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00006 ; + wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00004 ; + wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 ; + wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000016 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ; + wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ; + wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[9] ; + wire \BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_fb_i_94 ; + wire \BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i_or0000 ; + wire \BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_81 ; + wire \BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_or0000 ; + wire \BU2/U0/grf.rf/rstblk/wr_rst_comb ; + wire \BU2/U0/grf.rf/rstblk/rd_rst_comb ; + wire \BU2/U0/grf.rf/rstblk/wr_rst_asreg_72 ; + wire \BU2/U0/grf.rf/rstblk/rd_rst_asreg_71 ; + wire \BU2/U0/grf.rf/rstblk/wr_rst_asreg_d2_70 ; + wire \BU2/U0/grf.rf/rstblk/wr_rst_asreg_d1_69 ; + wire \BU2/U0/grf.rf/rstblk/rd_rst_asreg_d2_68 ; + wire \BU2/U0/grf.rf/rstblk/rd_rst_asreg_d1_67 ; + wire \BU2/N1 ; + wire NLW_VCC_P_UNCONNECTED; + wire NLW_GND_G_UNCONNECTED; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<15>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<14>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<13>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<12>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<11>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<10>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<9>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<8>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<7>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<6>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<5>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<4>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<3>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<2>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<1>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<0>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOPA<1>_UNCONNECTED ; + wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOPA<0>_UNCONNECTED ; + wire [17 : 0] din_2; + wire [17 : 0] dout_3; + wire [10 : 0] rd_data_count_4; + wire [10 : 0] wr_data_count_5; + wire [17 : 0] \BU2/U0/grf.rf/mem/dout_mem ; + wire [9 : 0] \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 ; + wire [8 : 0] \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy ; + wire [9 : 0] \BU2/U0/grf.rf/gl0.wr/wpntr/count ; + wire [8 : 0] \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy ; + wire [9 : 0] \BU2/U0/grf.rf/gl0.rd/rpntr/count ; + wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc ; + wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc ; + wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 ; + wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg ; + wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 ; + wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg ; + wire [4 : 0] \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 ; + wire [3 : 0] \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet ; + wire [4 : 0] \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 ; + wire [3 : 0] \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet ; + wire [4 : 0] \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 ; + wire [3 : 0] \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet ; + wire [4 : 0] \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 ; + wire [3 : 0] \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet ; + wire [9 : 0] \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut ; + wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin ; + wire [9 : 0] \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 ; + wire [8 : 0] \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy ; + wire [9 : 0] \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut ; + wire [9 : 0] \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 ; + wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin ; + wire [8 : 0] \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy ; + wire [1 : 1] \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy ; + wire [0 : 0] \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/diff_wr_rd_tmp ; + wire [9 : 1] \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 ; + wire [0 : 0] \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/diff_wr_rd_tmp ; + wire [10 : 0] \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 ; + wire [1 : 0] \BU2/U0/grf.rf/rstblk/wr_rst_reg ; + wire [2 : 0] \BU2/U0/grf.rf/rstblk/rd_rst_reg ; + wire [0 : 0] \BU2/data_count ; + assign + wr_data_count[10] = wr_data_count_5[10], + wr_data_count[9] = wr_data_count_5[9], + wr_data_count[8] = wr_data_count_5[8], + wr_data_count[7] = wr_data_count_5[7], + wr_data_count[6] = wr_data_count_5[6], + wr_data_count[5] = wr_data_count_5[5], + wr_data_count[4] = wr_data_count_5[4], + wr_data_count[3] = wr_data_count_5[3], + wr_data_count[2] = wr_data_count_5[2], + wr_data_count[1] = wr_data_count_5[1], + wr_data_count[0] = wr_data_count_5[0], + rd_data_count[10] = rd_data_count_4[10], + rd_data_count[9] = rd_data_count_4[9], + rd_data_count[8] = rd_data_count_4[8], + rd_data_count[7] = rd_data_count_4[7], + rd_data_count[6] = rd_data_count_4[6], + rd_data_count[5] = rd_data_count_4[5], + rd_data_count[4] = rd_data_count_4[4], + rd_data_count[3] = rd_data_count_4[3], + rd_data_count[2] = rd_data_count_4[2], + rd_data_count[1] = rd_data_count_4[1], + rd_data_count[0] = rd_data_count_4[0], + dout[17] = dout_3[17], + dout[16] = dout_3[16], + dout[15] = dout_3[15], + dout[14] = dout_3[14], + dout[13] = dout_3[13], + dout[12] = dout_3[12], + dout[11] = dout_3[11], + dout[10] = dout_3[10], + dout[9] = dout_3[9], + dout[8] = dout_3[8], + dout[7] = dout_3[7], + dout[6] = dout_3[6], + dout[5] = dout_3[5], + dout[4] = dout_3[4], + dout[3] = dout_3[3], + dout[2] = dout_3[2], + dout[1] = dout_3[1], + dout[0] = dout_3[0], + din_2[17] = din[17], + din_2[16] = din[16], + din_2[15] = din[15], + din_2[14] = din[14], + din_2[13] = din[13], + din_2[12] = din[12], + din_2[11] = din[11], + din_2[10] = din[10], + din_2[9] = din[9], + din_2[8] = din[8], + din_2[7] = din[7], + din_2[6] = din[6], + din_2[5] = din[5], + din_2[4] = din[4], + din_2[3] = din[3], + din_2[2] = din[2], + din_2[1] = din[1], + din_2[0] = din[0]; + VCC VCC_0 ( + .P(NLW_VCC_P_UNCONNECTED) + ); + GND GND_1 ( + .G(NLW_GND_G_UNCONNECTED) + ); + LUT4_D #( + .INIT ( 16'h0440 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>31 ( + .I0(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid_383 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ), + .I3(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ), + .LO(\BU2/N40 ), + .O(\BU2/N33 ) + ); + LUT4_L #( + .INIT ( 16'h8000 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<8>_SW1_SW0 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ), + .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ), + .LO(\BU2/N31 ) + ); + LUT3_D #( + .INIT ( 8'h80 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<9>_SW0_SW0 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 ), + .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000012 ), + .LO(\BU2/N39 ), + .O(\BU2/N27 ) + ); + LUT4_L #( + .INIT ( 16'h8000 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>21_SW1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ), + .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ), + .LO(\BU2/N19 ) + ); + LUT3_L #( + .INIT ( 8'h80 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>21_SW0 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ), + .LO(\BU2/N17 ) + ); + LUT4_D #( + .INIT ( 16'h2000 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<4>111_SW0 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid_383 ), + .I1(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .I2(\BU2/U0/grf.rf/gl0.rd/ram_valid_fwft ), + .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]), + .LO(\BU2/N381 ), + .O(\BU2/N11 ) + ); + LUT3_D #( + .INIT ( 8'h80 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>41_SW0 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ), + .LO(\BU2/N37 ), + .O(\BU2/N13 ) + ); + LUT3_D #( + .INIT ( 8'h7F )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<4>111 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ), + .LO(\BU2/N36 ), + .O(\BU2/N38 ) + ); + LUT2_D #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/RAM_VALID_FWFT11 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ), + .LO(\BU2/N351 ), + .O(\BU2/U0/grf.rf/gl0.rd/ram_valid_fwft ) + ); + RAMB16_S18_S18 #( + .INIT_3E ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_3F ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INITP_00 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INITP_01 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INITP_02 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INITP_03 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INITP_04 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INITP_05 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .SRVAL_A ( 18'h00000 ), + .SRVAL_B ( 18'h00000 ), + .INIT_00 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_01 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_02 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_03 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_04 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_05 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_06 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_07 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_08 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_09 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_0A ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_0B ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_0C ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_0D ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_0E ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_0F ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_10 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_11 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_12 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_13 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_14 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_15 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_16 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_17 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_18 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_19 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_1A ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_1B ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_1C ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_1D ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_1E ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_1F ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_20 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_21 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_22 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_23 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_24 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_25 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_26 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_27 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_28 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_29 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_2A ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_2B ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_2C ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_2D ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_2E ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_2F ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_30 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_31 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_32 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_33 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_34 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_35 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_36 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_37 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_38 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_39 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_3A ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_3B ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_3C ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .INIT_3D ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .WRITE_MODE_B ( "WRITE_FIRST" ), + .INITP_06 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ), + .SIM_COLLISION_CHECK ( "NONE" ), + .INIT_A ( 18'h00000 ), + .INIT_B ( 18'h00000 ), + .WRITE_MODE_A ( "WRITE_FIRST" ), + .INITP_07 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 )) + \BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram ( + .CLKA(wr_clk), + .CLKB(rd_clk), + .ENA(\BU2/N1 ), + .ENB(\BU2/U0/grf.rf/mem/tmp_ram_rd_en ), + .SSRA(\BU2/data_count [0]), + .SSRB(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .WEA(\BU2/U0/grf.rf/ram_wr_en ), + .WEB(\BU2/data_count [0]), + .ADDRA({\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [9], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7], +\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4], +\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1], +\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [0]}), + .ADDRB({\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7], +\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4], +\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1], +\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [0]}), + .DIA({din_2[16], din_2[15], din_2[14], din_2[13], din_2[12], din_2[11], din_2[10], din_2[9], din_2[7], din_2[6], din_2[5], din_2[4], din_2[3], +din_2[2], din_2[1], din_2[0]}), + .DIB({\BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], +\BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], +\BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0]}), + .DIPA({din_2[17], din_2[8]}), + .DIPB({\BU2/data_count [0], \BU2/data_count [0]}), + .DOA({\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<15>_UNCONNECTED +, \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<14>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<13>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<12>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<11>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<10>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<9>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<8>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<7>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<6>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<5>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<4>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<3>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<2>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<1>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<0>_UNCONNECTED }), + .DOPA({ +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOPA<1>_UNCONNECTED , +\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOPA<0>_UNCONNECTED }), + .DOB({\BU2/U0/grf.rf/mem/dout_mem [16], \BU2/U0/grf.rf/mem/dout_mem [15], \BU2/U0/grf.rf/mem/dout_mem [14], \BU2/U0/grf.rf/mem/dout_mem [13], +\BU2/U0/grf.rf/mem/dout_mem [12], \BU2/U0/grf.rf/mem/dout_mem [11], \BU2/U0/grf.rf/mem/dout_mem [10], \BU2/U0/grf.rf/mem/dout_mem [9], +\BU2/U0/grf.rf/mem/dout_mem [7], \BU2/U0/grf.rf/mem/dout_mem [6], \BU2/U0/grf.rf/mem/dout_mem [5], \BU2/U0/grf.rf/mem/dout_mem [4], +\BU2/U0/grf.rf/mem/dout_mem [3], \BU2/U0/grf.rf/mem/dout_mem [2], \BU2/U0/grf.rf/mem/dout_mem [1], \BU2/U0/grf.rf/mem/dout_mem [0]}), + .DOPB({\BU2/U0/grf.rf/mem/dout_mem [17], \BU2/U0/grf.rf/mem/dout_mem [8]}) + ); + INV \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_xor<1>11_INV_0 ( + .I(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [1]) + ); + LUT4 #( + .INIT ( 16'h8000 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9> ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000014 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000016 ), + .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ), + .I3(\BU2/N39 ), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[9] ) + ); + LUT4 #( + .INIT ( 16'h7FFF )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<8>_SW1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ), + .I3(\BU2/N31 ), + .O(\BU2/N7 ) + ); + LUT4 #( + .INIT ( 16'hA2AA )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>30_SW0 ( + .I0(\BU2/N33 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 ), + .I2(\BU2/N4 ), + .I3(\BU2/N37 ), + .O(\BU2/N21 ) + ); + LUT4 #( + .INIT ( 16'h6CCC )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<9> ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000014 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000016 ), + .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ), + .I3(\BU2/N27 ), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [9]) + ); + LUT4 #( + .INIT ( 16'h6CCC )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<8>1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000012 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000014 ), + .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ), + .I3(\BU2/N25 ), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [8]) + ); + LUT2 #( + .INIT ( 4'h8 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>31_SW1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 ), + .O(\BU2/N25 ) + ); + LUT4 #( + .INIT ( 16'hEAC0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>38 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000016 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>4_470 ), + .I2(\BU2/N35 ), + .I3(\BU2/N21 ), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [9]) + ); + LUT4 #( + .INIT ( 16'h8000 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<8>_SW0 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ), + .I2(\BU2/N11 ), + .I3(\BU2/N19 ), + .O(\BU2/N6 ) + ); + LUT4 #( + .INIT ( 16'h8000 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>41 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ), + .I2(\BU2/N11 ), + .I3(\BU2/N17 ), + .O(\BU2/N35 ) + ); + LUT4 #( + .INIT ( 16'h7FFF )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<5>11 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ), + .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ), + .O(\BU2/N4 ) + ); + LUT4 #( + .INIT ( 16'h8000 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<10>1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000016 ), + .I2(\BU2/N13 ), + .I3(\BU2/N30 ), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [10]) + ); + LUT4 #( + .INIT ( 16'hFF7F )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<7>_SW0 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ), + .I3(\BU2/N36 ), + .O(\BU2/N41 ) + ); + LUT4 #( + .INIT ( 16'h8000 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>21 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ), + .I3(\BU2/N381 ), + .O(\BU2/N30 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<9>_rt ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [9]), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<9>_rt_408 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<9>_rt ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [9]), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<9>_rt_361 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0>_rt ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [0]), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0>_rt_425 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1>_rt ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [1]), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1>_rt_424 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2>_rt ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [2]), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2>_rt_422 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3>_rt ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [3]), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3>_rt_420 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4>_rt ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [4]), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4>_rt_418 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5>_rt ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [5]), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5>_rt_416 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6>_rt ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [6]), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6>_rt_414 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7>_rt ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [7]), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7>_rt_412 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8>_rt ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [8]), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8>_rt_410 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0>_rt ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [0]), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0>_rt_378 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1>_rt ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [1]), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1>_rt_377 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2>_rt ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [2]), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2>_rt_375 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3>_rt ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [3]), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3>_rt_373 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4>_rt ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [4]), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4>_rt_371 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5>_rt ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [5]), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5>_rt_369 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6>_rt ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [6]), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6>_rt_367 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7>_rt ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [7]), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7>_rt_365 ) + ); + LUT1 #( + .INIT ( 2'h2 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8>_rt ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [8]), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8>_rt_363 ) + ); + LUT4 #( + .INIT ( 16'h8000 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>41 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 ), + .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00004 ), + .I3(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00006 ), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ) + ); + LUT3 #( + .INIT ( 8'h08 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>4 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000016 ), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>4_470 ) + ); + LUT4 #( + .INIT ( 16'hD580 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<8> ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 ), + .I1(\BU2/N33 ), + .I2(\BU2/N7 ), + .I3(\BU2/N6 ), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [8]) + ); + LUT4 #( + .INIT ( 16'hD580 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<7> ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ), + .I1(\BU2/N33 ), + .I2(\BU2/N41 ), + .I3(\BU2/N35 ), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [7]) + ); + LUT4 #( + .INIT ( 16'hEA40 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<6> ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ), + .I2(\BU2/N30 ), + .I3(\BU2/N2 ), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [6]) + ); + LUT4 #( + .INIT ( 16'hAA2A )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<6>_SW0 ( + .I0(\BU2/N40 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ), + .I3(\BU2/N38 ), + .O(\BU2/N2 ) + ); + LUT4 #( + .INIT ( 16'hD580 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<5>2 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ), + .I1(\BU2/N4 ), + .I2(\BU2/N33 ), + .I3(\BU2/N30 ), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [5]) + ); + LUT4 #( + .INIT ( 16'h6CCC )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<7>1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000012 ), + .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 ), + .I3(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [7]) + ); + LUT3 #( + .INIT ( 8'h6C )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<6>1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 ), + .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [6]) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<5>1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [5]) + ); + LUT3 #( + .INIT ( 8'h82 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<4>1 ( + .I0(\BU2/N33 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ), + .I2(\BU2/N38 ), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [4]) + ); + LUT4 #( + .INIT ( 16'h6CCC )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_xor<4>11 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00006 ), + .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00004 ), + .I3(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [4]) + ); + LUT4 #( + .INIT ( 16'h60C0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<3>1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ), + .I2(\BU2/N33 ), + .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [3]) + ); + LUT3 #( + .INIT ( 8'h6C )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_xor<3>11 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00004 ), + .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [3]) + ); + LUT3 #( + .INIT ( 8'h28 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<2>1 ( + .I0(\BU2/N33 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [2]) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_xor<2>11 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [2]) + ); + LUT2 #( + .INIT ( 4'h4 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<1>1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]), + .I1(\BU2/N33 ), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [1]) + ); + LUT4 #( + .INIT ( 16'h9669 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor000611 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [3]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [4]), + .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [5]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006_bdd0 ) + ); + LUT4 #( + .INIT ( 16'h9669 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00081 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [0]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [1]), + .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [2]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006_bdd0 ), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0008 ) + ); + LUT4 #( + .INIT ( 16'h9669 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor000611 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [3]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [4]), + .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [5]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006_bdd0 ) + ); + LUT4 #( + .INIT ( 16'h9669 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00081 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [0]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [1]), + .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [2]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006_bdd0 ), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0008 ) + ); + LUT3 #( + .INIT ( 8'h69 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00071 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [1]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [2]), + .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006_bdd0 ), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0007 ) + ); + LUT3 #( + .INIT ( 8'h69 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00071 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [1]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [2]), + .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006_bdd0 ), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0007 ) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00062 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [2]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006_bdd0 ), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006 ) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00062 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [2]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006_bdd0 ), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006 ) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1_0_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [1]), + .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [0]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [0]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [0]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1_0_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [1]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [1]), + .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count [0]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [0]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [0]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1_0_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [1]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [1]), + .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [0]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [0]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [0]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1_0_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [1]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [1]), + .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count [0]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [0]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [0]) + ); + LUT4 #( + .INIT ( 16'hBAAA )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i_or00001 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp1 ), + .I1(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_fb_i_94 ), + .I2(wr_en), + .I3(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp2 ), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i_or0000 ) + ); + LUT3 #( + .INIT ( 8'hF8 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_or00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gras.rsts/comp1 ), + .I1(\BU2/U0/grf.rf/ram_rd_en ), + .I2(\BU2/U0/grf.rf/gl0.rd/gras.rsts/comp0 ), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_or0000 ) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1_1_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [3]), + .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [2]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [1]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1_1_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [3]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [3]), + .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count [2]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [2]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [1]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1_1_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [3]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [3]), + .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [2]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [2]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [1]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1_1_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [3]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [3]), + .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count [2]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [2]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [1]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1_2_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [5]), + .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [4]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [2]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1_2_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [5]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [5]), + .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count [4]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [4]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [2]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1_2_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [5]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [5]), + .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [4]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [4]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [2]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1_2_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [5]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [5]), + .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count [4]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [4]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [2]) + ); + LUT4 #( + .INIT ( 16'h3010 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<0>1 ( + .I0(\BU2/N351 ), + .I1(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid_383 ), + .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/diff_wr_rd_tmp [0]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [0]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1_3_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [7]), + .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [6]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [3]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1_3_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [7]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [7]), + .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count [6]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [6]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [3]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1_3_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [7]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [7]), + .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [6]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [6]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [3]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1_3_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [7]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [7]), + .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count [6]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [6]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [3]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1_4_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [9]), + .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [8]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [4]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1_4_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [9]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [9]), + .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count [8]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [8]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [4]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1_4_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [9]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [9]), + .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [8]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [8]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [4]) + ); + LUT4 #( + .INIT ( 16'h9009 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1_4_and00001 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [9]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [9]), + .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count [8]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [8]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [4]) + ); + LUT2 #( + .INIT ( 4'hE )) + \BU2/U0/grf.rf/mem/tmp_ram_rd_en1 ( + .I0(\BU2/U0/grf.rf/ram_rd_en ), + .I1(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .O(\BU2/U0/grf.rf/mem/tmp_ram_rd_en ) + ); + LUT4 #( + .INIT ( 16'h5455 )) + \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/RAM_RD_EN_FWFT1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_81 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ), + .I2(rd_en), + .I3(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ), + .O(\BU2/U0/grf.rf/ram_rd_en ) + ); + LUT4 #( + .INIT ( 16'h6996 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00051 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [4]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [3]), + .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [5]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0005 ) + ); + LUT4 #( + .INIT ( 16'h6996 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00051 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [4]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [3]), + .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [5]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0005 ) + ); + LUT3 #( + .INIT ( 8'h96 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00041 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [5]), + .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [4]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0004 ) + ); + LUT3 #( + .INIT ( 8'h96 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00041 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [5]), + .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [4]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0004 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00032 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [5]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0003 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00032 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [5]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0003 ) + ); + LUT3 #( + .INIT ( 8'h62 )) + \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/RAM_REGOUT_EN1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ), + .I2(rd_en), + .O(\BU2/U0/grf.rf/ram_regout_en ) + ); + LUT2 #( + .INIT ( 4'h4 )) + \BU2/U0/grf.rf/gl0.wr/ram_wr_en_i1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_fb_i_94 ), + .I1(wr_en), + .O(\BU2/U0/grf.rf/ram_wr_en ) + ); + LUT4 #( + .INIT ( 16'h69A1 )) + \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2-In11 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_81 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ), + .I3(rd_en), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2-In ) + ); + LUT4 #( + .INIT ( 16'hCA8A )) + \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i_or00001 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_fb_385 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ), + .I2(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ), + .I3(rd_en), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i_or0000 ) + ); + LUT4 #( + .INIT ( 16'h6996 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00021 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [7]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [6]), + .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [9]), + .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [8]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ) + ); + LUT4 #( + .INIT ( 16'h6996 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00021 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [7]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [6]), + .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [9]), + .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [8]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ) + ); + LUT3 #( + .INIT ( 8'h6E )) + \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1-In11 ( + .I0(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ), + .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ), + .I2(rd_en), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1-In ) + ); + LUT3 #( + .INIT ( 8'h96 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00011 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [9]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [8]), + .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [7]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0001 ) + ); + LUT3 #( + .INIT ( 8'h96 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00011 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [9]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [8]), + .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [7]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0001 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0000_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0000 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0001_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0001 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0002_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0002 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0003_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0003 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0004_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0004 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0005_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0005 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0006_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0006 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0007_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0007 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0008_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [0]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0008 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0000_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [9]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0000 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0001_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0001 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0002_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0002 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0003_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0003 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0004_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0004 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0005_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0005 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0006_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0006 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0007_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0007 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0008_Result1 ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [0]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0008 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00001 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [8]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [9]), + .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0000 ) + ); + LUT2 #( + .INIT ( 4'h6 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00001 ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [8]), + .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [9]), + .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0000 ) + ); + LUT2 #( + .INIT ( 4'h4 )) + \BU2/U0/grf.rf/rstblk/rd_rst_comb1 ( + .I0(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_d2_68 ), + .I1(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_71 ), + .O(\BU2/U0/grf.rf/rstblk/rd_rst_comb ) + ); + LUT2 #( + .INIT ( 4'h4 )) + \BU2/U0/grf.rf/rstblk/wr_rst_comb1 ( + .I0(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_d2_70 ), + .I1(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_72 ), + .O(\BU2/U0/grf.rf/rstblk/wr_rst_comb ) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_0 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [0]), + .Q(dout_3[0]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_1 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [1]), + .Q(dout_3[1]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_2 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [2]), + .Q(dout_3[2]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_3 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [3]), + .Q(dout_3[3]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_4 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [4]), + .Q(dout_3[4]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_5 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [5]), + .Q(dout_3[5]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_6 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [6]), + .Q(dout_3[6]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_7 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [7]), + .Q(dout_3[7]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_8 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [8]), + .Q(dout_3[8]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_9 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [9]), + .Q(dout_3[9]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_10 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [10]), + .Q(dout_3[10]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_11 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [11]), + .Q(dout_3[11]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_12 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [12]), + .Q(dout_3[12]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_13 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [13]), + .Q(dout_3[13]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_14 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [14]), + .Q(dout_3[14]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_15 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [15]), + .Q(dout_3[15]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_16 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [16]), + .Q(dout_3[16]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/mem/dout_i_17 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_regout_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]), + .D(\BU2/U0/grf.rf/mem/dout_mem [17]), + .Q(dout_3[17]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_0 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [0]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [0]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_1 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [1]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_2 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [2]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_3 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [3]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_4 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [4]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_5 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [5]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_6 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [6]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_7 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [7]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_8 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [8]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_9 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [9]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [9]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_9 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [9]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [9]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_8 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [8]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [8]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_6 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [6]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [6]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_5 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [5]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [5]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_7 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [7]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [7]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_4 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [4]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [4]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_3 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [3]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [3]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_1 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [1]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [1]) + ); + FDPE #( + .INIT ( 1'b1 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_0 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [0]), + .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [0]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_2 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [2]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [2]) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0> ( + .CI(\BU2/N1 ), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0>_rt_425 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [0]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<0> ( + .CI(\BU2/N1 ), + .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0>_rt_425 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [0]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1>_rt_424 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [1]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<1> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [0]), + .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1>_rt_424 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count1 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [1]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2>_rt_422 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [2]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<2> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [1]), + .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2>_rt_422 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count2 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [2]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3>_rt_420 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [3]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<3> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [2]), + .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3>_rt_420 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count3 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [3]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4>_rt_418 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [4]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<4> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [3]), + .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4>_rt_418 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count4 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [4]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5>_rt_416 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [5]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<5> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [4]), + .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5>_rt_416 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count5 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [5]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6>_rt_414 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [6]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<6> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [5]), + .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6>_rt_414 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count6 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [6]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7>_rt_412 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [7]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<7> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [6]), + .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7>_rt_412 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count7 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [7]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8>_rt_410 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [8]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<8> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [7]), + .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8>_rt_410 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count8 ) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<9> ( + .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [8]), + .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<9>_rt_408 ), + .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count9 ) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_2 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count2 ), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [2]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_0 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count ), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [0]) + ); + FDPE #( + .INIT ( 1'b1 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_1 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count1 ), + .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [1]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_3 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count3 ), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [3]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_4 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count4 ), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [4]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_7 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count7 ), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [7]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_5 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count5 ), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [5]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_6 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count6 ), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [6]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_8 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count8 ), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [8]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/wpntr/count_9 ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/ram_wr_en ), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count9 ), + .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [9]) + ); + FDP #( + .INIT ( 1'b1 )) + \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_fb ( + .C(rd_clk), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i_or0000 ), + .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .Q(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_fb_385 ) + ); + FDP #( + .INIT ( 1'b1 )) + \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i ( + .C(rd_clk), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i_or0000 ), + .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .Q(empty) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1-In ), + .Q(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid_383 ) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1-In ), + .Q(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2-In ), + .Q(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_0 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [0]), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [0]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_1 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [1]), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_2 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [2]), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_3 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [3]), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_4 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [4]), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_5 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [5]), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_6 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [6]), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_7 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [7]), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_8 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [8]), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_9 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [9]), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9]) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0> ( + .CI(\BU2/N1 ), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0>_rt_378 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [0]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<0> ( + .CI(\BU2/N1 ), + .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0>_rt_378 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [0]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1>_rt_377 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [1]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<1> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [0]), + .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1>_rt_377 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count1 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [1]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2>_rt_375 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [2]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<2> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [1]), + .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2>_rt_375 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count2 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [2]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3>_rt_373 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [3]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<3> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [2]), + .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3>_rt_373 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count3 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [3]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4>_rt_371 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [4]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<4> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [3]), + .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4>_rt_371 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count4 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [4]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5>_rt_369 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [5]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<5> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [4]), + .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5>_rt_369 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count5 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [5]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6>_rt_367 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [6]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<6> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [5]), + .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6>_rt_367 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count6 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [6]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7>_rt_365 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [7]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<7> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [6]), + .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7>_rt_365 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count7 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [7]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8>_rt_363 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [8]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<8> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [7]), + .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8>_rt_363 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count8 ) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<9> ( + .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [8]), + .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<9>_rt_361 ), + .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count9 ) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_2 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count2 ), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [2]) + ); + FDPE #( + .INIT ( 1'b1 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_0 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count ), + .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [0]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_1 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count1 ), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [1]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_3 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count3 ), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [3]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_4 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count4 ), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [4]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_7 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count7 ), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [7]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_5 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count5 ), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [5]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_6 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count6 ), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [6]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_8 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count8 ), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [8]) + ); + FDCE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/rpntr/count_9 ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/ram_rd_en ), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count9 ), + .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [9]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_0 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0008 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [0]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_1 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0007 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [1]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_2 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0006 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [2]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_3 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0005 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [3]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_4 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0004 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [4]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_5 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0003 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [5]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_6 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0002 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [6]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_7 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0001 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [7]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_8 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0000 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [8]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_9 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [9]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [9]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_0 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0008 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [0]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_1 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0007 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [1]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_2 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0006 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [2]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_3 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0005 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [3]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_4 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0004 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [4]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_5 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0003 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [5]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_6 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0002 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [6]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_7 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0001 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [7]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_8 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0000 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [8]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_9 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [9]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_0 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [0]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [0]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_1 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [1]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [1]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_2 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [2]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [2]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_3 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [3]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [3]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_4 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [4]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [4]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_5 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [5]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [5]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_6 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [6]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [6]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_7 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [7]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [7]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_8 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [8]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [8]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_9 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [9]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [9]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_0 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [0]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [0]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_1 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [1]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [1]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_2 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [2]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [2]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_3 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [3]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [3]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_4 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [4]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [4]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_5 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [5]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [5]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_6 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [6]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [6]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_7 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [7]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [7]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_8 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [8]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [8]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_9 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [9]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [9]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_0 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [0]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [0]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_1 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [1]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [1]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_2 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [2]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [2]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_3 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [3]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [3]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_4 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [4]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [4]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_5 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [5]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [5]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_6 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [6]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [6]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_7 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [7]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [7]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_8 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [8]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [8]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_9 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [9]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [9]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_0 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [0]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [0]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_1 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [1]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [1]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_2 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [2]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [2]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_3 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [3]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [3]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_4 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [4]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [4]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_5 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [5]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [5]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_6 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [6]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [6]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_7 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [7]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [7]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_8 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [8]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [8]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_9 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [9]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [9]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_0 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0008 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [0]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_1 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0007 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [1]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_2 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [2]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_3 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0005 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [3]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_4 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0004 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [4]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_5 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0003 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [5]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_6 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [6]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_7 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0001 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [7]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_8 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0000 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [8]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_9 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]), + .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [9]), + .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [9]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_0 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0008 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [0]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_1 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0007 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [1]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_2 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [2]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_3 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0005 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [3]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_4 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0004 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [4]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_5 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0003 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [5]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_6 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [6]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_7 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0001 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [7]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_8 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0000 ), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [8]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_9 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]), + .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [9]), + .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [9]) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/gmux.gm[0].gm1.m1 ( + .CI(\BU2/N1 ), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [0]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [0]) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/gmux.gm[1].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [0]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [1]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [1]) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/gmux.gm[2].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [1]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [2]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [2]) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/gmux.gm[3].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [2]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [3]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [3]) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/gmux.gm[4].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [3]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [4]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp2 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/gmux.gm[0].gm1.m1 ( + .CI(\BU2/N1 ), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [0]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [0]) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/gmux.gm[1].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [0]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [1]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [1]) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/gmux.gm[2].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [1]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [2]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [2]) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/gmux.gm[3].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [2]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [3]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [3]) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/gmux.gm[4].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [3]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [4]), + .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp1 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/gmux.gm[0].gm1.m1 ( + .CI(\BU2/N1 ), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [0]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [0]) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/gmux.gm[1].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [0]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [1]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [1]) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/gmux.gm[2].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [1]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [2]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [2]) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/gmux.gm[3].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [2]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [3]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [3]) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/gmux.gm[4].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [3]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [4]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/comp1 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/gmux.gm[0].gm1.m1 ( + .CI(\BU2/N1 ), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [0]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [0]) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/gmux.gm[1].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [0]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [1]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [1]) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/gmux.gm[2].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [1]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [2]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [2]) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/gmux.gm[3].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [2]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [3]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [3]) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/gmux.gm[4].gms.ms ( + .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [3]), + .DI(\BU2/data_count [0]), + .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [4]), + .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/comp0 ) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<9> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [8]), + .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [9]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000016 ) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<9> ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [9]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [9]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [9]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<8> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [7]), + .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [8]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000014 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<8> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [7]), + .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8]), + .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [8]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [8]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<8> ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [8]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [8]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<7> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [6]), + .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [7]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000012 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<7> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [6]), + .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7]), + .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [7]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [7]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<7> ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [7]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [7]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<6> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [5]), + .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [6]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<6> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [5]), + .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6]), + .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [6]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [6]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<6> ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [6]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [6]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<5> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [4]), + .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [5]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<5> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [4]), + .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5]), + .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [5]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [5]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<5> ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [5]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [5]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<4> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [3]), + .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [4]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00006 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<4> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [3]), + .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4]), + .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [4]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [4]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<4> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [4]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [4]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<3> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [2]), + .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [3]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00004 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<3> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [2]), + .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3]), + .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [3]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [3]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<3> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [3]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [3]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<2> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [1]), + .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [2]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<2> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [1]), + .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2]), + .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [2]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [2]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<2> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [2]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [2]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<1> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [0]), + .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [1]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<1> ( + .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [0]), + .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1]), + .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [1]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [1]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<1> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [1]), + .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [1]) + ); + XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<0> ( + .CI(\BU2/N1 ), + .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [0]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/diff_wr_rd_tmp [0]) + ); + MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<0> ( + .CI(\BU2/N1 ), + .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [0]), + .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [0]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [0]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<0> ( + .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [0]), + .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [0]), + .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [0]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<9> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [8]), + .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [9]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000016 ) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<9> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [9]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [9]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<8> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [7]), + .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [8]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<8> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [7]), + .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [8]), + .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [8]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [8]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<8> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [8]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [8]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<7> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [6]), + .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [7]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<7> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [6]), + .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [7]), + .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [7]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [7]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<7> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [7]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [7]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<6> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [5]), + .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [6]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<6> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [5]), + .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [6]), + .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [6]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [6]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<6> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [6]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [6]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<5> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [4]), + .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [5]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<5> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [4]), + .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [5]), + .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [5]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [5]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<5> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [5]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [5]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<4> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [3]), + .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [4]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<4> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [3]), + .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [4]), + .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [4]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [4]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<4> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [4]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [4]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<3> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [2]), + .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [3]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<3> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [2]), + .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [3]), + .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [3]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [3]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<3> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [3]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [3]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<2> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [1]), + .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [2]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<2> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [1]), + .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [2]), + .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [2]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [2]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<2> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [2]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [2]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<1> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [0]), + .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [1]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<1> ( + .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [0]), + .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [1]), + .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [1]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [1]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<1> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [1]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [1]) + ); + XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<0> ( + .CI(\BU2/N1 ), + .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [0]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/diff_wr_rd_tmp [0]) + ); + MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<0> ( + .CI(\BU2/N1 ), + .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [0]), + .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [0]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [0]) + ); + LUT2 #( + .INIT ( 4'h9 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<0> ( + .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [0]), + .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [0]), + .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [0]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_10 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[9] ), + .Q(wr_data_count_5[10]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_9 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [9]), + .Q(wr_data_count_5[9]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_8 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [8]), + .Q(wr_data_count_5[8]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_7 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [7]), + .Q(wr_data_count_5[7]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_6 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [6]), + .Q(wr_data_count_5[6]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_5 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [5]), + .Q(wr_data_count_5[5]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_4 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [4]), + .Q(wr_data_count_5[4]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_3 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [3]), + .Q(wr_data_count_5[3]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_2 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [2]), + .Q(wr_data_count_5[2]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_1 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [1]), + .Q(wr_data_count_5[1]) + ); + FDC #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_0 ( + .C(wr_clk), + .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/diff_wr_rd_tmp [0]), + .Q(wr_data_count_5[0]) + ); + FDP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_fb_i ( + .C(wr_clk), + .D(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i_or0000 ), + .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .Q(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_fb_i_94 ) + ); + FDP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i ( + .C(wr_clk), + .D(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i_or0000 ), + .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]), + .Q(full) + ); + FDCP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_10 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [10]), + .PRE(\BU2/data_count [0]), + .Q(rd_data_count_4[10]) + ); + FDCP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_9 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [9]), + .PRE(\BU2/data_count [0]), + .Q(rd_data_count_4[9]) + ); + FDCP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_8 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [8]), + .PRE(\BU2/data_count [0]), + .Q(rd_data_count_4[8]) + ); + FDCP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_7 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [7]), + .PRE(\BU2/data_count [0]), + .Q(rd_data_count_4[7]) + ); + FDCP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_6 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [6]), + .PRE(\BU2/data_count [0]), + .Q(rd_data_count_4[6]) + ); + FDCP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_5 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [5]), + .PRE(\BU2/data_count [0]), + .Q(rd_data_count_4[5]) + ); + FDCP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_4 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [4]), + .PRE(\BU2/data_count [0]), + .Q(rd_data_count_4[4]) + ); + FDCP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_3 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [3]), + .PRE(\BU2/data_count [0]), + .Q(rd_data_count_4[3]) + ); + FDCP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_2 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [2]), + .PRE(\BU2/data_count [0]), + .Q(rd_data_count_4[2]) + ); + FDCP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_1 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [1]), + .PRE(\BU2/data_count [0]), + .Q(rd_data_count_4[1]) + ); + FDCP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_0 ( + .C(rd_clk), + .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [0]), + .PRE(\BU2/data_count [0]), + .Q(rd_data_count_4[0]) + ); + FDP #( + .INIT ( 1'b1 )) + \BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i ( + .C(rd_clk), + .D(\BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_or0000 ), + .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]), + .Q(\BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_81 ) + ); + FDP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/rstblk/wr_rst_reg_0 ( + .C(wr_clk), + .D(\BU2/data_count [0]), + .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_comb ), + .Q(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]) + ); + FDP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/rstblk/wr_rst_reg_1 ( + .C(wr_clk), + .D(\BU2/data_count [0]), + .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_comb ), + .Q(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]) + ); + FDP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/rstblk/rd_rst_reg_0 ( + .C(rd_clk), + .D(\BU2/data_count [0]), + .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_comb ), + .Q(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]) + ); + FDP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/rstblk/rd_rst_reg_1 ( + .C(rd_clk), + .D(\BU2/data_count [0]), + .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_comb ), + .Q(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]) + ); + FDP #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/rstblk/rd_rst_reg_2 ( + .C(rd_clk), + .D(\BU2/data_count [0]), + .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_comb ), + .Q(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]) + ); + FDPE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/rstblk/rd_rst_asreg ( + .C(rd_clk), + .CE(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_d1_67 ), + .D(\BU2/data_count [0]), + .PRE(rst), + .Q(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_71 ) + ); + FD #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/rstblk/wr_rst_asreg_d1 ( + .C(wr_clk), + .D(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_72 ), + .Q(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_d1_69 ) + ); + FDPE #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/rstblk/wr_rst_asreg ( + .C(wr_clk), + .CE(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_d1_69 ), + .D(\BU2/data_count [0]), + .PRE(rst), + .Q(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_72 ) + ); + FD #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/rstblk/rd_rst_asreg_d1 ( + .C(rd_clk), + .D(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_71 ), + .Q(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_d1_67 ) + ); + FD #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/rstblk/wr_rst_asreg_d2 ( + .C(wr_clk), + .D(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_d1_69 ), + .Q(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_d2_70 ) + ); + FD #( + .INIT ( 1'b0 )) + \BU2/U0/grf.rf/rstblk/rd_rst_asreg_d2 ( + .C(rd_clk), + .D(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_d1_67 ), + .Q(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_d2_68 ) + ); + VCC \BU2/XST_VCC ( + .P(\BU2/N1 ) + ); + GND \BU2/XST_GND ( + .G(\BU2/data_count [0]) + ); + +// synthesis translate_on + +endmodule + +// synthesis translate_off + +`timescale 1 ps / 1 ps + +module glbl (); + + parameter ROC_WIDTH = 100000; + parameter TOC_WIDTH = 0; + + wire GSR; + wire GTS; + wire PRLD; + + reg GSR_int; + reg GTS_int; + reg PRLD_int; + +//-------- JTAG Globals -------------- + wire JTAG_TDO_GLBL; + wire JTAG_TCK_GLBL; + wire JTAG_TDI_GLBL; + wire JTAG_TMS_GLBL; + wire JTAG_TRST_GLBL; + + reg JTAG_CAPTURE_GLBL; + reg JTAG_RESET_GLBL; + reg JTAG_SHIFT_GLBL; + reg JTAG_UPDATE_GLBL; + + reg JTAG_SEL1_GLBL = 0; + reg JTAG_SEL2_GLBL = 0 ; + reg JTAG_SEL3_GLBL = 0; + reg JTAG_SEL4_GLBL = 0; + + reg JTAG_USER_TDO1_GLBL = 1'bz; + reg JTAG_USER_TDO2_GLBL = 1'bz; + reg JTAG_USER_TDO3_GLBL = 1'bz; + reg JTAG_USER_TDO4_GLBL = 1'bz; + + assign (weak1, weak0) GSR = GSR_int; + assign (weak1, weak0) GTS = GTS_int; + assign (weak1, weak0) PRLD = PRLD_int; + + initial begin + GSR_int = 1'b1; + PRLD_int = 1'b1; + #(ROC_WIDTH) + GSR_int = 1'b0; + PRLD_int = 1'b0; + end + + initial begin + GTS_int = 1'b1; + #(TOC_WIDTH) + GTS_int = 1'b0; + end + +endmodule + +// synthesis translate_on diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.veo b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.veo new file mode 100644 index 000000000..c98e03c3b --- /dev/null +++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.veo @@ -0,0 +1,47 @@ +/******************************************************************************* +* This file is owned and controlled by Xilinx and must be used * +* solely for design, simulation, implementation and creation of * +* design files limited to Xilinx devices or technologies. Use * +* with non-Xilinx devices or technologies is expressly prohibited * +* and immediately terminates your license. * +* * +* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" * +* SOLELY FOR USE IN DEVELOPING PROGRAMS AND SOLUTIONS FOR * +* XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION * +* AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION * +* OR STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS * +* IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, * +* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE * +* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY * +* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE * +* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR * +* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF * +* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * +* FOR A PARTICULAR PURPOSE. * +* * +* Xilinx products are not intended for use in life support * +* appliances, devices, or systems. Use in such applications are * +* expressly prohibited. * +* * +* (c) Copyright 1995-2007 Xilinx, Inc. * +* All rights reserved. * +*******************************************************************************/ +// The following must be inserted into your Verilog file for this +// core to be instantiated. Change the instance name and port connections +// (in parentheses) to your own signal names. + +//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG +fifo_xlnx_1Kx18_2clk YourInstanceName ( + .din(din), // Bus [17 : 0] + .rd_clk(rd_clk), + .rd_en(rd_en), + .rst(rst), + .wr_clk(wr_clk), + .wr_en(wr_en), + .dout(dout), // Bus [17 : 0] + .empty(empty), + .full(full), + .rd_data_count(rd_data_count), // Bus [10 : 0] + .wr_data_count(wr_data_count)); // Bus [10 : 0] + +// INST_TAG_END ------ End INSTANTIATION Template --------- diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.xco b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.xco new file mode 100644 index 000000000..082aef22b --- /dev/null +++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.xco @@ -0,0 +1,82 @@ +############################################################## +# +# Xilinx Core Generator version K.39 +# Date: Fri Jun 10 23:12:12 2011 +# +############################################################## +# +# This file contains the customisation parameters for a +# Xilinx CORE Generator IP GUI. It is strongly recommended +# that you do not manually alter this file as it may cause +# unexpected and unsupported behavior. +# +############################################################## +# +# BEGIN Project Options +SET addpads = false +SET asysymbol = false +SET busformat = BusFormatAngleBracketNotRipped +SET createndf = false +SET designentry = Verilog +SET device = xc3s2000 +SET devicefamily = spartan3 +SET flowvendor = Other +SET formalverification = false +SET foundationsym = false +SET implementationfiletype = Ngc +SET package = fg456 +SET removerpms = false +SET simulationfiles = Structural +SET speedgrade = -5 +SET verilogsim = true +SET vhdlsim = false +# END Project Options +# BEGIN Select +SELECT Fifo_Generator family Xilinx,_Inc. 4.3 +# END Select +# BEGIN Parameters +CSET almost_empty_flag=false +CSET almost_full_flag=false +CSET component_name=fifo_xlnx_1Kx18_2clk +CSET data_count=false +CSET data_count_width=11 +CSET disable_timing_violations=false +CSET dout_reset_value=0 +CSET empty_threshold_assert_value=4 +CSET empty_threshold_negate_value=5 +CSET enable_ecc=false +CSET enable_int_clk=false +CSET fifo_implementation=Independent_Clocks_Block_RAM +CSET full_flags_reset_value=1 +CSET full_threshold_assert_value=1023 +CSET full_threshold_negate_value=1022 +CSET input_data_width=18 +CSET input_depth=1024 +CSET output_data_width=18 +CSET output_depth=1024 +CSET overflow_flag=false +CSET overflow_sense=Active_High +CSET performance_options=First_Word_Fall_Through +CSET programmable_empty_type=No_Programmable_Empty_Threshold +CSET programmable_full_type=No_Programmable_Full_Threshold +CSET read_clock_frequency=1 +CSET read_data_count=true +CSET read_data_count_width=11 +CSET reset_pin=true +CSET reset_type=Asynchronous_Reset +CSET underflow_flag=false +CSET underflow_sense=Active_High +CSET use_dout_reset=true +CSET use_embedded_registers=false +CSET use_extra_logic=true +CSET valid_flag=false +CSET valid_sense=Active_High +CSET write_acknowledge_flag=false +CSET write_acknowledge_sense=Active_High +CSET write_clock_frequency=1 +CSET write_data_count=true +CSET write_data_count_width=11 +# END Parameters +GENERATE +# CRC: c3fb8408 + diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.lso b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.lso new file mode 100644 index 000000000..f1a6f7899 --- /dev/null +++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.lso @@ -0,0 +1,3 @@ +blkmemdp_v6_2 +blk_mem_gen_v2_6 +fifo_generator_v4_3 diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt new file mode 100644 index 000000000..be22cb8dc --- /dev/null +++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<document OS="lin64" product="ISE" version="10.1.03"> + + <!--The data in this file is primarily intended for consumption by Xilinx tools. + The structure and the elements are likely to change over the next few releases. + This means code written to parse this file will need to be revisited each subsequent release.--> + + <application stringID="Xst" timeStamp="Fri Jun 10 16:11:52 2011"> + <section stringID="XST_HDL_SYNTHESIS_REPORT"> + <item dataType="int" stringID="XST_ADDERSSUBTRACTORS" value="4"></item> + <item dataType="int" stringID="XST_COUNTERS" value="2"> + <item dataType="int" stringID="XST_10BIT_UP_COUNTER" value="2"/> + </item> + <item dataType="int" stringID="XST_REGISTERS" value="31"> + <item dataType="int" stringID="XST_1BIT_REGISTER" value="15"/> + <item dataType="int" stringID="XST_10BIT_REGISTER" value="11"/> + <item dataType="int" stringID="XST_11BIT_REGISTER" value="2"/> + <item dataType="int" stringID="XST_2BIT_REGISTER" value="1"/> + <item dataType="int" stringID="XST_3BIT_REGISTER" value="1"/> + </item> + <item dataType="int" stringID="XST_XORS" value="76"> + <item dataType="int" stringID="XST_1BIT_XOR2" value="76"/> + </item> + </section> + <section stringID="XST_ADVANCED_HDL_SYNTHESIS_REPORT"> + <item dataType="int" stringID="XST_FSMS" value="1"/> + <item dataType="int" stringID="XST_ADDERSSUBTRACTORS" value="4"></item> + <item dataType="int" stringID="XST_COUNTERS" value="2"> + <item dataType="int" stringID="XST_10BIT_UP_COUNTER" value="2"/> + </item> + <item dataType="int" stringID="XST_REGISTERS" value="159"> + <item dataType="int" stringID="XST_FLIPFLOPS" value="159"/> + </item> + <item dataType="int" stringID="XST_XORS" value="76"> + <item dataType="int" stringID="XST_1BIT_XOR2" value="76"/> + </item> + </section> + <section stringID="XST_FINAL_REGISTER_REPORT"> + <item dataType="int" stringID="XST_REGISTERS" value="189"> + <item dataType="int" stringID="XST_FLIPFLOPS" value="189"/> + </item> + </section> + <section stringID="XST_PARTITION_REPORT"> + <section stringID="XST_PARTITION_IMPLEMENTATION_STATUS"> + <section stringID="XST_NO_PARTITIONS_WERE_FOUND_IN_THIS_DESIGN"/> + </section> + </section> + <section stringID="XST_FINAL_REPORT"> + <section stringID="XST_FINAL_RESULTS"> + <item stringID="XST_TOP_LEVEL_OUTPUT_FILE_NAME" value="/tmp/_cg/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc"/> + <item stringID="XST_OUTPUT_FORMAT" value="NGC"/> + <item stringID="XST_OPTIMIZATION_GOAL" value="SPEED"/> + <item stringID="XST_KEEP_HIERARCHY" value="no"/> + </section> + <section stringID="XST_DESIGN_STATISTICS"> + <item stringID="XST_IOS" value="153"/> + </section> + <section stringID="XST_CELL_USAGE"> + <item dataType="int" stringID="XST_BELS" value="248"> + <item dataType="int" stringID="XST_GND" value="1"/> + <item dataType="int" stringID="XST_INV" value="1"/> + <item dataType="int" stringID="XST_LUT1" value="20"/> + <item dataType="int" stringID="XST_LUT2" value="52"/> + <item dataType="int" stringID="XST_LUT2D" value="1"/> + <item dataType="int" stringID="XST_LUT3" value="14"/> + <item dataType="int" stringID="XST_LUT3D" value="3"/> + <item dataType="int" stringID="XST_LUT3L" value="1"/> + <item dataType="int" stringID="XST_LUT4" value="54"/> + <item dataType="int" stringID="XST_LUT4D" value="2"/> + <item dataType="int" stringID="XST_LUT4L" value="2"/> + <item dataType="int" stringID="XST_MUXCY" value="56"/> + <item dataType="int" stringID="XST_VCC" value="1"/> + <item dataType="int" stringID="XST_XORCY" value="40"/> + </item> + <item dataType="int" stringID="XST_FLIPFLOPSLATCHES" value="189"> + <item dataType="int" stringID="XST_FD" value="4"/> + <item dataType="int" stringID="XST_FDC" value="94"/> + <item dataType="int" stringID="XST_FDCE" value="65"/> + <item dataType="int" stringID="XST_FDP" value="10"/> + <item dataType="int" stringID="XST_FDPE" value="5"/> + </item> + <item dataType="int" stringID="XST_RAMS" value="1"> + <item dataType="int" stringID="XST_RAMB16S18S18" value="1"/> + </item> + </section> + </section> + <section stringID="XST_DEVICE_UTILIZATION_SUMMARY"> + <item stringID="XST_SELECTED_DEVICE" value="3s2000fg456-5"/> + <item AVAILABLE="20480" dataType="int" stringID="XST_NUMBER_OF_SLICES" value="139"/> + <item AVAILABLE="40960" dataType="int" stringID="XST_NUMBER_OF_SLICE_FLIP_FLOPS" value="189"/> + <item AVAILABLE="40960" dataType="int" stringID="XST_NUMBER_OF_4_INPUT_LUTS" value="150"/> + <item dataType="int" stringID="XST_NUMBER_OF_IOS" value="153"/> + <item AVAILABLE="333" dataType="int" stringID="XST_NUMBER_OF_BONDED_IOBS" value="0"/> + <item AVAILABLE="40" dataType="int" stringID="XST_NUMBER_OF_BRAMS" value="1"/> + </section> + <section stringID="XST_PARTITION_RESOURCE_SUMMARY"> + <section stringID="XST_NO_PARTITIONS_WERE_FOUND_IN_THIS_DESIGN"/> + </section> + <section stringID="XST_ERRORS_STATISTICS"> + <item dataType="int" filtered="0" stringID="XST_NUMBER_OF_ERRORS" value="0"/> + <item dataType="int" filtered="0" stringID="XST_NUMBER_OF_WARNINGS" value="136"/> + <item dataType="int" filtered="0" stringID="XST_NUMBER_OF_INFOS" value="17"/> + </section> + </application> + +</document> diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_flist.txt b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_flist.txt new file mode 100644 index 000000000..3bd308751 --- /dev/null +++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_flist.txt @@ -0,0 +1,8 @@ +# Output products list for <fifo_xlnx_1Kx18_2clk> +fifo_xlnx_1Kx18_2clk.ngc +fifo_xlnx_1Kx18_2clk.v +fifo_xlnx_1Kx18_2clk.veo +fifo_xlnx_1Kx18_2clk.xco +fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt +fifo_xlnx_1Kx18_2clk_flist.txt +fifo_xlnx_1Kx18_2clk_xmdf.tcl diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_readme.txt b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_readme.txt new file mode 100644 index 000000000..72f83d6fb --- /dev/null +++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_readme.txt @@ -0,0 +1,38 @@ +The following files were generated for 'fifo_xlnx_1Kx18_2clk' in directory +/home/matt/sourcerepo/fpga/usrp2/coregen/: + +fifo_xlnx_1Kx18_2clk.ngc: + Binary Xilinx implementation netlist file containing the information + required to implement the module in a Xilinx (R) FPGA. + +fifo_xlnx_1Kx18_2clk.v: + Unisim Verilog file containing the information required to simulate + the module. + +fifo_xlnx_1Kx18_2clk.veo: + VEO template file containing code that can be used as a model for + instantiating a CORE Generator module in a Verilog design. + +fifo_xlnx_1Kx18_2clk.xco: + CORE Generator input file containing the parameters used to + regenerate a core. + +fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt: + Please see the core data sheet. + +fifo_xlnx_1Kx18_2clk_flist.txt: + Text file listing all of the output files produced when a customized + core was generated in the CORE Generator. + +fifo_xlnx_1Kx18_2clk_readme.txt: + Text file indicating the files generated and how they are used. + +fifo_xlnx_1Kx18_2clk_xmdf.tcl: + ISE Project Navigator interface file. ISE uses this file to determine + how the files output by CORE Generator for the core can be integrated + into your ISE project. + + +Please see the Xilinx CORE Generator online help for further details on +generated files and how to use them. + diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_xmdf.tcl b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_xmdf.tcl new file mode 100644 index 000000000..244d03d85 --- /dev/null +++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_xmdf.tcl @@ -0,0 +1,68 @@ +# The package naming convention is <core_name>_xmdf +package provide fifo_xlnx_1Kx18_2clk_xmdf 1.0 + +# This includes some utilities that support common XMDF operations +package require utilities_xmdf + +# Define a namespace for this package. The name of the name space +# is <core_name>_xmdf +namespace eval ::fifo_xlnx_1Kx18_2clk_xmdf { +# Use this to define any statics +} + +# Function called by client to rebuild the params and port arrays +# Optional when the use context does not require the param or ports +# arrays to be available. +proc ::fifo_xlnx_1Kx18_2clk_xmdf::xmdfInit { instance } { +# Variable containg name of library into which module is compiled +# Recommendation: <module_name> +# Required +utilities_xmdf::xmdfSetData $instance Module Attributes Name fifo_xlnx_1Kx18_2clk +} +# ::fifo_xlnx_1Kx18_2clk_xmdf::xmdfInit + +# Function called by client to fill in all the xmdf* data variables +# based on the current settings of the parameters +proc ::fifo_xlnx_1Kx18_2clk_xmdf::xmdfApplyParams { instance } { + +set fcount 0 +# Array containing libraries that are assumed to exist +# Examples include unisim and xilinxcorelib +# Optional +# In this example, we assume that the unisim library will +# be magically +# available to the simulation and synthesis tool +utilities_xmdf::xmdfSetData $instance FileSet $fcount type logical_library +utilities_xmdf::xmdfSetData $instance FileSet $fcount logical_library unisim +incr fcount + +utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk.ngc +utilities_xmdf::xmdfSetData $instance FileSet $fcount type ngc +incr fcount + +utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk.v +utilities_xmdf::xmdfSetData $instance FileSet $fcount type verilog +incr fcount + +utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk.veo +utilities_xmdf::xmdfSetData $instance FileSet $fcount type verilog_template +incr fcount + +utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk.xco +utilities_xmdf::xmdfSetData $instance FileSet $fcount type coregen_ip +incr fcount + +utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt +utilities_xmdf::xmdfSetData $instance FileSet $fcount type AnyView +incr fcount + +utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk_xmdf.tcl +utilities_xmdf::xmdfSetData $instance FileSet $fcount type AnyView +incr fcount + +utilities_xmdf::xmdfSetData $instance FileSet $fcount associated_module fifo_xlnx_1Kx18_2clk +incr fcount + +} + +# ::gen_comp_name_xmdf::xmdfApplyParams diff --git a/fpga/usrp2/fifo/fifo_2clock.v b/fpga/usrp2/fifo/fifo_2clock.v index 756ad508f..c6aaf34dc 100644 --- a/fpga/usrp2/fifo/fifo_2clock.v +++ b/fpga/usrp2/fifo/fifo_2clock.v @@ -65,6 +65,11 @@ module fifo_2clock (.rst(arst), .wr_clk(wclk),.din({1'b0,datain}),.full(full),.wr_en(write),.wr_data_count(level_wclk), .rd_clk(rclk),.dout({dummy,dataout}),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) ); + else if ((WIDTH==18) & (SIZE==10)) + fifo_xlnx_1Kx18_2clk fifo_xlnx_1Kx18_2clk + (.rst(arst), + .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk), + .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) ); endgenerate assign occupied = {{(16-SIZE-1){1'b0}},level_rclk}; diff --git a/fpga/usrp2/gpmc/Makefile.srcs b/fpga/usrp2/gpmc/Makefile.srcs index bff6ae3e0..bf0c0ecfd 100644 --- a/fpga/usrp2/gpmc/Makefile.srcs +++ b/fpga/usrp2/gpmc/Makefile.srcs @@ -17,4 +17,6 @@ gpmc_to_fifo_async.v \ gpmc_to_fifo_sync.v \ gpmc_wb.v \ ram_to_fifo.v \ +new_write.v \ +new_read.v \ )) diff --git a/fpga/usrp2/gpmc/fifo_watcher.v b/fpga/usrp2/gpmc/fifo_watcher.v index b139f5143..3971e3c54 100644 --- a/fpga/usrp2/gpmc/fifo_watcher.v +++ b/fpga/usrp2/gpmc/fifo_watcher.v @@ -30,10 +30,11 @@ module fifo_watcher reg [15:0] counter; wire [4:0] pkt_count; assign debug = pkt_count; + wire space; fifo_short #(.WIDTH(16)) frame_lengths (.clk(clk), .reset(reset), .clear(clear), - .datain(counter), .src_rdy_i(write), .dst_rdy_o(), + .datain(counter), .src_rdy_i(write), .dst_rdy_o(space), .dataout(length), .src_rdy_o(have_packet_int), .dst_rdy_i(read), .occupied(pkt_count), .space()); @@ -53,7 +54,9 @@ module fifo_watcher bus_error <= 1; else if(read & ~have_packet_int) bus_error <= 1; - + else if(write & ~space) + bus_error <= 1; + reg in_packet; always @(posedge clk) if(reset | clear) diff --git a/fpga/usrp2/gpmc/gpmc_async.v b/fpga/usrp2/gpmc/gpmc_async.v index c0bec683a..9972e81b0 100644 --- a/fpga/usrp2/gpmc/gpmc_async.v +++ b/fpga/usrp2/gpmc/gpmc_async.v @@ -22,7 +22,7 @@ module gpmc_async parameter RXFIFOSIZE = 11, parameter BUSDEBUG = 1) (// GPMC signals - input arst, + input arst, input bus_clk, input EM_CLK, inout [15:0] EM_D, input [10:1] EM_A, input [1:0] EM_NBE, input EM_WAIT0, input EM_NCS4, input EM_NCS6, input EM_NWE, input EM_NOE, @@ -67,27 +67,21 @@ module gpmc_async // //////////////////////////////////////////// // TX Data Path - wire [17:0] tx18_data, tx18b_data; - wire tx18_src_rdy, tx18_dst_rdy, tx18b_src_rdy, tx18b_dst_rdy; + wire [17:0] tx18_data; + wire tx18_src_rdy, tx18_dst_rdy; wire [15:0] tx_fifo_space; wire [35:0] tx36_data, tx_data; wire tx36_src_rdy, tx36_dst_rdy, tx_src_rdy, tx_dst_rdy; - gpmc_to_fifo_async gpmc_to_fifo_async + new_write new_write (.EM_D(EM_D), .EM_NBE(EM_NBE), .EM_NCS(EM_NCS4), .EM_NWE(EM_NWE), - .fifo_clk(fifo_clk), .fifo_rst(fifo_rst), .clear(clear_tx), + .bus_clk(bus_clk), .fifo_clk(fifo_clk), .fifo_rst(fifo_rst), .clear(clear_tx), .data_o(tx18_data), .src_rdy_o(tx18_src_rdy), .dst_rdy_i(tx18_dst_rdy), - .frame_len(tx_frame_len), .fifo_space(tx_fifo_space), .fifo_ready(tx_have_space), - .bus_error(bus_error_tx) ); + .frame_len(tx_frame_len), .fifo_ready(tx_have_space), .bus_error(bus_error_tx) ); - fifo_cascade #(.WIDTH(18), .SIZE(10)) tx_fifo - (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx), - .datain(tx18_data), .src_rdy_i(tx18_src_rdy), .dst_rdy_o(tx18_dst_rdy), .space(tx_fifo_space), - .dataout(tx18b_data), .src_rdy_o(tx18b_src_rdy), .dst_rdy_i(tx18b_dst_rdy), .occupied()); - fifo19_to_fifo36 #(.LE(1)) f19_to_f36 // Little endian because ARM is LE (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx), - .f19_datain({1'b0,tx18b_data}), .f19_src_rdy_i(tx18b_src_rdy), .f19_dst_rdy_o(tx18b_dst_rdy), + .f19_datain({1'b0,tx18_data}), .f19_src_rdy_i(tx18_src_rdy), .f19_dst_rdy_o(tx18_dst_rdy), .f36_dataout(tx36_data), .f36_src_rdy_o(tx36_src_rdy), .f36_dst_rdy_i(tx36_dst_rdy)); fifo_cascade #(.WIDTH(36), .SIZE(TXFIFOSIZE)) tx_fifo36 @@ -110,31 +104,20 @@ module gpmc_async .datain(rx_data), .src_rdy_i(rx_src_rdy), .dst_rdy_o(rx_dst_rdy), .dataout(rx36_data), .src_rdy_o(rx36_src_rdy), .dst_rdy_i(rx36_dst_rdy)); + wire [31:0] pkt_count; + wire throttle = pkt_count == 16; + fifo36_to_fifo19 #(.LE(1)) f36_to_f19 // Little endian because ARM is LE (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx), .f36_datain(rx36_data), .f36_src_rdy_i(rx36_src_rdy), .f36_dst_rdy_o(rx36_dst_rdy), .f19_dataout({dummy,rx18_data}), .f19_src_rdy_o(rx18_src_rdy), .f19_dst_rdy_i(rx18_dst_rdy) ); - fifo_cascade #(.WIDTH(18), .SIZE(12)) rx_fifo - (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx), - .datain(rx18_data), .src_rdy_i(rx18_src_rdy), .dst_rdy_o(rx18_dst_rdy), .space(rx_fifo_space), - .dataout(rx18b_data), .src_rdy_o(rx18b_src_rdy), .dst_rdy_i(rx18b_dst_rdy), .occupied()); - - fifo_to_gpmc_async fifo_to_gpmc_async + new_read new_read (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx), - .data_i(rx18b_data), .src_rdy_i(rx18b_src_rdy), .dst_rdy_o(rx18b_dst_rdy), + .data_i(rx18_data), .src_rdy_i(rx18_src_rdy), .dst_rdy_o(rx18_dst_rdy), .EM_D(EM_D_fifo), .EM_NCS(EM_NCS4), .EM_NOE(EM_NOE), - .frame_len(rx_frame_len) ); - - wire [31:0] pkt_count; + .have_packet(rx_have_data), .frame_len(rx_frame_len), .bus_error(bus_error_rx) ); - fifo_watcher fifo_watcher - (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx), - .src_rdy1(rx18_src_rdy), .dst_rdy1(rx18_dst_rdy), .sof1(rx18_data[16]), .eof1(rx18_data[17]), - .src_rdy2(rx18b_src_rdy), .dst_rdy2(rx18b_dst_rdy), .sof2(rx18b_data[16]), .eof2(rx18b_data[17]), - .have_packet(rx_have_data), .length(rx_frame_len), .bus_error(bus_error_rx), - .debug(pkt_count)); - // //////////////////////////////////////////// // Control path on CS6 @@ -230,16 +213,13 @@ module gpmc_async // FIXME -- make sure packet completes before we shutoff // FIXME -- handle overrun and underrun -wire [0:17] dummy18; - -assign debug = {8'd0, - test_rate, - pkt_src_enable, pkt_sink_enable, timedrx_src_rdy_int, timedrx_dst_rdy_int, - timedrx_src_rdy, timedrx_dst_rdy, - testrx_src_rdy, testrx_dst_rdy, - rx_src_rdy, rx_dst_rdy, - rx36_src_rdy, rx36_dst_rdy, - rx18_src_rdy, rx18_dst_rdy, - rx18b_src_rdy, rx18b_dst_rdy}; + wire [0:17] dummy18; + + assign debug = {rx_overrun, tx_underrun, bus_error_tx, bus_error_rx, tx_have_space, rx_have_data, EM_NCS4, EM_NCS6, + 6'd0, EM_NOE, EM_NWE, + pkt_src_enable, pkt_sink_enable, timedrx_src_rdy_int, timedrx_dst_rdy_int, + timedrx_src_rdy, timedrx_dst_rdy, + testrx_src_rdy, testrx_dst_rdy, + rx_src_rdy, rx_dst_rdy, rx36_src_rdy, rx36_dst_rdy, rx18_src_rdy, rx18_dst_rdy, rx18b_src_rdy, rx18b_dst_rdy}; endmodule // gpmc_async diff --git a/fpga/usrp2/gpmc/new_read.v b/fpga/usrp2/gpmc/new_read.v new file mode 100644 index 000000000..ae3db23cf --- /dev/null +++ b/fpga/usrp2/gpmc/new_read.v @@ -0,0 +1,62 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +module new_read + (input clk, input reset, input clear, + input [17:0] data_i, input src_rdy_i, output dst_rdy_o, + output reg [15:0] EM_D, input EM_NCS, input EM_NOE, + output have_packet, output [15:0] frame_len, output bus_error); + + wire [17:0] data_int; + wire src_rdy_int, dst_rdy_int; + + fifo_cascade #(.WIDTH(18), .SIZE(12)) rx_fifo + (.clk(clk), .reset(reset), .clear(clear), + .datain(data_i), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o), .space(), + .dataout(data_int), .src_rdy_o(src_rdy_int), .dst_rdy_i(dst_rdy_int), .occupied()); + + fifo_watcher fifo_watcher + (.clk(clk), .reset(reset), .clear(clear), + .src_rdy1(src_rdy_i), .dst_rdy1(dst_rdy_o), .sof1(data_i[16]), .eof1(data_i[17]), + .src_rdy2(src_rdy_int), .dst_rdy2(dst_rdy_int), .sof2(data_int[16]), .eof2(data_int[17]), + .have_packet(have_packet), .length(frame_len), .bus_error(bus_error), + .debug()); + + // Synchronize the async control signals + reg [1:0] cs_del, oe_del; + reg [15:0] counter; + + always @(posedge clk) + if(reset) + begin + cs_del <= 2'b11; + oe_del <= 2'b11; + end + else + begin + cs_del <= { cs_del[0], EM_NCS }; + oe_del <= { oe_del[0], EM_NOE }; + end + + assign dst_rdy_int = ( ~cs_del[1] & ~oe_del[1] & oe_del[0]); // change output on trailing edge + + //always @(posedge clk) // 3 cycle latency ( OE -> OE_del -> FIFO -> output REG ) + always @* // 2 cycle latency ( OE -> OE_del -> FIFO ) + EM_D <= data_int[15:0]; + +endmodule // new_read diff --git a/fpga/usrp2/gpmc/new_write.v b/fpga/usrp2/gpmc/new_write.v new file mode 100644 index 000000000..df0ce19db --- /dev/null +++ b/fpga/usrp2/gpmc/new_write.v @@ -0,0 +1,82 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +module new_write + (input [15:0] EM_D, input [1:0] EM_NBE, input EM_NCS, input EM_NWE, + + input bus_clk, + input fifo_clk, input fifo_rst, input clear, + output [17:0] data_o, output src_rdy_o, input dst_rdy_i, + + input [15:0] frame_len, output reg fifo_ready, + output reg bus_error ); + + wire [15:0] fifo_space; + reg [15:0] counter; + + // Synchronize the async control signals + reg [1:0] cs_del, we_del; + reg [15:0] data_del[0:1]; + + always @(posedge bus_clk) + if(fifo_rst) + begin + cs_del <= 2'b11; + we_del <= 2'b11; + end + else + begin + cs_del <= { cs_del[0], EM_NCS }; + we_del <= { we_del[0], EM_NWE }; + data_del[1] <= data_del[0]; + data_del[0] <= EM_D; + end + + wire first_write = (counter == 0); + wire last_write = ((counter+1) == frame_len); + + wire [17:0] data_int = {last_write,first_write,data_del[1]}; + wire src_rdy_int = (~cs_del[1] & ~we_del[1] & we_del[0]); // rising edge + wire dst_rdy_int; + + always @(posedge bus_clk) + if(fifo_rst | clear) + counter <= 0; + else if(src_rdy_int) + if(last_write) + counter <= 0; + else + counter <= counter + 1; + + always @(posedge bus_clk) + if(fifo_rst | clear) + fifo_ready <= 0; + else + fifo_ready <= /* first_write & */ (fifo_space > 16'd1023); + + always @(posedge bus_clk) + if(fifo_rst | clear) + bus_error <= 0; + else if(src_rdy_int & ~dst_rdy_int) + bus_error <= 1; + + fifo_2clock_cascade #(.WIDTH(18), .SIZE(10)) tx_fifo + (.wclk(bus_clk), .datain(data_int), .src_rdy_i(src_rdy_int), .dst_rdy_o(dst_rdy_int), .space(fifo_space), + .rclk(fifo_clk), .dataout(data_o), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i), .occupied(), .arst(fifo_rst)); + +endmodule // new_write diff --git a/fpga/usrp2/sdr_lib/Makefile.srcs b/fpga/usrp2/sdr_lib/Makefile.srcs index 90eede20f..defbced17 100644 --- a/fpga/usrp2/sdr_lib/Makefile.srcs +++ b/fpga/usrp2/sdr_lib/Makefile.srcs @@ -8,6 +8,8 @@ SDR_LIB_SRCS = $(abspath $(addprefix $(BASE_DIR)/../sdr_lib/, \ acc.v \ add2.v \ +add2_and_clip.v \ +add2_and_clip_reg.v \ add2_and_round.v \ add2_and_round_reg.v \ add2_reg.v \ @@ -22,16 +24,16 @@ cordic.v \ cordic_z24.v \ cordic_stage.v \ dsp_core_rx.v \ -dsp_core_rx_old.v \ dsp_core_tx.v \ hb_dec.v \ hb_interp.v \ round.v \ round_reg.v \ -rx_control.v \ +round_sd.v \ rx_dcoffset.v \ +rx_frontend.v \ sign_extend.v \ small_hb_dec.v \ small_hb_int.v \ -tx_control.v \ +tx_frontend.v \ )) diff --git a/fpga/usrp2/sdr_lib/add2_and_clip.v b/fpga/usrp2/sdr_lib/add2_and_clip.v new file mode 100644 index 000000000..663f5d004 --- /dev/null +++ b/fpga/usrp2/sdr_lib/add2_and_clip.v @@ -0,0 +1,12 @@ + +module add2_and_clip + #(parameter WIDTH=16) + (input [WIDTH-1:0] in1, + input [WIDTH-1:0] in2, + output [WIDTH-1:0] sum); + + wire [WIDTH:0] sum_int = {in1[WIDTH-1],in1} + {in2[WIDTH-1],in2}; + clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip + (.in(sum_int),.out(sum)); + +endmodule // add2_and_clip diff --git a/fpga/usrp2/sdr_lib/add2_and_clip_reg.v b/fpga/usrp2/sdr_lib/add2_and_clip_reg.v new file mode 100644 index 000000000..8073b3b54 --- /dev/null +++ b/fpga/usrp2/sdr_lib/add2_and_clip_reg.v @@ -0,0 +1,25 @@ + +module add2_and_clip_reg + #(parameter WIDTH=16) + (input clk, + input rst, + input [WIDTH-1:0] in1, + input [WIDTH-1:0] in2, + input strobe_in, + output reg [WIDTH-1:0] sum, + output reg strobe_out); + + wire [WIDTH-1:0] sum_int; + + add2_and_clip #(.WIDTH(WIDTH)) add2_and_clip (.in1(in1),.in2(in2),.sum(sum_int)); + + always @(posedge clk) + if(rst) + sum <= 0; + else if(strobe_in) + sum <= sum_int; + + always @(posedge clk) + strobe_out <= strobe_in; + +endmodule // add2_and_clip_reg diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx.v b/fpga/usrp2/sdr_lib/dsp_core_rx.v index 0e69e53f7..639744de7 100644 --- a/fpga/usrp2/sdr_lib/dsp_core_rx.v +++ b/fpga/usrp2/sdr_lib/dsp_core_rx.v @@ -21,8 +21,8 @@ module dsp_core_rx (input clk, input rst, input set_stb, input [7:0] set_addr, input [31:0] set_data, - input [13:0] adc_a, input adc_ovf_a, - input [13:0] adc_b, input adc_ovf_b, + input [23:0] adc_i, input adc_ovf_i, + input [23:0] adc_q, input adc_ovf_q, output [31:0] sample, input run, @@ -30,70 +30,56 @@ module dsp_core_rx output [31:0] debug ); - wire [15:0] scale_i, scale_q; - wire [13:0] adc_a_ofs, adc_b_ofs; - reg [13:0] adc_i, adc_q; wire [31:0] phase_inc; reg [31:0] phase; - wire [35:0] prod_i, prod_q; - wire [23:0] i_cordic, q_cordic; + wire [24:0] i_cordic, q_cordic; + wire [23:0] i_cordic_clip, q_cordic_clip; wire [23:0] i_cic, q_cic; - wire [17:0] i_cic_scaled, q_cic_scaled; - wire [17:0] i_hb1, q_hb1; - wire [17:0] i_hb2, q_hb2; - wire [15:0] i_out, q_out; - + wire [23:0] i_hb1, q_hb1; + wire [23:0] i_hb2, q_hb2; + wire strobe_cic, strobe_hb1, strobe_hb2; wire enable_hb1, enable_hb2; wire [7:0] cic_decim_rate; + reg [23:0] adc_i_mux, adc_q_mux; + wire realmode; + wire swap_iq; + setting_reg #(.my_addr(BASE+0)) sr_0 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(phase_inc),.changed()); + /* setting_reg #(.my_addr(BASE+1)) sr_1 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out({scale_i,scale_q}),.changed()); + */ setting_reg #(.my_addr(BASE+2), .width(10)) sr_2 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out({enable_hb1, enable_hb2, cic_decim_rate}),.changed()); - rx_dcoffset #(.WIDTH(14),.ADDR(BASE+3)) rx_dcoffset_a - (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), - .adc_in(adc_a),.adc_out(adc_a_ofs)); - - rx_dcoffset #(.WIDTH(14),.ADDR(BASE+4)) rx_dcoffset_b - (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), - .adc_in(adc_b),.adc_out(adc_b_ofs)); - - wire [7:0] muxctrl; - setting_reg #(.my_addr(BASE+5), .width(8)) sr_8 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out(muxctrl),.changed()); - - wire [1:0] gpio_ena; - setting_reg #(.my_addr(BASE+6), .width(2)) sr_9 + setting_reg #(.my_addr(BASE+3), .width(2)) sr_3 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out(gpio_ena),.changed()); + .in(set_data),.out({realmode,swap_iq}),.changed()); - always @(posedge clk) - case(muxctrl[3:0]) // The I mapping - 0: adc_i <= adc_a_ofs; - 1: adc_i <= adc_b_ofs; - 2: adc_i <= 0; - default: adc_i <= 0; - endcase // case (muxctrl[3:0]) + // MUX so we can do realmode signals on either input always @(posedge clk) - case(muxctrl[7:4]) // The Q mapping - 0: adc_q <= adc_a_ofs; - 1: adc_q <= adc_b_ofs; - 2: adc_q <= 0; - default: adc_q <= 0; - endcase // case (muxctrl[7:4]) - + if(swap_iq) + begin + adc_i_mux <= adc_q; + adc_q_mux <= realmode ? 24'd0 : adc_i; + end + else + begin + adc_i_mux <= adc_i; + adc_q_mux <= realmode ? 24'd0 : adc_q; + end + + // NCO always @(posedge clk) if(rst) phase <= 0; @@ -102,74 +88,55 @@ module dsp_core_rx else phase <= phase + phase_inc; - MULT18X18S mult_i - (.P(prod_i), // 36-bit multiplier output - .A({{4{adc_i[13]}},adc_i} ), // 18-bit multiplier input - .B({{2{scale_i[15]}},scale_i}), // 18-bit multiplier input - .C(clk), // Clock input - .CE(1), // Clock enable input - .R(rst) // Synchronous reset input - ); - - MULT18X18S mult_q - (.P(prod_q), // 36-bit multiplier output - .A({{4{adc_q[13]}},adc_q} ), // 18-bit multiplier input - .B({{2{scale_q[15]}},scale_q}), // 18-bit multiplier input - .C(clk), // Clock input - .CE(1), // Clock enable input - .R(rst) // Synchronous reset input - ); - - - cordic_z24 #(.bitwidth(24)) + // CORDIC 24-bit I/O + cordic_z24 #(.bitwidth(25)) cordic(.clock(clk), .reset(rst), .enable(run), - .xi(prod_i[23:0]),. yi(prod_q[23:0]), .zi(phase[31:8]), + .xi({adc_i_mux[23],adc_i_mux}),. yi({adc_q_mux[23],adc_q_mux}), .zi(phase[31:8]), .xo(i_cordic),.yo(q_cordic),.zo() ); + clip_reg #(.bits_in(25), .bits_out(24)) clip_i (.clk(clk), .in(i_cordic), .out(i_cordic_clip)); + clip_reg #(.bits_in(25), .bits_out(24)) clip_q (.clk(clk), .in(q_cordic), .out(q_cordic_clip)); + + // CIC decimator 24 bit I/O cic_strober cic_strober(.clock(clk),.reset(rst),.enable(run),.rate(cic_decim_rate), .strobe_fast(1),.strobe_slow(strobe_cic) ); cic_decim #(.bw(24)) decim_i (.clock(clk),.reset(rst),.enable(run), .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), - .signal_in(i_cordic),.signal_out(i_cic)); + .signal_in(i_cordic_clip),.signal_out(i_cic)); cic_decim #(.bw(24)) decim_q (.clock(clk),.reset(rst),.enable(run), .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), - .signal_in(q_cordic),.signal_out(q_cic)); + .signal_in(q_cordic_clip),.signal_out(q_cic)); - round_reg #(.bits_in(24),.bits_out(18)) round_icic (.clk(clk),.in(i_cic),.out(i_cic_scaled)); - round_reg #(.bits_in(24),.bits_out(18)) round_qcic (.clk(clk),.in(q_cic),.out(q_cic_scaled)); - reg strobe_cic_d1; - always @(posedge clk) strobe_cic_d1 <= strobe_cic; - - small_hb_dec #(.WIDTH(18)) small_hb_i + // First (small) halfband 24 bit I/O + small_hb_dec #(.WIDTH(24)) small_hb_i (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run), - .stb_in(strobe_cic_d1),.data_in(i_cic_scaled),.stb_out(strobe_hb1),.data_out(i_hb1)); + .stb_in(strobe_cic),.data_in(i_cic),.stb_out(strobe_hb1),.data_out(i_hb1)); - small_hb_dec #(.WIDTH(18)) small_hb_q + small_hb_dec #(.WIDTH(24)) small_hb_q (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run), - .stb_in(strobe_cic_d1),.data_in(q_cic_scaled),.stb_out(),.data_out(q_hb1)); + .stb_in(strobe_cic),.data_in(q_cic),.stb_out(),.data_out(q_hb1)); + // Second (large) halfband 24 bit I/O wire [8:0] cpi_hb = enable_hb1 ? {cic_decim_rate,1'b0} : {1'b0,cic_decim_rate}; - hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_i + hb_dec #(.WIDTH(24)) hb_i (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb), .stb_in(strobe_hb1),.data_in(i_hb1),.stb_out(strobe_hb2),.data_out(i_hb2)); - hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_q + hb_dec #(.WIDTH(24)) hb_q (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb), .stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2)); - round #(.bits_in(18),.bits_out(16)) round_iout (.in(i_hb2),.out(i_out)); - round #(.bits_in(18),.bits_out(16)) round_qout (.in(q_hb2),.out(q_out)); + // Round final answer to 16 bits + round_sd #(.WIDTH_IN(24),.WIDTH_OUT(16)) round_i + (.clk(clk),.reset(rst), .in(i_hb2),.strobe_in(strobe_hb2), .out(sample[31:16]), .strobe_out(strobe)); - reg [31:0] sample_reg; - always @(posedge clk) - sample_reg <= {i_out,q_out}; + round_sd #(.WIDTH_IN(24),.WIDTH_OUT(16)) round_q + (.clk(clk),.reset(rst), .in(q_hb2),.strobe_in(strobe_hb2), .out(sample[15:0]), .strobe_out()); - assign sample = sample_reg; - assign strobe = strobe_hb2; - assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_cic_d1, strobe_hb1, strobe_hb2}; + assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_hb1, strobe_hb2}; endmodule // dsp_core_rx diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v b/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v new file mode 100644 index 000000000..271db8cef --- /dev/null +++ b/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v @@ -0,0 +1,73 @@ + +`timescale 1ns/1ns +module dsp_core_rx_tb(); + + reg clk, rst; + + initial rst = 1; + initial #1000 rst = 0; + initial clk = 0; + always #5 clk = ~clk; + + initial $dumpfile("dsp_core_rx_tb.vcd"); + initial $dumpvars(0,dsp_core_rx_tb); + + reg signed [23:0] adc_in; + wire signed [15:0] adc_out_i, adc_out_q; + + always @(posedge clk) + begin + $display(adc_in); + $display(adc_out_i); + $display(adc_out_q); + end + + reg run; + reg set_stb; + reg [7:0] set_addr; + reg [31:0] set_data; + + dsp_core_rx #(.BASE(0)) dsp_core_rx + (.clk(clk),.rst(rst), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .adc_i(adc_in), .adc_ovf_i(0), + .adc_q(0), .adc_ovf_q(0), + .sample({adc_out_i,adc_out_q}), + .run(run), .strobe(), .debug()); + + initial + begin + run <= 0; + @(negedge rst); + @(posedge clk); + set_addr <= 1; + set_data <= {16'd64,16'd64}; // set gains + set_stb <= 1; + @(posedge clk); + set_addr <= 2; + set_data <= {16'd0,8'd3,8'd1}; // set decim + set_stb <= 1; + @(posedge clk); + set_addr <= 0; + //set_data <= {32'h0000_0000}; + set_data <= {32'h01CA_C083}; // 700 kHz + set_stb <= 1; + @(posedge clk); + set_stb <= 0; + @(posedge clk); + run <= 1; + end + + always @(posedge clk) + //adc_in <= 24'd1000000; + adc_in <= 24'h80_0000; + + /* + always @(posedge clk) + if(rst) + adc_in <= 0; + else + adc_in <= adc_in + 4; + //adc_in <= (($random % 473) + 23)/4; +*/ +endmodule // dsp_core_rx_tb diff --git a/fpga/usrp2/sdr_lib/dsp_core_tx.v b/fpga/usrp2/sdr_lib/dsp_core_tx.v index 58bd82f6e..f02c63b42 100644 --- a/fpga/usrp2/sdr_lib/dsp_core_tx.v +++ b/fpga/usrp2/sdr_lib/dsp_core_tx.v @@ -21,8 +21,7 @@ module dsp_core_tx (input clk, input rst, input set_stb, input [7:0] set_addr, input [31:0] set_data, - output reg [15:0] dac_a, - output reg [15:0] dac_b, + output [23:0] tx_i, output [23:0] tx_q, // To tx_control input [31:0] sample, @@ -50,10 +49,6 @@ module dsp_core_tx (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out({enable_hb1, enable_hb2, interp_rate}),.changed()); - setting_reg #(.my_addr(BASE+4), .width(8)) sr_4 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({dacmux_b,dacmux_a}),.changed()); - // Strobes are all now delayed by 1 cycle for timing reasons wire strobe_cic_pre, strobe_hb1_pre, strobe_hb2_pre; reg strobe_cic = 1; @@ -148,20 +143,9 @@ module dsp_core_tx .CE(1), // Clock enable input .R(rst) // Synchronous reset input ); - - always @(posedge clk) - case(dacmux_a) - 0 : dac_a <= prod_i[28:13]; - 1 : dac_a <= prod_q[28:13]; - default : dac_a <= 0; - endcase // case(dacmux_a) - - always @(posedge clk) - case(dacmux_b) - 0 : dac_b <= prod_i[28:13]; - 1 : dac_b <= prod_q[28:13]; - default : dac_b <= 0; - endcase // case(dacmux_b) + + assign tx_i = prod_i[28:5]; + assign tx_q = prod_q[28:5]; assign debug = {strobe_cic, strobe_hb1, strobe_hb2,run}; diff --git a/fpga/usrp2/sdr_lib/hb_dec.v b/fpga/usrp2/sdr_lib/hb_dec.v index 9747f0adb..8d21c21c0 100644 --- a/fpga/usrp2/sdr_lib/hb_dec.v +++ b/fpga/usrp2/sdr_lib/hb_dec.v @@ -22,17 +22,27 @@ // myfilt = round(2^18 * halfgen4(.7/4,8)) module hb_dec - #(parameter IWIDTH=18, OWIDTH=18, CWIDTH=18, ACCWIDTH=24) + #(parameter WIDTH=24) (input clk, input rst, input bypass, input run, input [8:0] cpi, // Clocks per input -- equal to the decimation ratio ahead of this block input stb_in, - input [IWIDTH-1:0] data_in, + input [WIDTH-1:0] data_in, output reg stb_out, - output reg [OWIDTH-1:0] data_out); + output reg [WIDTH-1:0] data_out); + localparam INTWIDTH = 17; + localparam ACCWIDTH = WIDTH + 3; + + // Round off inputs to 17 bits because of 18 bit multipliers + wire [INTWIDTH-1:0] data_rnd; + wire stb_rnd; + + round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in + (.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd)); + // Control reg [3:0] addr_odd_a, addr_odd_b, addr_odd_c, addr_odd_d; wire write_odd, write_even, do_mult; @@ -45,16 +55,16 @@ module hb_dec always @(posedge clk) if(rst | ~run) odd <= 0; - else if(stb_in) + else if(stb_rnd) odd <= ~odd; - assign write_odd = stb_in & odd; - assign write_even = stb_in & ~odd; + assign write_odd = stb_rnd & odd; + assign write_even = stb_rnd & ~odd; always @(posedge clk) if(rst | ~run) phase <= 0; - else if(stb_in & odd) + else if(stb_rnd & odd) phase <= 1; else if(phase == 4) phase <= 0; @@ -69,7 +79,7 @@ module hb_dec if(rst) stb_out_pre <= 0; else - stb_out_pre <= {stb_out_pre[14:0],(stb_in & odd)}; + stb_out_pre <= {stb_out_pre[14:0],(stb_rnd & odd)}; always @* case(phase) @@ -93,11 +103,12 @@ module hb_dec assign clear = stb_out_pre[3]; // Data - wire [IWIDTH-1:0] data_odd_a, data_odd_b, data_odd_c, data_odd_d; - wire [IWIDTH-1:0] sum1, sum2; - wire [OWIDTH-1:0] final_sum; - reg [CWIDTH-1:0] coeff1, coeff2; - wire [35:0] prod1, prod2; + wire [INTWIDTH-1:0] data_odd_a, data_odd_b, data_odd_c, data_odd_d; + reg [INTWIDTH:0] sum1, sum2; // these are 18-bit inputs to mult + reg [WIDTH:0] final_sum; + wire [WIDTH-1:0] final_sum_clip; + reg [17:0] coeff1, coeff2; + wire [35:0] prod1, prod2; always @* // Outer coeffs case(phase_d1) @@ -117,19 +128,19 @@ module hb_dec default : coeff2 = -6107; endcase // case(phase) - srl #(.WIDTH(IWIDTH)) srl_odd_a - (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_a),.out(data_odd_a)); - srl #(.WIDTH(IWIDTH)) srl_odd_b - (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_b),.out(data_odd_b)); - srl #(.WIDTH(IWIDTH)) srl_odd_c - (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_c),.out(data_odd_c)); - srl #(.WIDTH(IWIDTH)) srl_odd_d - (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_d),.out(data_odd_d)); - - add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add1 (.clk(clk),.in1(data_odd_a),.in2(data_odd_b),.sum(sum1)); - add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add2 (.clk(clk),.in1(data_odd_c),.in2(data_odd_d),.sum(sum2)); - - wire [IWIDTH-1:0] data_even; + srl #(.WIDTH(INTWIDTH)) srl_odd_a + (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_a),.out(data_odd_a)); + srl #(.WIDTH(INTWIDTH)) srl_odd_b + (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_b),.out(data_odd_b)); + srl #(.WIDTH(INTWIDTH)) srl_odd_c + (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_c),.out(data_odd_c)); + srl #(.WIDTH(INTWIDTH)) srl_odd_d + (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_d),.out(data_odd_d)); + + always @(posedge clk) sum1 <= {data_odd_a[INTWIDTH-1],data_odd_a} + {data_odd_b[INTWIDTH-1],data_odd_b}; + always @(posedge clk) sum2 <= {data_odd_c[INTWIDTH-1],data_odd_c} + {data_odd_d[INTWIDTH-1],data_odd_d}; + + wire [INTWIDTH-1:0] data_even; reg [3:0] addr_even; always @(posedge clk) @@ -140,49 +151,39 @@ module hb_dec default : addr_even <= 7; endcase // case(cpi) - srl #(.WIDTH(IWIDTH)) srl_even - (.clk(clk),.write(write_even),.in(data_in),.addr(addr_even),.out(data_even)); - - localparam MWIDTH = ACCWIDTH-2; - wire [MWIDTH-1:0] sum_of_prod; + srl #(.WIDTH(INTWIDTH)) srl_even + (.clk(clk),.write(write_even),.in(data_rnd),.addr(addr_even),.out(data_even)); MULT18X18S mult1(.C(clk), .CE(do_mult), .R(rst), .P(prod1), .A(coeff1), .B(sum1) ); MULT18X18S mult2(.C(clk), .CE(do_mult), .R(rst), .P(prod2), .A(coeff2), .B(sum2) ); - add2_and_round_reg #(.WIDTH(MWIDTH)) - add3 (.clk(clk),.in1(prod1[35:36-MWIDTH]),.in2(prod2[35:36-MWIDTH]),.sum(sum_of_prod)); - wire [ACCWIDTH-1:0] acc_out; + reg [35:0] sum_of_prod; + always @(posedge clk) sum_of_prod <= prod1 + prod2; // Can't overflow - acc #(.IWIDTH(MWIDTH),.OWIDTH(ACCWIDTH)) - acc (.clk(clk),.clear(clear),.acc(do_acc),.in(sum_of_prod),.out(acc_out)); + wire [ACCWIDTH-1:0] acc_out; + acc #(.IWIDTH(ACCWIDTH-2),.OWIDTH(ACCWIDTH)) + acc (.clk(clk),.clear(clear),.acc(do_acc),.in(sum_of_prod[35:38-ACCWIDTH]),.out(acc_out)); - localparam SHIFT_FACTOR = ACCWIDTH-IWIDTH-5; wire [ACCWIDTH-1:0] data_even_signext; - wire [ACCWIDTH:0] final_sum_unrounded; - sign_extend #(.bits_in(IWIDTH),.bits_out(ACCWIDTH-SHIFT_FACTOR)) - signext_data_even (.in(data_even),.out(data_even_signext[ACCWIDTH-1:SHIFT_FACTOR])); - assign data_even_signext[SHIFT_FACTOR-1:0] = 0; + localparam SHIFT_FACTOR = 6; - add2_reg /* add2_and_round_reg */ #(.WIDTH(ACCWIDTH+1)) - final_adder (.clk(clk), .in1({acc_out,1'b0}), .in2({data_even_signext,1'b0}), .sum(final_sum_unrounded)); - - round_reg #(.bits_in(ACCWIDTH-4),.bits_out(OWIDTH)) - final_round (.clk(clk),.in(final_sum_unrounded[ACCWIDTH-5:0]),.out(final_sum)); - - // Output - always @(posedge clk) - if(bypass) - data_out <= data_in; - else if(stb_out_pre[9]) - data_out <= final_sum; + sign_extend #(.bits_in(INTWIDTH),.bits_out(ACCWIDTH-SHIFT_FACTOR)) signext_data_even + (.in(data_even),.out(data_even_signext[ACCWIDTH-1:SHIFT_FACTOR])); + assign data_even_signext[SHIFT_FACTOR-1:0] = 0; + always @(posedge clk) final_sum <= acc_out + data_even_signext; + + clip #(.bits_in(WIDTH+1), .bits_out(WIDTH)) clip (.in(final_sum), .out(final_sum_clip)); + + // Output MUX to allow for bypass + wire selected_stb = bypass ? stb_in : stb_out_pre[8]; + always @(posedge clk) - if(rst) - stb_out <= 0; - else if(bypass) - stb_out <= stb_in; - else - stb_out <= stb_out_pre[9]; - + begin + stb_out <= selected_stb; + if(selected_stb) + data_out <= bypass ? data_in : final_sum_clip; + end + endmodule // hb_dec diff --git a/fpga/usrp2/sdr_lib/hb_dec_tb.v b/fpga/usrp2/sdr_lib/hb_dec_tb.v index 256f6085d..153cfba76 100644 --- a/fpga/usrp2/sdr_lib/hb_dec_tb.v +++ b/fpga/usrp2/sdr_lib/hb_dec_tb.v @@ -18,7 +18,7 @@ module hb_dec_tb( ) ; // Parameters for instantiation - parameter clocks = 9'd2 ; // Number of clocks per input + parameter clocks = 9'd12 ; // Number of clocks per input parameter decim = 1 ; // Sets the filter to decimate parameter rate = 2 ; // Sets the decimation rate @@ -26,9 +26,9 @@ module hb_dec_tb( ) ; reg reset ; reg enable ; reg strobe_in ; - reg signed [17:0] data_in ; + reg signed [23:0] data_in ; wire strobe_out ; - wire signed [17:0] data_out ; + wire signed [23:0] data_out ; initial begin @@ -65,8 +65,8 @@ module hb_dec_tb( ) ; */ - hb_dec #(.IWIDTH(18),.OWIDTH(18),.CWIDTH(18),.ACCWIDTH(24)) uut - (.clk(clock),.rst(reset),.bypass(0),.cpi(clocks),.stb_in(strobe_in),.data_in(data_in), + hb_dec #(.WIDTH(24)) uut + (.clk(clock),.rst(reset),.bypass(0),.run(1),.cpi(clocks),.stb_in(strobe_in),.data_in(data_in), .stb_out(strobe_out),.data_out(data_out) ); integer i, ri, ro, infile, outfile ; diff --git a/fpga/usrp2/sdr_lib/input.dat b/fpga/usrp2/sdr_lib/input.dat index 1e649ac2e..85b5887e8 100644 --- a/fpga/usrp2/sdr_lib/input.dat +++ b/fpga/usrp2/sdr_lib/input.dat @@ -6,7 +6,6 @@ 0 0 0 --131072 0 0 0 @@ -16,6 +15,7 @@ 0 0 0 +8388607 0 0 0 @@ -38,34 +38,6 @@ 0 0 0 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 0 0 0 @@ -82,6 +54,7 @@ 0 0 0 +8388607 0 0 0 @@ -96,200 +69,6 @@ 0 0 0 -131071 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -131071 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -100000 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 --131072 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 --131072 -0 -0 0 0 0 @@ -313,6 +92,56 @@ 0 0 0 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 +8388607 0 0 0 @@ -339,3 +168,4 @@ 0 0 0 + diff --git a/fpga/usrp2/sdr_lib/round.v b/fpga/usrp2/sdr_lib/round.v index c4f9ec9cd..7a137d702 100644 --- a/fpga/usrp2/sdr_lib/round.v +++ b/fpga/usrp2/sdr_lib/round.v @@ -26,8 +26,10 @@ module round #(parameter bits_in=0, parameter bits_out=0) (input [bits_in-1:0] in, - output [bits_out-1:0] out); + output [bits_out-1:0] out, + output [bits_in-bits_out:0] err); assign out = in[bits_in-1:bits_in-bits_out] + (in[bits_in-1] & |in[bits_in-bits_out-1:0]); + assign err = in - {out,{(bits_in-bits_out){1'b0}}}; endmodule // round diff --git a/fpga/usrp2/sdr_lib/round_reg.v b/fpga/usrp2/sdr_lib/round_reg.v index aa0972dab..6f2e974d7 100644 --- a/fpga/usrp2/sdr_lib/round_reg.v +++ b/fpga/usrp2/sdr_lib/round_reg.v @@ -27,13 +27,18 @@ module round_reg parameter bits_out=0) (input clk, input [bits_in-1:0] in, - output reg [bits_out-1:0] out); + output reg [bits_out-1:0] out, + output reg [bits_in-bits_out:0] err); wire [bits_out-1:0] temp; - - round #(.bits_in(bits_in),.bits_out(bits_out)) round (.in(in),.out(temp)); + wire [bits_in-bits_out:0] err_temp; + + round #(.bits_in(bits_in),.bits_out(bits_out)) round (.in(in),.out(temp), .err(err_temp)); always @(posedge clk) out <= temp; + + always @(posedge clk) + err <= err_temp; -endmodule // round +endmodule // round_reg diff --git a/fpga/usrp2/sdr_lib/round_sd.v b/fpga/usrp2/sdr_lib/round_sd.v new file mode 100644 index 000000000..aeeb3502f --- /dev/null +++ b/fpga/usrp2/sdr_lib/round_sd.v @@ -0,0 +1,22 @@ + + +module round_sd + #(parameter WIDTH_IN=18, + parameter WIDTH_OUT=16) + (input clk, input reset, + input [WIDTH_IN-1:0] in, input strobe_in, + output [WIDTH_OUT-1:0] out, output strobe_out); + + localparam ERR_WIDTH = WIDTH_IN - WIDTH_OUT + 1; + + wire [ERR_WIDTH-1:0] err; + wire [WIDTH_IN-1:0] err_ext, sum; + + sign_extend #(.bits_in(ERR_WIDTH),.bits_out(WIDTH_IN)) ext_err (.in(err), .out(err_ext)); + + add2_and_clip_reg #(.WIDTH(WIDTH_IN)) add2_and_clip_reg + (.clk(clk), .rst(reset), .in1(in), .in2(err_ext), .strobe_in(strobe_in), .sum(sum), .strobe_out(strobe_out)); + + round #(.bits_in(WIDTH_IN),.bits_out(WIDTH_OUT)) round_sum (.in(sum), .out(out), .err(err)); + +endmodule // round_sd diff --git a/fpga/usrp2/sdr_lib/round_sd_tb.v b/fpga/usrp2/sdr_lib/round_sd_tb.v new file mode 100644 index 000000000..1e8e9a323 --- /dev/null +++ b/fpga/usrp2/sdr_lib/round_sd_tb.v @@ -0,0 +1,58 @@ + +module round_sd_tb(); + + reg clk, rst; + + initial rst = 1; + initial #1000 rst = 0; + initial clk = 0; + always #5 clk = ~clk; + + initial $dumpfile("round_sd_tb.vcd"); + initial $dumpvars(0,round_sd_tb); + + localparam WIDTH_IN = 8; + localparam WIDTH_OUT = 5; + + reg [WIDTH_IN-1:0] adc_in, adc_in_del; + wire [WIDTH_OUT-1:0] adc_out; + + integer factor = 1<<(WIDTH_IN-WIDTH_OUT); + + always @(posedge clk) + if(~rst) + begin + if(adc_in_del[WIDTH_IN-1]) + $write("-%d\t",-adc_in_del); + else + $write("%d\t",adc_in_del); + if(adc_out[WIDTH_OUT-1]) + $write("-%d\t",-adc_out); + else + $write("%d\t",adc_out); + $write("\n"); + + //$write("%f\t",adc_in_del/factor); + //$write("%f\n",adc_in_del/factor-adc_out); + end + + round_sd #(.WIDTH_IN(WIDTH_IN),.WIDTH_OUT(WIDTH_OUT)) + round_sd(.clk(clk),.reset(rst), .in(adc_in), .strobe_in(1'b1), .out(adc_out), .strobe_out()); + + reg [5:0] counter = 0; + + always @(posedge clk) + counter <= counter+1; + + always @(posedge clk) + adc_in_del <= adc_in; + + always @(posedge clk) + if(rst) + adc_in <= 0; + else if(counter == 63) + adc_in <= adc_in + 1; + + initial #300000 $finish; + +endmodule // longfifo_tb diff --git a/fpga/usrp2/sdr_lib/rx_dcoffset.v b/fpga/usrp2/sdr_lib/rx_dcoffset.v index 64ff4110d..e43461261 100644 --- a/fpga/usrp2/sdr_lib/rx_dcoffset.v +++ b/fpga/usrp2/sdr_lib/rx_dcoffset.v @@ -18,43 +18,40 @@ module rx_dcoffset - #(parameter WIDTH=14, - parameter ADDR=8'd0) - (input clk, input rst, - input set_stb, input [7:0] set_addr, input [31:0] set_data, - input signed [WIDTH-1:0] adc_in, output signed [WIDTH-1:0] adc_out); - - // Because of some extra delays to make timing easier, the transfer function is: - // (z-1)/(z^2-z-alpha) where alpha is 1/2^n + #(parameter WIDTH=16, + parameter ADDR=8'd0, + parameter alpha_shift=16) + (input clk, input rst, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input [WIDTH-1:0] in, output [WIDTH-1:0] out); - wire set_now = set_stb & (ADDR == set_addr); + wire set_now = set_stb & (ADDR == set_addr); - reg fixed; // uses fixed offset - wire signed [WIDTH-1:0] fixed_dco; - reg signed [31:0] integrator; + reg fixed; // uses fixed offset + wire [WIDTH-1:0] fixed_dco; + + localparam int_width = WIDTH + alpha_shift; + reg [int_width-1:0] integrator; + wire [WIDTH-1:0] quantized; always @(posedge clk) if(rst) begin fixed <= 0; - integrator <= 32'd0; + integrator <= {int_width{1'b0}}; end else if(set_now) begin - integrator <= {set_data[WIDTH-1:0],{(32-WIDTH){1'b0}}}; + //integrator <= {set_data[30:0],{(31-int_width){1'b0}}}; fixed <= set_data[31]; end else if(~fixed) - integrator <= integrator + adc_out; - - wire [WIDTH:0] scaled_integrator; - - round #(.bits_in(33),.bits_out(15)) round (.in({integrator[31],integrator}),.out(scaled_integrator)); - - wire [WIDTH:0] adc_out_int = {adc_in[WIDTH-1],adc_in} - scaled_integrator; + integrator <= integrator + {{(alpha_shift){out[WIDTH-1]}},out}; - clip_reg #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip_adc - (.clk(clk),.in(adc_out_int),.out(adc_out)); + round_sd #(.WIDTH_IN(int_width),.WIDTH_OUT(WIDTH)) round_sd + (.clk(clk), .reset(rst), .in(integrator), .strobe_in(1'b1), .out(quantized), .strobe_out()); + add2_and_clip_reg #(.WIDTH(WIDTH)) add2_and_clip_reg + (.clk(clk), .rst(rst), .in1(in), .in2(-quantized), .strobe_in(1'b1), .sum(out), .strobe_out()); endmodule // rx_dcoffset diff --git a/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v b/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v index b0dd8cb05..b4fb66ad7 100644 --- a/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v +++ b/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v @@ -29,14 +29,26 @@ module rx_dcoffset_tb(); initial $dumpfile("rx_dcoffset_tb.vcd"); initial $dumpvars(0,rx_dcoffset_tb); - reg [13:0] adc_in = 7; + reg [13:0] adc_in; wire [13:0] adc_out; always @(posedge clk) - $display("%d\t%d",adc_in,adc_out); + begin + if(adc_in[13]) + $write("-%d,",-adc_in); + else + $write("%d,",adc_in); + if(adc_out[13]) + $write("-%d\n",-adc_out); + else + $write("%d\n",adc_out); + end - rx_dcoffset #(.WIDTH(14),.ADDR(0)) + rx_dcoffset #(.WIDTH(14),.ADDR(0), .alpha_shift(8)) rx_dcoffset(.clk(clk),.rst(rst),.set_stb(0),.set_addr(0),.set_data(0), - .adc_in(adc_in),.adc_out(adc_out)); + .in(adc_in),.out(adc_out)); + + always @(posedge clk) + adc_in <= (($random % 473) + 23)/4; endmodule // longfifo_tb diff --git a/fpga/usrp2/sdr_lib/rx_frontend.v b/fpga/usrp2/sdr_lib/rx_frontend.v new file mode 100644 index 000000000..04b14787e --- /dev/null +++ b/fpga/usrp2/sdr_lib/rx_frontend.v @@ -0,0 +1,73 @@ + +module rx_frontend + #(parameter BASE = 0) + (input clk, input rst, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + input [15:0] adc_a, input adc_ovf_a, + input [15:0] adc_b, input adc_ovf_b, + + output [23:0] i_out, output [23:0] q_out, + input run, + output [31:0] debug + ); + + reg [15:0] adc_i, adc_q; + wire [17:0] adc_i_ofs, adc_q_ofs; + wire [35:0] corr_i, corr_q; wire [17:0] mag_corr,phase_corr; + wire swap_iq; + wire [23:0] i_final, q_final; + + setting_reg #(.my_addr(BASE), .width(1)) sr_8 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(swap_iq),.changed()); + + always @(posedge clk) + if(swap_iq) // Swap + {adc_i,adc_q} <= {adc_b,adc_a}; + else + {adc_i,adc_q} <= {adc_a,adc_b}; + + setting_reg #(.my_addr(BASE+1),.width(18)) sr_1 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(mag_corr),.changed()); + + setting_reg #(.my_addr(BASE+2),.width(18)) sr_2 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(phase_corr),.changed()); + + rx_dcoffset #(.WIDTH(18),.ADDR(BASE+3)) rx_dcoffset_i + (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .in({adc_i,2'b00}),.out(adc_i_ofs)); + + rx_dcoffset #(.WIDTH(18),.ADDR(BASE+4)) rx_dcoffset_q + (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .in({adc_q,2'b00}),.out(adc_q_ofs)); + + MULT18X18S mult_mag_corr + (.P(corr_i), .A(adc_i_ofs), .B(mag_corr), .C(clk), .CE(1), .R(rst) ); + + MULT18X18S mult_phase_corr + (.P(corr_q), .A(adc_i_ofs), .B(phase_corr), .C(clk), .CE(1), .R(rst) ); + + add2_and_clip_reg #(.WIDTH(24)) add_clip_i + (.clk(clk), .rst(rst), + .in1({adc_i_ofs,6'd0}), .in2({{4{corr_i[35]}},corr_i[35:16]}), .strobe_in(1'b1), + .sum(i_final), .strobe_out()); + + add2_and_clip_reg #(.WIDTH(24)) add_clip_q + (.clk(clk), .rst(rst), + .in1({adc_q_ofs,6'd0}), .in2({{4{corr_q[35]}},corr_q[35:16]}), .strobe_in(1'b1), + .sum(q_final), .strobe_out()); + + assign i_out = i_final; + assign q_out = q_final; + + /* + round_sd #(.WIDTH_IN(24),.WIDTH_OUT(18)) round_i + (.clk(clk), .reset(rst), .in(i_final), .strobe_in(1'b1), .out(i_out), .strobe_out()); + + round_sd #(.WIDTH_IN(24),.WIDTH_OUT(18)) round_q + (.clk(clk), .reset(rst), .in(q_final), .strobe_in(1'b1), .out(q_out), .strobe_out()); + */ +endmodule // rx_frontend diff --git a/fpga/usrp2/sdr_lib/rx_frontend_tb.v b/fpga/usrp2/sdr_lib/rx_frontend_tb.v new file mode 100644 index 000000000..487b72687 --- /dev/null +++ b/fpga/usrp2/sdr_lib/rx_frontend_tb.v @@ -0,0 +1,45 @@ + +`timescale 1ns/1ns +module rx_frontend_tb(); + + reg clk, rst; + + initial rst = 1; + initial #1000 rst = 0; + initial clk = 0; + always #5 clk = ~clk; + + initial $dumpfile("rx_frontend_tb.vcd"); + initial $dumpvars(0,rx_frontend_tb); + + reg [15:0] adc_in; + wire [17:0] adc_out; + + always @(posedge clk) + begin + if(adc_in[13]) + $write("-%d,",-adc_in); + else + $write("%d,",adc_in); + if(adc_out[13]) + $write("-%d\n",-adc_out); + else + $write("%d\n",adc_out); + end + + rx_frontend #(.BASE(0)) rx_frontend + (.clk(clk),.rst(rst), + .set_stb(0),.set_addr(0),.set_data(0), + .adc_a(adc_in), .adc_ovf_a(0), + .adc_b(0), .adc_ovf_b(0), + .i_out(adc_out),.q_out(), + .run(), .debug()); + + always @(posedge clk) + if(rst) + adc_in <= 0; + else + adc_in <= adc_in + 4; + //adc_in <= (($random % 473) + 23)/4; + +endmodule // rx_frontend_tb diff --git a/fpga/usrp2/sdr_lib/small_hb_dec.v b/fpga/usrp2/sdr_lib/small_hb_dec.v index 151b8c287..a7f93e056 100644 --- a/fpga/usrp2/sdr_lib/small_hb_dec.v +++ b/fpga/usrp2/sdr_lib/small_hb_dec.v @@ -29,21 +29,30 @@ module small_hb_dec input stb_in, input [WIDTH-1:0] data_in, output reg stb_out, - output [WIDTH-1:0] data_out); + output reg [WIDTH-1:0] data_out); - reg stb_in_d1; - reg [WIDTH-1:0] data_in_d1; - always @(posedge clk) stb_in_d1 <= stb_in; - always @(posedge clk) data_in_d1 <= data_in; + // Round off inputs to 17 bits because of 18 bit multipliers + localparam INTWIDTH = 17; + wire [INTWIDTH-1:0] data_rnd; + wire stb_rnd; + + round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in + (.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd)); + + + reg stb_rnd_d1; + reg [INTWIDTH-1:0] data_rnd_d1; + always @(posedge clk) stb_rnd_d1 <= stb_rnd; + always @(posedge clk) data_rnd_d1 <= data_rnd; wire go; reg phase, go_d1, go_d2, go_d3, go_d4; always @(posedge clk) if(rst | ~run) phase <= 0; - else if(stb_in_d1) + else if(stb_rnd_d1) phase <= ~phase; - assign go = stb_in_d1 & phase; + assign go = stb_rnd_d1 & phase; always @(posedge clk) if(rst | ~run) begin @@ -63,11 +72,11 @@ module small_hb_dec wire [17:0] coeff_a = -10690; wire [17:0] coeff_b = 75809; - reg [WIDTH-1:0] d1, d2, d3, d4 , d5, d6; + reg [INTWIDTH-1:0] d1, d2, d3, d4 , d5, d6; always @(posedge clk) - if(stb_in_d1 | rst) + if(stb_rnd_d1 | rst) begin - d1 <= data_in_d1; + d1 <= data_rnd_d1; d2 <= d1; d3 <= d2; d4 <= d3; @@ -76,16 +85,14 @@ module small_hb_dec end reg [17:0] sum_a, sum_b, middle, middle_d1; - wire [17:0] sum_a_unreg, sum_b_unreg; - add2 #(.WIDTH(18)) add2_a (.in1(data_in_d1),.in2(d6),.sum(sum_a_unreg)); - add2 #(.WIDTH(18)) add2_b (.in1(d2),.in2(d4),.sum(sum_b_unreg)); - + always @(posedge clk) if(go) begin - sum_a <= sum_a_unreg; - sum_b <= sum_b_unreg; - middle <= d3; + sum_a <= {data_rnd_d1[INTWIDTH-1],data_rnd_d1} + {d6[INTWIDTH-1],d6}; + sum_b <= {d2[INTWIDTH-1],d2} + {d4[INTWIDTH-1],d4}; + //middle <= {d3[INTWIDTH-1],d3}; + middle <= {d3,1'b0}; end always @(posedge clk) @@ -106,23 +113,22 @@ module small_hb_dec else if(go_d3) accum <= accum + {prod}; - wire [17:0] accum_rnd; - round #(.bits_in(36),.bits_out(18)) round_acc (.in(accum),.out(accum_rnd)); + wire [WIDTH:0] accum_rnd; + wire [WIDTH-1:0] accum_rnd_clip; + + wire stb_round; + + round_sd #(.WIDTH_IN(36),.WIDTH_OUT(WIDTH+1)) round_acc + (.clk(clk), .reset(rst), .in(accum), .strobe_in(go_d4), .out(accum_rnd), .strobe_out(stb_round)); - reg [17:0] final_sum; + clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip (.in(accum_rnd), .out(accum_rnd_clip)); + + // Output always @(posedge clk) - if(bypass) - final_sum <= data_in_d1; - else if(go_d4) - final_sum <= accum_rnd; + begin + stb_out <= bypass ? stb_in : stb_round; + data_out <= bypass ? data_in : accum_rnd_clip; + end - assign data_out = final_sum; - always @(posedge clk) - if(rst) - stb_out <= 0; - else if(bypass) - stb_out <= stb_in_d1; - else - stb_out <= go_d4; endmodule // small_hb_dec diff --git a/fpga/usrp2/sdr_lib/tx_frontend.v b/fpga/usrp2/sdr_lib/tx_frontend.v new file mode 100644 index 000000000..d8525dd25 --- /dev/null +++ b/fpga/usrp2/sdr_lib/tx_frontend.v @@ -0,0 +1,86 @@ + +module tx_frontend + #(parameter BASE=0, + parameter WIDTH_OUT=16) + (input clk, input rst, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input [23:0] tx_i, input [23:0] tx_q, input run, + output reg [WIDTH_OUT-1:0] dac_a, output reg [WIDTH_OUT-1:0] dac_b + ); + + // IQ balance --> DC offset --> rounding --> mux + + wire [23:0] i_dco, q_dco, i_ofs, q_ofs; + wire [WIDTH_OUT-1:0] i_final, q_final; + wire [7:0] mux_ctrl; + wire [35:0] corr_i, corr_q; + wire [23:0] i_bal, q_bal; + wire [17:0] mag_corr, phase_corr; + + setting_reg #(.my_addr(BASE+0), .width(24)) sr_0 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(i_dco),.changed()); + + setting_reg #(.my_addr(BASE+1), .width(24)) sr_1 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(q_dco),.changed()); + + setting_reg #(.my_addr(BASE+2),.width(18)) sr_2 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(mag_corr),.changed()); + + setting_reg #(.my_addr(BASE+3),.width(18)) sr_3 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(phase_corr),.changed()); + + setting_reg #(.my_addr(BASE+4), .width(8)) sr_4 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(mux_ctrl),.changed()); + + // IQ Balance + MULT18X18S mult_mag_corr + (.P(corr_i), .A(tx_i[23:6]), .B(mag_corr), .C(clk), .CE(1), .R(rst) ); + + MULT18X18S mult_phase_corr + (.P(corr_q), .A(tx_i[23:6]), .B(phase_corr), .C(clk), .CE(1), .R(rst) ); + + add2_and_clip_reg #(.WIDTH(24)) add_clip_i + (.clk(clk), .rst(rst), + .in1(tx_i), .in2({{4{corr_i[35]}},corr_i[35:16]}), .strobe_in(1'b1), + .sum(i_bal), .strobe_out()); + + add2_and_clip_reg #(.WIDTH(24)) add_clip_q + (.clk(clk), .rst(rst), + .in1(tx_q), .in2({{4{corr_q[35]}},corr_q[35:16]}), .strobe_in(1'b1), + .sum(q_bal), .strobe_out()); + + // DC Offset + add2_and_clip_reg #(.WIDTH(24)) add_dco_i + (.clk(clk), .rst(rst), .in1(i_dco), .in2(i_bal), .strobe_in(1'b1), .sum(i_ofs), .strobe_out()); + + add2_and_clip_reg #(.WIDTH(24)) add_dco_q + (.clk(clk), .rst(rst), .in1(q_dco), .in2(q_bal), .strobe_in(1'b1), .sum(q_ofs), .strobe_out()); + + // Rounding + round_sd #(.WIDTH_IN(24),.WIDTH_OUT(WIDTH_OUT)) round_i + (.clk(clk), .reset(rst), .in(i_ofs),.strobe_in(1'b1), .out(i_final), .strobe_out()); + + round_sd #(.WIDTH_IN(24),.WIDTH_OUT(WIDTH_OUT)) round_q + (.clk(clk), .reset(rst), .in(q_ofs),.strobe_in(1'b1), .out(q_final), .strobe_out()); + + // Mux + always @(posedge clk) + case(mux_ctrl[3:0]) + 0 : dac_a <= i_final; + 1 : dac_a <= q_final; + default : dac_a <= 0; + endcase // case (mux_ctrl[3:0]) + + always @(posedge clk) + case(mux_ctrl[7:4]) + 0 : dac_b <= i_final; + 1 : dac_b <= q_final; + default : dac_b <= 0; + endcase // case (mux_ctrl[7:4]) + +endmodule // tx_frontend diff --git a/fpga/usrp2/top/B100/u1plus_core.v b/fpga/usrp2/top/B100/u1plus_core.v index 8a02f0fb8..4683f653c 100644 --- a/fpga/usrp2/top/B100/u1plus_core.v +++ b/fpga/usrp2/top/B100/u1plus_core.v @@ -30,7 +30,6 @@ module u1plus_core output sclk, output [15:0] sen, output mosi, input miso, input cgen_st_status, input cgen_st_ld, input cgen_st_refmon, output cgen_sync_b, output cgen_ref_sel, - output tx_underrun, output rx_overrun, inout [15:0] io_tx, inout [15:0] io_rx, output [13:0] tx_i, output [13:0] tx_q, input [11:0] rx_i, input [11:0] rx_q, @@ -41,24 +40,31 @@ module u1plus_core localparam RXFIFOSIZE = 11; // 64 total regs in address space - localparam SR_RX_CTRL = 0; // 9 regs (+0 to +8) - localparam SR_RX_DSP = 16; // 7 regs (+0 to +6) - localparam SR_TX_CTRL = 24; // 6 regs (+0 to +5) - localparam SR_TX_DSP = 32; // 5 regs (+0 to +4) - localparam SR_TIME64 = 40; // 6 regs (+0 to +5) - localparam SR_CLEAR_RX_FIFO = 48; // 1 reg - localparam SR_CLEAR_TX_FIFO = 49; // 1 reg - localparam SR_GLOBAL_RESET = 50; // 1 reg - localparam SR_REG_TEST32 = 52; // 1 reg - - wire [7:0] COMPAT_NUM = 8'd3; + localparam SR_RX_CTRL0 = 0; // 9 regs (+0 to +8) + localparam SR_RX_DSP0 = 10; // 4 regs (+0 to +3) + localparam SR_RX_CTRL1 = 16; // 9 regs (+0 to +8) + localparam SR_RX_DSP1 = 26; // 4 regs (+0 to +3) + localparam SR_TX_CTRL = 32; // 4 regs (+0 to +3) + localparam SR_TX_DSP = 38; // 3 regs (+0 to +2) + + localparam SR_TIME64 = 42; // 6 regs (+0 to +5) + localparam SR_RX_FRONT = 48; // 5 regs (+0 to +4) + localparam SR_TX_FRONT = 54; // 5 regs (+0 to +4) + + localparam SR_REG_TEST32 = 60; // 1 reg + localparam SR_CLEAR_RX_FIFO = 61; // 1 reg + localparam SR_CLEAR_TX_FIFO = 62; // 1 reg + localparam SR_GLOBAL_RESET = 63; // 1 reg + + wire [7:0] COMPAT_NUM = 8'd5; wire wb_clk = clk_fpga; wire wb_rst, global_reset; wire pps_int; wire [63:0] vita_time, vita_time_pps; - reg [15:0] reg_leds, reg_cgen_ctrl, reg_test, xfer_rate; + reg [15:0] reg_leds, reg_cgen_ctrl, reg_test; + wire [15:0] xfer_rate = 0; wire [7:0] test_rate; wire [3:0] test_ctrl; @@ -72,11 +78,11 @@ module u1plus_core wire [31:0] debug_vt; wire gpif_rst; - wire rx_overrun_dsp, rx_overrun_gpmc, tx_underrun_dsp, tx_underrun_gpmc; reg [7:0] frames_per_packet; - assign rx_overrun = rx_overrun_gpmc | rx_overrun_dsp; - assign tx_underrun = tx_underrun_gpmc | tx_underrun_dsp; + wire rx_overrun_dsp0, rx_overrun_dsp1, rx_overrun_gpif, tx_underrun_dsp, tx_underrun_gpif; + wire rx_overrun = rx_overrun_gpif | rx_overrun_dsp0 | rx_overrun_dsp1; + wire tx_underrun = tx_underrun_gpif | tx_underrun_dsp; setting_reg #(.my_addr(SR_GLOBAL_RESET), .width(1)) sr_reset (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), @@ -97,13 +103,12 @@ module u1plus_core wire [sw-1:0] m0_sel; wire m0_cyc, m0_stb, m0_we, m0_ack, m0_err, m0_rty; - wire [31:0] debug_gpmc; + wire [31:0] debug_gpif; wire [35:0] tx_data, rx_data, tx_err_data; wire tx_src_rdy, tx_dst_rdy, rx_src_rdy, rx_dst_rdy, tx_err_src_rdy, tx_err_dst_rdy; - wire bus_error; wire clear_tx, clear_rx; setting_reg #(.my_addr(SR_CLEAR_RX_FIFO), .width(1)) sr_clear_rx @@ -128,36 +133,83 @@ module u1plus_core .rx_data_i(rx_data), .rx_src_rdy_i(rx_src_rdy), .rx_dst_rdy_o(rx_dst_rdy), .tx_err_data_i(tx_err_data), .tx_err_src_rdy_i(tx_err_src_rdy), .tx_err_dst_rdy_o(tx_err_dst_rdy), - .tx_underrun(tx_underrun_gpmc), .rx_overrun(rx_overrun_gpmc), + .tx_underrun(tx_underrun_gpif), .rx_overrun(rx_overrun_gpif), .frames_per_packet(frames_per_packet), .test_len(test_len), .test_rate(test_rate), .test_ctrl(test_ctrl), .debug0(debug0), .debug1(debug1)); // ///////////////////////////////////////////////////////////////////////// - // DSP RX - wire [31:0] sample_rx; - wire strobe_rx, run_rx; - wire [31:0] debug_rx_dsp, vr_debug; + // RX ADC Frontend, does IQ Balance, DC Offset, muxing + + wire [23:0] adc_i, adc_q; // 24 bits is total overkill here, but it matches u2/u2p + wire run_rx, run_rx0, run_rx1; + + rx_frontend #(.BASE(SR_RX_FRONT)) rx_frontend + (.clk(wb_clk),.rst(wb_rst), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .adc_a({rx_i,4'b00}),.adc_ovf_a(0), + .adc_b({rx_q,4'b00}),.adc_ovf_b(0), + .i_out(adc_i), .q_out(adc_q), .run(run_rx0 | run_rx1), .debug()); + + // ///////////////////////////////////////////////////////////////////////// + // DSP RX 0 + + wire [31:0] sample_rx0; + wire strobe_rx0; + wire [35:0] vita_rx_data0; + wire vita_rx_src_rdy0, vita_rx_dst_rdy0; - dsp_core_rx #(.BASE(SR_RX_DSP)) dsp_core_rx + dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0 (.clk(wb_clk),.rst(wb_rst), .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), - .adc_a({rx_i,2'b0}),.adc_ovf_a(0),.adc_b({rx_q,2'b0}),.adc_ovf_b(0), - .sample(sample_rx), .run(run_rx), .strobe(strobe_rx), - .debug(debug_rx_dsp) ); + .adc_i(adc_i),.adc_ovf_i(0),.adc_q(adc_q),.adc_ovf_q(0), + .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0), + .debug() ); + + vita_rx_chain #(.BASE(SR_RX_CTRL0), .UNIT(0), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain0 + (.clk(wb_clk),.reset(wb_rst),.clear(clear_rx), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .vita_time(vita_time), .overrun(rx_overrun_dsp0), + .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0), + .rx_data_o(vita_rx_data0), .rx_dst_rdy_i(vita_rx_dst_rdy0), .rx_src_rdy_o(vita_rx_src_rdy0), + .debug() ); - vita_rx_chain #(.BASE(SR_RX_CTRL), .UNIT(0), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain + // ///////////////////////////////////////////////////////////////////////// + // DSP RX 1 + + wire [31:0] sample_rx1; + wire strobe_rx1; + wire [35:0] vita_rx_data1; + wire vita_rx_src_rdy1, vita_rx_dst_rdy1; + + dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1 + (.clk(wb_clk),.rst(wb_rst), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .adc_i(adc_i),.adc_ovf_i(0),.adc_q(adc_q),.adc_ovf_q(0), + .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1), + .debug() ); + + vita_rx_chain #(.BASE(SR_RX_CTRL1), .UNIT(1), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain1 (.clk(wb_clk),.reset(wb_rst),.clear(clear_rx), .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), - .vita_time(vita_time), .overrun(rx_overrun_dsp), - .sample(sample_rx), .run(run_rx), .strobe(strobe_rx), - .rx_data_o(rx_data), .rx_dst_rdy_i(rx_dst_rdy), .rx_src_rdy_o(rx_src_rdy), - .debug(vr_debug) ); + .vita_time(vita_time), .overrun(rx_overrun_dsp1), + .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1), + .rx_data_o(vita_rx_data1), .rx_dst_rdy_i(vita_rx_dst_rdy1), .rx_src_rdy_o(vita_rx_src_rdy1), + .debug() ); + + // ///////////////////////////////////////////////////////////////////////// + // RX Stream muxing + + fifo36_mux #(.prio(0)) mux_data_streams + (.clk(wb_clk), .reset(wb_rst), .clear(0), + .data0_i(vita_rx_data0), .src0_rdy_i(vita_rx_src_rdy0), .dst0_rdy_o(vita_rx_dst_rdy0), + .data1_i(vita_rx_data1), .src1_rdy_i(vita_rx_src_rdy1), .dst1_rdy_o(vita_rx_dst_rdy1), + .data_o(rx_data), .src_rdy_o(rx_src_rdy), .dst_rdy_i(rx_dst_rdy)); // /////////////////////////////////////////////////////////////////////////////////// // DSP TX - wire [15:0] tx_i_int, tx_q_int; + wire [23:0] tx_i_int, tx_q_int; wire run_tx; vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP), @@ -170,13 +222,16 @@ module u1plus_core .vita_time(vita_time), .tx_data_i(tx_data), .tx_src_rdy_i(tx_src_rdy), .tx_dst_rdy_o(tx_dst_rdy), .err_data_o(tx_err_data), .err_src_rdy_o(tx_err_src_rdy), .err_dst_rdy_i(tx_err_dst_rdy), - .dac_a(tx_i_int),.dac_b(tx_q_int), + .tx_i(tx_i_int),.tx_q(tx_q_int), .underrun(tx_underrun_dsp), .run(run_tx), .debug(debug_vt)); - - assign tx_i = tx_i_int[15:2]; - assign tx_q = tx_q_int[15:2]; - + + tx_frontend #(.BASE(SR_TX_FRONT), .WIDTH_OUT(14)) tx_frontend + (.clk(wb_clk), .rst(wb_rst), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .tx_i(tx_i_int), .tx_q(tx_q_int), .run(1'b1), + .dac_a(tx_i), .dac_b(tx_q)); + // ///////////////////////////////////////////////////////////////////////////////////// // Wishbone Intercon, single master wire [dw-1:0] s0_dat_mosi, s1_dat_mosi, s0_dat_miso, s1_dat_miso, s2_dat_mosi, s3_dat_mosi, s2_dat_miso, s3_dat_miso, @@ -263,7 +318,7 @@ module u1plus_core reg_leds <= 0; reg_cgen_ctrl <= 2'b11; reg_test <= 0; - xfer_rate <= 0; + //xfer_rate <= 0; frames_per_packet <= 0; end else @@ -277,8 +332,8 @@ module u1plus_core reg_test <= s0_dat_mosi; REG_RX_FRAMELEN : frames_per_packet <= s0_dat_mosi[7:0]; - REG_XFER_RATE : - xfer_rate <= s0_dat_mosi; + //REG_XFER_RATE : + //xfer_rate <= s0_dat_mosi; endcase // case (s0_adr[6:0]) assign test_ctrl = xfer_rate[11:8]; @@ -300,14 +355,16 @@ module u1plus_core // ///////////////////////////////////////////////////////////////////////////////////// // Slave 1, UART // depth of 3 is 128 entries, clkdiv of 278 gives 230.4k with a 64 MHz system clock - + +/* simple_uart #(.TXDEPTH(3),.RXDEPTH(3), .CLKDIV_DEFAULT(278)) uart (.clk_i(wb_clk),.rst_i(wb_rst), .we_i(s1_we),.stb_i(s1_stb),.cyc_i(s1_cyc),.ack_o(s1_ack), .adr_i(s1_adr[3:1]),.dat_i({16'd0,s1_dat_mosi}),.dat_o(s1_dat_miso), .rx_int_o(),.tx_int_o(), .tx_o(debug_txd),.rx_i(debug_rxd),.baud_o()); - +*/ + // ///////////////////////////////////////////////////////////////////////////////////// // Slave 2, SPI @@ -401,9 +458,8 @@ module u1plus_core // Debug circuitry assign debug_clk = { gpif_clk, clk_fpga }; - assign debug = debug0; + assign debug = 0; assign debug_gpio_0 = 0; assign debug_gpio_1 = 0; - //assign {io_tx,io_rx} = {debug1}; endmodule // u1plus_core diff --git a/fpga/usrp2/top/E1x0/Makefile.passthru b/fpga/usrp2/top/E1x0/Makefile.passthru deleted file mode 100644 index f2d835608..000000000 --- a/fpga/usrp2/top/E1x0/Makefile.passthru +++ /dev/null @@ -1,98 +0,0 @@ -# -# Copyright 2008 Ettus Research LLC -# - -################################################## -# Project Setup -################################################## -TOP_MODULE = passthru -BUILD_DIR = $(abspath build$(ISE)) - -################################################## -# Include other makefiles -################################################## - -include ../Makefile.common -include ../../fifo/Makefile.srcs -include ../../control_lib/Makefile.srcs -include ../../sdr_lib/Makefile.srcs -include ../../serdes/Makefile.srcs -include ../../simple_gemac/Makefile.srcs -include ../../timing/Makefile.srcs -include ../../opencores/Makefile.srcs -include ../../vrt/Makefile.srcs -include ../../udp/Makefile.srcs -include ../../coregen/Makefile.srcs -include ../../gpmc/Makefile.srcs - -################################################## -# Project Properties -################################################## -export PROJECT_PROPERTIES := \ -family "Spartan-3A DSP" \ -device xc3sd1800a \ -package cs484 \ -speed -4 \ -top_level_module_type "HDL" \ -synthesis_tool "XST (VHDL/Verilog)" \ -simulator "ISE Simulator (VHDL/Verilog)" \ -"Preferred Language" "Verilog" \ -"Enable Message Filtering" FALSE \ -"Display Incremental Messages" FALSE - -################################################## -# Sources -################################################## -TOP_SRCS = \ -passthru.v \ -passthru.ucf - -SOURCES = $(abspath $(TOP_SRCS)) $(FIFO_SRCS) \ -$(CONTROL_LIB_SRCS) $(SDR_LIB_SRCS) $(SERDES_SRCS) \ -$(SIMPLE_GEMAC_SRCS) $(TIMING_SRCS) $(OPENCORES_SRCS) \ -$(VRT_SRCS) $(UDP_SRCS) $(COREGEN_SRCS) \ -$(GPMC_SRCS) - -################################################## -# Process Properties -################################################## -SYNTHESIZE_PROPERTIES = \ -"Number of Clock Buffers" 8 \ -"Pack I/O Registers into IOBs" Yes \ -"Optimization Effort" High \ -"Optimize Instantiated Primitives" TRUE \ -"Register Balancing" Yes \ -"Use Clock Enable" Auto \ -"Use Synchronous Reset" Auto \ -"Use Synchronous Set" Auto - -TRANSLATE_PROPERTIES = \ -"Macro Search Path" "$(shell pwd)/../../coregen/" - -MAP_PROPERTIES = \ -"Allow Logic Optimization Across Hierarchy" TRUE \ -"Map to Input Functions" 4 \ -"Optimization Strategy (Cover Mode)" Speed \ -"Pack I/O Registers/Latches into IOBs" "For Inputs and Outputs" \ -"Perform Timing-Driven Packing and Placement" TRUE \ -"Map Effort Level" High \ -"Extra Effort" Normal \ -"Combinatorial Logic Optimization" TRUE \ -"Register Duplication" TRUE - -PLACE_ROUTE_PROPERTIES = \ -"Place & Route Effort Level (Overall)" High - -STATIC_TIMING_PROPERTIES = \ -"Number of Paths in Error/Verbose Report" 10 \ -"Report Type" "Error Report" - -GEN_PROG_FILE_PROPERTIES = \ -"Configuration Rate" 6 \ -"Create Binary Configuration File" TRUE \ -"Done (Output Events)" 5 \ -"Enable Bitstream Compression" TRUE \ -"Enable Outputs (Output Events)" 6 \ -"Unused IOB Pins" "Pull Up" - -SIM_MODEL_PROPERTIES = "" diff --git a/fpga/usrp2/top/E1x0/core_compile b/fpga/usrp2/top/E1x0/core_compile index dc0cd081e..02d7f006e 100755 --- a/fpga/usrp2/top/E1x0/core_compile +++ b/fpga/usrp2/top/E1x0/core_compile @@ -1,3 +1,3 @@ -iverilog -Wall -y. -y ../../control_lib/ -y ../../fifo/ -y ../../gpmc/ -y ../../models/ -y ../../sdr_lib/ -y ../../coregen/ -y ../../vrt/ -y ../../opencores/i2c/rtl/verilog/ -y ../../opencores/spi/rtl/verilog/ -y ../../timing/ -y ../../opencores/8b10b/ -I ../../opencores/spi/rtl/verilog/ -I ../../opencores/i2c/rtl/verilog/ -y ../../simple_gemac u1e_core.v 2>&1 | grep -v timescale | grep -v coregen | grep -v models +iverilog -Wall -y. -y ../../control_lib/ -y ../../fifo/ -y ../../gpmc/ -y ../../models/ -y ../../sdr_lib/ -y ../../coregen/ -y ../../vrt/ -y ../../opencores/i2c/rtl/verilog/ -y ../../opencores/spi/rtl/verilog/ -y ../../timing/ -y ../../opencores/8b10b/ -I ../../opencores/spi/rtl/verilog/ -I ../../opencores/i2c/rtl/verilog/ -y ../../simple_gemac -y $XILINX/verilog/src/unisims u1e_core.v 2>&1 | grep -v timescale | grep -v coregen | grep -v models diff --git a/fpga/usrp2/top/E1x0/passthru.ucf b/fpga/usrp2/top/E1x0/passthru.ucf deleted file mode 100644 index 64e6f0440..000000000 --- a/fpga/usrp2/top/E1x0/passthru.ucf +++ /dev/null @@ -1,6 +0,0 @@ -NET "overo_gpio145" LOC = "C7" ; -NET "cgen_mosi" LOC = "E22" ; -NET "cgen_sclk" LOC = "J19" ; -NET "cgen_sen_b" LOC = "H20" ; -NET "fpga_cfg_din" LOC = "W17" ; -NET "fpga_cfg_cclk" LOC = "V17" ; diff --git a/fpga/usrp2/top/E1x0/u1e.v b/fpga/usrp2/top/E1x0/u1e.v index adf42fd07..4f85b7d6e 100644 --- a/fpga/usrp2/top/E1x0/u1e.v +++ b/fpga/usrp2/top/E1x0/u1e.v @@ -36,11 +36,12 @@ module u1e output cgen_sclk, output cgen_sen_b, output cgen_mosi, input cgen_miso, // Clock gen SPI input cgen_st_status, input cgen_st_ld, input cgen_st_refmon, output cgen_sync_b, output cgen_ref_sel, + input overo_gpio65, input overo_gpio128, input overo_gpio145, output overo_gpio147, //aux SPI - output overo_gpio144, output overo_gpio145, output overo_gpio146, output overo_gpio147, // Fifo controls + output overo_gpio144, output overo_gpio146, // Fifo controls input overo_gpio0, input overo_gpio14, input overo_gpio21, input overo_gpio22, // Misc GPIO - input overo_gpio23, input overo_gpio64, input overo_gpio65, input overo_gpio127, // Misc GPIO - input overo_gpio128, input overo_gpio163, input overo_gpio170, input overo_gpio176, // Misc GPIO + input overo_gpio23, input overo_gpio64, input overo_gpio127, // Misc GPIO + input overo_gpio176, input overo_gpio163, input overo_gpio170, // Misc GPIO inout [15:0] io_tx, inout [15:0] io_rx, @@ -75,19 +76,29 @@ module u1e clk_doubler (.CLKFB(clk_fb), .CLKIN(clk_fpga_in), .RST(dcm_rst), .DSSEN(0), .PSCLK(0), .PSEN(0), .PSINCDEC(0), .PSDONE(), .CLKDV(), .CLKFX(), .CLKFX180(), - .CLK2X(), .CLK2X180(), + .CLK2X(clk_2x), .CLK2X180(), .CLK0(clk_fb), .CLK90(clk_fpga), .CLK180(), .CLK270(), .LOCKED(dcm_locked), .STATUS()); - + // ///////////////////////////////////////////////////////////////////////// // SPI wire mosi, sclk, miso; assign { db_sclk_tx, db_mosi_tx } = ~db_sen_tx ? {sclk,mosi} : 2'b0; assign { db_sclk_rx, db_mosi_rx } = ~db_sen_rx ? {sclk,mosi} : 2'b0; assign { sclk_codec, mosi_codec } = ~sen_codec ? {sclk,mosi} : 2'b0; - assign { cgen_sclk, cgen_mosi } = ~cgen_sen_b ? {sclk,mosi} : 2'b0; + //assign { cgen_sclk, cgen_mosi } = ~cgen_sen_b ? {sclk,mosi} : 2'b0; //replaced by aux spi assign miso = (~db_sen_tx & db_miso_tx) | (~db_sen_rx & db_miso_rx) | - (~sen_codec & miso_codec) | (~cgen_sen_b & cgen_miso); + (~sen_codec & miso_codec) | (~cgen_sen_b & cgen_miso); + + //assign the aux spi to the cgen (bypasses wishbone) + assign cgen_sclk = overo_gpio65; + assign cgen_sen_b = overo_gpio128; + assign cgen_mosi = overo_gpio145; + wire proc_int; //re-purpose gpio for interrupt when we are not using aux spi + assign overo_gpio147 = (cgen_sen_b == 1'b0)? cgen_miso : proc_int; + + wire _cgen_sen_b; + //assign cgen_sen_b = _cgen_sen_b; //replaced by aux spi // ///////////////////////////////////////////////////////////////////////// // TX DAC -- handle the interleaved data bus to DAC, with clock doubling DLL @@ -130,25 +141,22 @@ module u1e // ///////////////////////////////////////////////////////////////////////// // Main U1E Core - u1e_core u1e_core(.clk_fpga(clk_fpga), .rst_fpga(~debug_pb), + u1e_core u1e_core(.clk_fpga(clk_fpga), .bus_clk(clk_2x), .rst_fpga(~debug_pb), .debug_led(debug_led), .debug(debug), .debug_clk(debug_clk), .debug_txd(FPGA_TXD), .debug_rxd(FPGA_RXD), .EM_CLK(EM_CLK), .EM_D(EM_D), .EM_A(EM_A), .EM_NBE(EM_NBE), .EM_WAIT0(EM_WAIT0), .EM_NCS4(EM_NCS4), .EM_NCS5(EM_NCS5), .EM_NCS6(EM_NCS6), .EM_NWE(EM_NWE), .EM_NOE(EM_NOE), .db_sda(db_sda), .db_scl(db_scl), - .sclk(sclk), .sen({cgen_sen_b,sen_codec,db_sen_tx,db_sen_rx}), .mosi(mosi), .miso(miso), + .sclk(sclk), .sen({_cgen_sen_b,sen_codec,db_sen_tx,db_sen_rx}), .mosi(mosi), .miso(miso), .cgen_st_status(cgen_st_status), .cgen_st_ld(cgen_st_ld),.cgen_st_refmon(cgen_st_refmon), .cgen_sync_b(cgen_sync_b), .cgen_ref_sel(cgen_ref_sel), - .tx_have_space(overo_gpio144), .tx_underrun(overo_gpio145), - .rx_have_data(overo_gpio146), .rx_overrun(overo_gpio147), + .tx_have_space(overo_gpio144), + .rx_have_data(overo_gpio146), .io_tx(io_tx), .io_rx(io_rx), .tx_i(tx_i), .tx_q(tx_q), .rx_i(DA), .rx_q(DB), - .misc_gpio( {{overo_gpio128,overo_gpio163,overo_gpio170,overo_gpio176}, - {overo_gpio0,overo_gpio14,overo_gpio21,overo_gpio22}, - {overo_gpio23,overo_gpio64,overo_gpio65,overo_gpio127}}), - .pps_in(PPS_IN) ); + .pps_in(PPS_IN), .proc_int(proc_int) ); // ///////////////////////////////////////////////////////////////////////// // Local Debug diff --git a/fpga/usrp2/top/E1x0/u1e_core.v b/fpga/usrp2/top/E1x0/u1e_core.v index 4c513587b..d481867e3 100644 --- a/fpga/usrp2/top/E1x0/u1e_core.v +++ b/fpga/usrp2/top/E1x0/u1e_core.v @@ -18,7 +18,7 @@ module u1e_core - (input clk_fpga, input rst_fpga, + (input clk_fpga, input bus_clk, input rst_fpga, output [3:0] debug_led, output [31:0] debug, output [1:0] debug_clk, output debug_txd, input debug_rxd, @@ -31,29 +31,36 @@ module u1e_core output sclk, output [15:0] sen, output mosi, input miso, input cgen_st_status, input cgen_st_ld, input cgen_st_refmon, output cgen_sync_b, output cgen_ref_sel, - output tx_have_space, output tx_underrun, output rx_have_data, output rx_overrun, + output tx_have_space, output rx_have_data, inout [15:0] io_tx, inout [15:0] io_rx, output [13:0] tx_i, output [13:0] tx_q, input [11:0] rx_i, input [11:0] rx_q, - input [11:0] misc_gpio, input pps_in + input pps_in, output proc_int ); localparam TXFIFOSIZE = 13; localparam RXFIFOSIZE = 13; // 64 total regs in address space - localparam SR_RX_CTRL = 0; // 9 regs (+0 to +8) - localparam SR_RX_DSP = 16; // 7 regs (+0 to +6) - localparam SR_TX_CTRL = 24; // 6 regs (+0 to +5) - localparam SR_TX_DSP = 32; // 5 regs (+0 to +4) - localparam SR_TIME64 = 40; // 6 regs (+0 to +5) - localparam SR_CLEAR_RX_FIFO = 48; // 1 reg - localparam SR_CLEAR_TX_FIFO = 49; // 1 reg - localparam SR_GLOBAL_RESET = 50; // 1 reg - localparam SR_REG_TEST32 = 52; // 1 reg - - wire [7:0] COMPAT_NUM = 8'd4; + localparam SR_RX_CTRL0 = 0; // 9 regs (+0 to +8) + localparam SR_RX_DSP0 = 10; // 4 regs (+0 to +3) + localparam SR_RX_CTRL1 = 16; // 9 regs (+0 to +8) + localparam SR_RX_DSP1 = 26; // 4 regs (+0 to +3) + localparam SR_ERR_CTRL = 30; // 1 reg + localparam SR_TX_CTRL = 32; // 4 regs (+0 to +3) + localparam SR_TX_DSP = 38; // 3 regs (+0 to +2) + + localparam SR_TIME64 = 42; // 6 regs (+0 to +5) + localparam SR_RX_FRONT = 48; // 5 regs (+0 to +4) + localparam SR_TX_FRONT = 54; // 5 regs (+0 to +4) + + localparam SR_REG_TEST32 = 60; // 1 reg + localparam SR_CLEAR_RX_FIFO = 61; // 1 reg + localparam SR_CLEAR_TX_FIFO = 62; // 1 reg + localparam SR_GLOBAL_RESET = 63; // 1 reg + + wire [7:0] COMPAT_NUM = 8'd5; wire wb_clk = clk_fpga; wire wb_rst, global_reset; @@ -69,9 +76,9 @@ module u1e_core wire set_stb; wire [31:0] debug_vt; - wire rx_overrun_dsp, rx_overrun_gpmc, tx_underrun_dsp, tx_underrun_gpmc; - assign rx_overrun = rx_overrun_gpmc | rx_overrun_dsp; - assign tx_underrun = tx_underrun_gpmc | tx_underrun_dsp; + wire rx_overrun_dsp0, rx_overrun_dsp1, rx_overrun_gpmc, tx_underrun_dsp, tx_underrun_gpmc; + wire rx_overrun = rx_overrun_gpmc | rx_overrun_dsp0 | rx_overrun_dsp1; + wire tx_underrun = tx_underrun_gpmc | tx_underrun_dsp; setting_reg #(.my_addr(SR_GLOBAL_RESET), .width(1)) sr_reset (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), @@ -110,7 +117,7 @@ module u1e_core .in(set_data),.out(),.changed(clear_tx)); gpmc_async #(.TXFIFOSIZE(TXFIFOSIZE), .RXFIFOSIZE(RXFIFOSIZE)) - gpmc (.arst(wb_rst), + gpmc (.arst(wb_rst), .bus_clk(bus_clk), .EM_CLK(EM_CLK), .EM_D(EM_D), .EM_A(EM_A), .EM_NBE(EM_NBE), .EM_WAIT0(EM_WAIT0), .EM_NCS4(EM_NCS4), .EM_NCS6(EM_NCS6), .EM_NWE(EM_NWE), .EM_NOE(EM_NOE), @@ -133,44 +140,82 @@ module u1e_core .test_rate(test_rate), .test_ctrl(test_ctrl), .debug(debug_gpmc)); - wire rx_sof = rx_data[32]; - wire rx_eof = rx_data[33]; wire rx_src_rdy_int, rx_dst_rdy_int, tx_src_rdy_int, tx_dst_rdy_int; wire [31:0] debug_rx_dsp, vrc_debug, vrf_debug, vr_debug; // ///////////////////////////////////////////////////////////////////////// - // DSP RX - wire [31:0] sample_rx; - wire strobe_rx, run_rx; - wire [35:0] vita_rx_data; - wire vita_rx_src_rdy, vita_rx_dst_rdy; + // RX ADC Frontend, does IQ Balance, DC Offset, muxing + + wire [23:0] adc_i, adc_q; // 24 bits is total overkill here, but it matches u2/u2p + wire run_rx, run_rx0, run_rx1; - dsp_core_rx #(.BASE(SR_RX_DSP)) dsp_core_rx + rx_frontend #(.BASE(SR_RX_FRONT)) rx_frontend (.clk(wb_clk),.rst(wb_rst), .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), - .adc_a({rx_i,2'b0}),.adc_ovf_a(0),.adc_b({rx_q,2'b0}),.adc_ovf_b(0), - .sample(sample_rx), .run(run_rx), .strobe(strobe_rx), - .debug(debug_rx_dsp) ); + .adc_a({rx_i,4'b00}),.adc_ovf_a(0), + .adc_b({rx_q,4'b00}),.adc_ovf_b(0), + .i_out(adc_i), .q_out(adc_q), .run(run_rx0 | run_rx1), .debug()); + + // ///////////////////////////////////////////////////////////////////////// + // DSP RX 0 - vita_rx_chain #(.BASE(SR_RX_CTRL), .UNIT(0), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain + wire [31:0] sample_rx0; + wire strobe_rx0; + wire [35:0] vita_rx_data0; + wire vita_rx_src_rdy0, vita_rx_dst_rdy0; + + dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0 + (.clk(wb_clk),.rst(wb_rst), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .adc_i(adc_i),.adc_ovf_i(0),.adc_q(adc_q),.adc_ovf_q(0), + .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0), + .debug() ); + + vita_rx_chain #(.BASE(SR_RX_CTRL0), .UNIT(0), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain0 (.clk(wb_clk),.reset(wb_rst),.clear(clear_rx), .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), - .vita_time(vita_time), .overrun(rx_overrun_dsp), - .sample(sample_rx), .run(run_rx), .strobe(strobe_rx), - .rx_data_o(vita_rx_data), .rx_dst_rdy_i(vita_rx_dst_rdy), .rx_src_rdy_o(vita_rx_src_rdy), - .debug(vr_debug) ); + .vita_time(vita_time), .overrun(rx_overrun_dsp0), + .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0), + .rx_data_o(vita_rx_data0), .rx_dst_rdy_i(vita_rx_dst_rdy0), .rx_src_rdy_o(vita_rx_src_rdy0), + .debug() ); - fifo36_mux #(.prio(0)) mux_err_stream + // ///////////////////////////////////////////////////////////////////////// + // DSP RX 1 + + wire [31:0] sample_rx1; + wire strobe_rx1; + wire [35:0] vita_rx_data1; + wire vita_rx_src_rdy1, vita_rx_dst_rdy1; + + dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1 + (.clk(wb_clk),.rst(wb_rst), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .adc_i(adc_i),.adc_ovf_i(0),.adc_q(adc_q),.adc_ovf_q(0), + .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1), + .debug() ); + + vita_rx_chain #(.BASE(SR_RX_CTRL1), .UNIT(1), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain1 + (.clk(wb_clk),.reset(wb_rst),.clear(clear_rx), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .vita_time(vita_time), .overrun(rx_overrun_dsp1), + .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1), + .rx_data_o(vita_rx_data1), .rx_dst_rdy_i(vita_rx_dst_rdy1), .rx_src_rdy_o(vita_rx_src_rdy1), + .debug() ); + + // ///////////////////////////////////////////////////////////////////////// + // RX Stream muxing + + fifo36_mux #(.prio(0)) mux_data_streams (.clk(wb_clk), .reset(wb_rst), .clear(0), - .data0_i(vita_rx_data), .src0_rdy_i(vita_rx_src_rdy), .dst0_rdy_o(vita_rx_dst_rdy), - .data1_i(tx_err_data), .src1_rdy_i(tx_err_src_rdy), .dst1_rdy_o(tx_err_dst_rdy), + .data0_i(vita_rx_data0), .src0_rdy_i(vita_rx_src_rdy0), .dst0_rdy_o(vita_rx_dst_rdy0), + .data1_i(vita_rx_data1), .src1_rdy_i(vita_rx_src_rdy1), .dst1_rdy_o(vita_rx_dst_rdy1), .data_o(rx_data), .src_rdy_o(rx_src_rdy), .dst_rdy_i(rx_dst_rdy)); - + // /////////////////////////////////////////////////////////////////////////////////// // DSP TX - wire [15:0] tx_i_int, tx_q_int; + wire [23:0] tx_i_int, tx_q_int; wire run_tx; vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP), @@ -183,13 +228,16 @@ module u1e_core .vita_time(vita_time), .tx_data_i(tx_data), .tx_src_rdy_i(tx_src_rdy), .tx_dst_rdy_o(tx_dst_rdy), .err_data_o(tx_err_data), .err_src_rdy_o(tx_err_src_rdy), .err_dst_rdy_i(tx_err_dst_rdy), - .dac_a(tx_i_int),.dac_b(tx_q_int), + .tx_i(tx_i_int),.tx_q(tx_q_int), .underrun(tx_underrun_dsp), .run(run_tx), .debug(debug_vt)); - - assign tx_i = tx_i_int[15:2]; - assign tx_q = tx_q_int[15:2]; - + + tx_frontend #(.BASE(SR_TX_FRONT), .WIDTH_OUT(14)) tx_frontend + (.clk(wb_clk), .rst(wb_rst), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .tx_i(tx_i_int), .tx_q(tx_q_int), .run(1'b1), + .dac_a(tx_i), .dac_b(tx_q)); + // ///////////////////////////////////////////////////////////////////////////////////// // Wishbone Intercon, single master wire [dw-1:0] s0_dat_mosi, s1_dat_mosi, s0_dat_miso, s1_dat_miso, s2_dat_mosi, s3_dat_mosi, s2_dat_miso, s3_dat_miso, @@ -255,7 +303,7 @@ module u1e_core .sf_dat_o(sf_dat_mosi),.sf_adr_o(sf_adr),.sf_sel_o(sf_sel),.sf_we_o(sf_we),.sf_cyc_o(sf_cyc),.sf_stb_o(sf_stb), .sf_dat_i(sf_dat_miso),.sf_ack_i(sf_ack),.sf_err_i(0),.sf_rty_i(0) ); - assign s5_ack = 0; assign s9_ack = 0; assign sa_ack = 0; assign sb_ack = 0; + assign s9_ack = 0; assign sa_ack = 0; assign sb_ack = 0; assign sc_ack = 0; assign sd_ack = 0; assign se_ack = 0; assign sf_ack = 0; // ///////////////////////////////////////////////////////////////////////////////////// @@ -336,7 +384,7 @@ module u1e_core wire scl_pad_i, scl_pad_o, scl_pad_oen_o, sda_pad_i, sda_pad_o, sda_pad_oen_o; i2c_master_top #(.ARST_LVL(1)) i2c (.wb_clk_i(wb_clk),.wb_rst_i(wb_rst),.arst_i(1'b0), - .wb_adr_i(s3_adr[4:2]),.wb_dat_i(s3_dat_mosi[7:0]),.wb_dat_o(s3_dat_miso[7:0]), + .wb_adr_i(s3_adr[3:1]),.wb_dat_i(s3_dat_mosi[7:0]),.wb_dat_o(s3_dat_miso[7:0]), .wb_we_i(s3_we),.wb_stb_i(s3_stb),.wb_cyc_i(s3_cyc), .wb_ack_o(s3_ack),.wb_inta_o(), .scl_pad_i(scl_pad_i),.scl_pad_o(scl_pad_o),.scl_padoen_o(scl_pad_oen_o), @@ -361,6 +409,43 @@ module u1e_core .atr(atr_lines),.debug_0(debug_gpio_0),.debug_1(debug_gpio_1), .gpio( {io_tx,io_rx} ) ); + //////////////////////////////////////////////////////////////////////////// + // FIFO to WB slave for async messages - Slave #5 + + //signals between fifo and buffer module + wire [35:0] _tx_err_data; + wire _tx_err_src_rdy, _tx_err_dst_rdy; + + fifo_cascade #(.WIDTH(36), .SIZE(9/*512 lines plenty for short pkts*/)) err_fifo( + .clk(wb_clk), .reset(wb_rst), .clear(wb_rst), + .datain(tx_err_data), .src_rdy_i(tx_err_src_rdy), .dst_rdy_o(tx_err_dst_rdy), + .dataout(_tx_err_data), .src_rdy_o(_tx_err_src_rdy), .dst_rdy_i(_tx_err_dst_rdy) + ); + + wire [31:0] err_status, err_data32; + //the buffer is 32 bits, but the data is 16, so mux based on the addr bit + assign s5_dat_miso = (s5_adr[1] == 1'b0)? err_data32[15:0] : err_data32[31:16]; + + buffer_int2 #(.BASE(SR_ERR_CTRL), .BUF_SIZE(5)) fifo_to_wb( + .clk(wb_clk), .rst(wb_rst), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .status(err_status), + // Wishbone interface to RAM + .wb_clk_i(wb_clk), .wb_rst_i(wb_rst), + .wb_we_i(s5_we), .wb_stb_i(s5_stb), + .wb_adr_i(s5_adr), .wb_dat_i({16'b0, s5_dat_mosi}), + .wb_dat_o(err_data32), .wb_ack_o(s5_ack), + // Write FIFO Interface + .wr_data_i(_tx_err_data), .wr_ready_i(_tx_err_src_rdy), .wr_ready_o(_tx_err_dst_rdy), + // Read FIFO Interface + .rd_data_o(), .rd_ready_o(), .rd_ready_i(1'b0) + ); + + //////////////////////////////////////////////////////////////////////////// + // Interrupts + + assign proc_int = (|err_status[1:0]); + // ///////////////////////////////////////////////////////////////////////// // Settings Bus -- Slave #8 + 9 @@ -369,7 +454,7 @@ module u1e_core (.wb_clk(wb_clk),.wb_rst(wb_rst),.wb_adr_i(s8_adr),.wb_dat_i(s8_dat_mosi), .wb_stb_i(s8_stb),.wb_we_i(s8_we),.wb_ack_o(s8_ack), .strobe(set_stb),.addr(set_addr),.data(set_data) ); - + // ///////////////////////////////////////////////////////////////////////// // ATR Controller -- Slave #6 @@ -384,8 +469,9 @@ module u1e_core wire [31:0] reg_test32; + //this setting reg is persistent across resets, to check for fpga loaded setting_reg #(.my_addr(SR_REG_TEST32)) sr_reg_test32 - (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), + (.clk(wb_clk),.rst(/*wb_rst*/1'b0),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(reg_test32),.changed()); wb_readback_mux_16LE readback_mux_32 @@ -394,7 +480,7 @@ module u1e_core .word00(vita_time[63:32]), .word01(vita_time[31:0]), .word02(vita_time_pps[63:32]), .word03(vita_time_pps[31:0]), - .word04(reg_test32), .word05(32'b0), + .word04(reg_test32), .word05(err_status), .word06(32'b0), .word07(32'b0), .word08(32'b0), .word09(32'b0), .word10(32'b0), .word11(32'b0), @@ -423,7 +509,7 @@ module u1e_core */ assign debug = debug_gpmc; - assign debug_gpio_0 = { {run_tx, 1'b0, run_rx, strobe_rx, tx_i[11:0]}, + assign debug_gpio_0 = { {run_tx, 1'b0, run_rx, strobe_rx0, tx_i[11:0]}, {2'b00, tx_src_rdy, tx_dst_rdy, tx_q[11:0]} }; assign debug_gpio_1 = debug_vt; @@ -431,7 +517,7 @@ module u1e_core /* assign debug_gpio_1 = { {rx_enable, rx_src_rdy, rx_dst_rdy, rx_src_rdy & ~rx_dst_rdy}, {tx_enable, tx_src_rdy, tx_dst_rdy, tx_dst_rdy & ~tx_src_rdy}, - {rx_sof, rx_eof, rx_src_rdy, rx_dst_rdy, rx_data[33:32],2'b0}, + {2'b0, rx_src_rdy, rx_dst_rdy, rx_data[33:32],2'b0}, {2'b0, bus_error, debug_gpmc[4:0] }, {misc_gpio[7:0]} }; */ diff --git a/fpga/usrp2/top/N2x0/u2plus_core.v b/fpga/usrp2/top/N2x0/u2plus_core.v index 8a7c6ddee..e2142ad06 100644 --- a/fpga/usrp2/top/N2x0/u2plus_core.v +++ b/fpga/usrp2/top/N2x0/u2plus_core.v @@ -428,7 +428,7 @@ module u2plus_core // Buffer Pool Status -- Slave #5 //compatibility number -> increment when the fpga has been sufficiently altered - localparam compat_num = 32'd6; + localparam compat_num = {16'd7, 16'd0}; //major, minor wb_readback_mux buff_pool_status (.wb_clk_i(wb_clk), .wb_rst_i(wb_rst), .wb_stb_i(s5_stb), @@ -584,6 +584,17 @@ module u2plus_core .sclk_pad_o(spiflash_clk),.mosi_pad_o(spiflash_mosi),.miso_pad_i(spiflash_miso) ); // ///////////////////////////////////////////////////////////////////////// + // ADC Frontend + wire [23:0] adc_i, adc_q; + + rx_frontend #(.BASE(SR_RX_FRONT)) rx_frontend + (.clk(dsp_clk),.rst(dsp_rst), + .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), + .adc_a({adc_a,2'b00}),.adc_ovf_a(adc_ovf_a), + .adc_b({adc_b,2'b00}),.adc_ovf_b(adc_ovf_b), + .i_out(adc_i), .q_out(adc_q), .run(run_rx0_d1 | run_rx1_d1), .debug()); + + // ///////////////////////////////////////////////////////////////////////// // DSP RX 0 wire [31:0] sample_rx0; wire clear_rx0, strobe_rx0; @@ -594,7 +605,7 @@ module u2plus_core dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0 (.clk(dsp_clk),.rst(dsp_rst), .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), - .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b), + .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b), .sample(sample_rx0), .run(run_rx0_d1), .strobe(strobe_rx0), .debug() ); @@ -622,7 +633,7 @@ module u2plus_core dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1 (.clk(dsp_clk),.rst(dsp_rst), .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), - .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b), + .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b), .sample(sample_rx1), .run(run_rx1_d1), .strobe(strobe_rx1), .debug() ); @@ -676,6 +687,8 @@ module u2plus_core .debug(debug_extfifo), .debug2(debug_extfifo2) ); + wire [23:0] tx_i, tx_q; + vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP), .REPORT_ERROR(1), .DO_FLOW_CONTROL(1), .PROT_ENG_FLAGS(1), .USE_TRANS_HEADER(1), @@ -686,10 +699,16 @@ module u2plus_core .vita_time(vita_time), .tx_data_i(tx_data), .tx_src_rdy_i(tx_src_rdy), .tx_dst_rdy_o(tx_dst_rdy), .err_data_o(tx_err_data), .err_src_rdy_o(tx_err_src_rdy), .err_dst_rdy_i(tx_err_dst_rdy), - .dac_a(dac_a),.dac_b(dac_b), + .tx_i(tx_i),.tx_q(tx_q), .underrun(underrun), .run(run_tx), .debug(debug_vt)); - + + tx_frontend #(.BASE(SR_TX_FRONT)) tx_frontend + (.clk(dsp_clk), .rst(dsp_rst), + .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), + .tx_i(tx_i), .tx_q(tx_q), .run(1'b1), + .dac_a(dac_a), .dac_b(dac_b)); + // /////////////////////////////////////////////////////////////////////////////////// // SERDES diff --git a/fpga/usrp2/top/USRP2/u2_core.v b/fpga/usrp2/top/USRP2/u2_core.v index ca9762ac5..2e3d41731 100644 --- a/fpga/usrp2/top/USRP2/u2_core.v +++ b/fpga/usrp2/top/USRP2/u2_core.v @@ -283,7 +283,7 @@ module u2_core .sf_dat_o(sf_dat_o),.sf_adr_o(sf_adr),.sf_sel_o(sf_sel),.sf_we_o(sf_we),.sf_cyc_o(sf_cyc),.sf_stb_o(sf_stb), .sf_dat_i(sf_dat_i),.sf_ack_i(sf_ack),.sf_err_i(0),.sf_rty_i(0)); - ////////////////////////////////////////////////////////////////////////////////////////// + // //////////////////////////////////////////////////////////////////////////////////////// // Reset Controller system_control sysctrl (.wb_clk_i(wb_clk), // .por_i(por), .ram_loader_rst_o(ram_loader_rst), @@ -433,7 +433,7 @@ module u2_core // Buffer Pool Status -- Slave #5 //compatibility number -> increment when the fpga has been sufficiently altered - localparam compat_num = 32'd6; + localparam compat_num = {16'd7, 16'd0}; //major, minor wb_readback_mux buff_pool_status (.wb_clk_i(wb_clk), .wb_rst_i(wb_rst), .wb_stb_i(s5_stb), @@ -583,6 +583,17 @@ module u2_core assign sd_dat_i[31:8] = 0; // ///////////////////////////////////////////////////////////////////////// + // ADC Frontend + wire [23:0] adc_i, adc_q; + + rx_frontend #(.BASE(SR_RX_FRONT)) rx_frontend + (.clk(dsp_clk),.rst(dsp_rst), + .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), + .adc_a({adc_a,2'b00}),.adc_ovf_a(adc_ovf_a), + .adc_b({adc_b,2'b00}),.adc_ovf_b(adc_ovf_b), + .i_out(adc_i), .q_out(adc_q), .run(run_rx0_d1 | run_rx1_d1), .debug()); + + // ///////////////////////////////////////////////////////////////////////// // DSP RX 0 wire [31:0] sample_rx0; wire clear_rx0, strobe_rx0; @@ -593,7 +604,7 @@ module u2_core dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0 (.clk(dsp_clk),.rst(dsp_rst), .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), - .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b), + .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b), .sample(sample_rx0), .run(run_rx0_d1), .strobe(strobe_rx0), .debug() ); @@ -621,7 +632,7 @@ module u2_core dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1 (.clk(dsp_clk),.rst(dsp_rst), .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), - .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b), + .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b), .sample(sample_rx1), .run(run_rx1_d1), .strobe(strobe_rx1), .debug() ); @@ -673,6 +684,8 @@ module u2_core .debug(debug_extfifo), .debug2(debug_extfifo2) ); + wire [23:0] tx_i, tx_q; + vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP), .REPORT_ERROR(1), .DO_FLOW_CONTROL(1), .PROT_ENG_FLAGS(1), .USE_TRANS_HEADER(1), @@ -683,10 +696,16 @@ module u2_core .vita_time(vita_time), .tx_data_i(tx_data), .tx_src_rdy_i(tx_src_rdy), .tx_dst_rdy_o(tx_dst_rdy), .err_data_o(tx_err_data), .err_src_rdy_o(tx_err_src_rdy), .err_dst_rdy_i(tx_err_dst_rdy), - .dac_a(dac_a),.dac_b(dac_b), + .tx_i(tx_i),.tx_q(tx_q), .underrun(underrun), .run(run_tx), .debug(debug_vt)); - + + tx_frontend #(.BASE(SR_TX_FRONT)) tx_frontend + (.clk(dsp_clk), .rst(dsp_rst), + .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), + .tx_i(tx_i), .tx_q(tx_q), .run(1'b1), + .dac_a(dac_a), .dac_b(dac_b)); + // /////////////////////////////////////////////////////////////////////////////////// // SERDES diff --git a/fpga/usrp2/vrt/vita_tx_chain.v b/fpga/usrp2/vrt/vita_tx_chain.v index 542968afa..ac9f08fc8 100644 --- a/fpga/usrp2/vrt/vita_tx_chain.v +++ b/fpga/usrp2/vrt/vita_tx_chain.v @@ -29,7 +29,7 @@ module vita_tx_chain input [63:0] vita_time, input [35:0] tx_data_i, input tx_src_rdy_i, output tx_dst_rdy_o, output [35:0] err_data_o, output err_src_rdy_o, input err_dst_rdy_i, - output [15:0] dac_a, output [15:0] dac_b, + output [23:0] tx_i, output [23:0] tx_q, output underrun, output run, output [31:0] debug); @@ -84,7 +84,7 @@ module vita_tx_chain (.clk(clk),.rst(reset), .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), .sample(sample_tx), .run(run), .strobe(strobe_tx), - .dac_a(dac_a),.dac_b(dac_b), + .tx_i(tx_i),.tx_q(tx_q), .debug(debug_tx_dsp) ); wire [35:0] flow_data, err_data_int; diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index b5f8e57c2..12c1cc179 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -26,7 +26,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(UHD CXX) ENABLE_TESTING() -LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/Modules) +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) INCLUDE(UHDComponent) #enable components INCLUDE(UHDPackage) #setup cpack @@ -81,7 +81,7 @@ IF(CMAKE_COMPILER_IS_GNUCXX) ENDIF(CMAKE_COMPILER_IS_GNUCXX) IF(MSVC) - INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/msvc) + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/cmake/msvc) ADD_DEFINITIONS( #stop all kinds of compatibility warnings -D_SCL_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_DEPRECATE @@ -160,7 +160,7 @@ PYTHON_CHECK_MODULE( # Create Uninstall Target ######################################################################## CONFIGURE_FILE( - ${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in + ${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake @ONLY) diff --git a/host/apps/omap_debug/usrp_e.h b/host/apps/omap_debug/usrp_e.h index 4c6a5dd89..2c4aa2ac1 100644 --- a/host/apps/omap_debug/usrp_e.h +++ b/host/apps/omap_debug/usrp_e.h @@ -28,46 +28,15 @@ struct usrp_e_ctl32 { __u32 buf[10]; }; -/* SPI interface */ - -#define UE_SPI_TXONLY 0 -#define UE_SPI_TXRX 1 - -/* Defines for spi ctrl register */ -#define UE_SPI_CTRL_TXNEG (1<<10) -#define UE_SPI_CTRL_RXNEG (1<<9) - -#define UE_SPI_PUSH_RISE 0 -#define UE_SPI_PUSH_FALL UE_SPI_CTRL_TXNEG -#define UE_SPI_LATCH_RISE 0 -#define UE_SPI_LATCH_FALL UE_SPI_CTRL_RXNEG - -struct usrp_e_spi { - __u8 readback; - __u32 slave; - __u32 data; - __u32 length; - __u32 flags; -}; - -struct usrp_e_i2c { - __u8 addr; - __u32 len; - __u8 data[]; -}; - #define USRP_E_IOC_MAGIC 'u' #define USRP_E_WRITE_CTL16 _IOW(USRP_E_IOC_MAGIC, 0x20, struct usrp_e_ctl16) #define USRP_E_READ_CTL16 _IOWR(USRP_E_IOC_MAGIC, 0x21, struct usrp_e_ctl16) #define USRP_E_WRITE_CTL32 _IOW(USRP_E_IOC_MAGIC, 0x22, struct usrp_e_ctl32) #define USRP_E_READ_CTL32 _IOWR(USRP_E_IOC_MAGIC, 0x23, struct usrp_e_ctl32) -#define USRP_E_SPI _IOWR(USRP_E_IOC_MAGIC, 0x24, struct usrp_e_spi) -#define USRP_E_I2C_READ _IOWR(USRP_E_IOC_MAGIC, 0x25, struct usrp_e_i2c) -#define USRP_E_I2C_WRITE _IOW(USRP_E_IOC_MAGIC, 0x26, struct usrp_e_i2c) #define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t) #define USRP_E_GET_COMPAT_NUMBER _IO(USRP_E_IOC_MAGIC, 0x28) -#define USRP_E_COMPAT_NUMBER 1 +#define USRP_E_COMPAT_NUMBER 2 /* Flag defines */ #define RB_USER (1<<0) diff --git a/host/Modules/FindDocutils.cmake b/host/cmake/Modules/FindDocutils.cmake index 3a97d8643..3a97d8643 100644 --- a/host/Modules/FindDocutils.cmake +++ b/host/cmake/Modules/FindDocutils.cmake diff --git a/host/Modules/FindGit.cmake b/host/cmake/Modules/FindGit.cmake index 2d8214287..2d8214287 100644 --- a/host/Modules/FindGit.cmake +++ b/host/cmake/Modules/FindGit.cmake diff --git a/host/Modules/FindUSB1.cmake b/host/cmake/Modules/FindUSB1.cmake index efb2e288b..efb2e288b 100644 --- a/host/Modules/FindUSB1.cmake +++ b/host/cmake/Modules/FindUSB1.cmake diff --git a/host/Modules/UHDComponent.cmake b/host/cmake/Modules/UHDComponent.cmake index 52b7450d5..52b7450d5 100644 --- a/host/Modules/UHDComponent.cmake +++ b/host/cmake/Modules/UHDComponent.cmake diff --git a/host/Modules/UHDPackage.cmake b/host/cmake/Modules/UHDPackage.cmake index e36793d73..e36793d73 100644 --- a/host/Modules/UHDPackage.cmake +++ b/host/cmake/Modules/UHDPackage.cmake diff --git a/host/Modules/UHDPython.cmake b/host/cmake/Modules/UHDPython.cmake index fdcdccb4b..fdcdccb4b 100644 --- a/host/Modules/UHDPython.cmake +++ b/host/cmake/Modules/UHDPython.cmake diff --git a/host/Modules/UHDVersion.cmake b/host/cmake/Modules/UHDVersion.cmake index f5364941c..ba736d2fc 100644 --- a/host/Modules/UHDVersion.cmake +++ b/host/cmake/Modules/UHDVersion.cmake @@ -26,8 +26,8 @@ FIND_PACKAGE(Git QUIET) # - increment patch on for bug fixes and docs ######################################################################## SET(UHD_VERSION_MAJOR 003) -SET(UHD_VERSION_MINOR 001) -SET(UHD_VERSION_PATCH 002) +SET(UHD_VERSION_MINOR 002) +SET(UHD_VERSION_PATCH 000) ######################################################################## # Version information discovery through git log diff --git a/host/cmake_uninstall.cmake.in b/host/cmake/cmake_uninstall.cmake.in index 6031a6ca9..6031a6ca9 100644 --- a/host/cmake_uninstall.cmake.in +++ b/host/cmake/cmake_uninstall.cmake.in diff --git a/host/msvc/inttypes.h b/host/cmake/msvc/inttypes.h index 1c2baa82e..1c2baa82e 100644 --- a/host/msvc/inttypes.h +++ b/host/cmake/msvc/inttypes.h diff --git a/host/msvc/stdint.h b/host/cmake/msvc/stdint.h index 15333b467..15333b467 100644 --- a/host/msvc/stdint.h +++ b/host/cmake/msvc/stdint.h diff --git a/host/docs/images.rst b/host/docs/images.rst index adfa6d530..c0645a821 100644 --- a/host/docs/images.rst +++ b/host/docs/images.rst @@ -14,6 +14,7 @@ The methods of loading images into the device varies among devices: * **USRP2:** The user must manually write the images onto the USRP2 SD card. * **USRP-N Series:** The user must manually transfer the images over ethernet. * **USRP-E Series:** The host code will automatically load the FPGA at runtime. +* **USRP-B Series:** The host code will automatically load the FPGA at runtime. ------------------------------------------------------------------------ Pre-built images diff --git a/host/docs/usrp1.rst b/host/docs/usrp1.rst index 97a8c3bb5..71b4f6779 100644 --- a/host/docs/usrp1.rst +++ b/host/docs/usrp1.rst @@ -34,24 +34,16 @@ Example device address string representations to specify non-standard firmware a Specifying the subdevice to use ------------------------------------------------------------------------ The USRP1 has multiple daughterboard slots, known as slot A and slot B. -The subdevice specification can be used to select -the daughterboard and subdevice for each channel. -For daughterboards with one one subdevice, -the subdevice name may be left blank for automatic selection. +The subdevice specification can be used to map an RF frontend to a DSP. +An RF frontend is identified by the daughterboard slot name and subdevice name. Ex: The subdev spec markup string to select a WBX on slot B. -Notice the use of the blank subdevice name for automatic selection. :: - B: - - -- OR -- - B:0 Ex: The subdev spec markup string to select a BasicRX on slot B. -Notice that the subdevice name is always specified in the 3 possible cases. :: @@ -82,6 +74,10 @@ List of emulated features * Receiving at a specific time * Receiving a specific number of samples * End of burst flags for transmit/receive +* Notification on late stream command +* Notification on late transmit packet +* Notification on underflow or overflow +* Notification on broken chain error **Note:** These emulated features rely on the host system's clock for timed operations, @@ -90,10 +86,6 @@ and therefore may not have sufficient precision for the application. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ List of missing features ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* Notification on late stream command -* Notification on late transmit packet -* Notification on broken chain error -* Notification on underflow or overflow * Start of burst flags for transmit/receive ------------------------------------------------------------------------ diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 1b07834fb..025cdd198 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -246,60 +246,42 @@ Using the MIMO Cable ------------------------------------------------------------------------ The MIMO cable allows two USRP devices to share reference clocks, time synchronization, and the ethernet interface. +One of the devices will sink its clock and time references to the MIMO cable. +This device will be referred to as the slave, and the other device, the master. + +* The slave device acquires the clock and time references from the master device. +* The master and slave may be used individually or in a multi-device configuration. +* External clocking is optional, and should only be supplied to the master device. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Shared ethernet mode ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In shared ethernet mode, only one device in the configuration can be attached to the ethernet. -This device will be referred to as the master, and the other device, the slave. -* The master provides reference clock and time synchronization to the slave. -* All data passing between the host and the slave is routed over the MIMO cable. +* Clock reference, time reference, and data are communicated over the MIMO cable. * Both master and slave must have different IPv4 addresses in the same subnet. -* The master and slave may be used individually or in a multi-device configuration. -* External clocking is optional, and should only be supplied to the master device. -* The role of slave and master may be switched with the "mimo_mode" device address (see dual ethernet mode). - -Example device address string representation for 2 USRP2s with IPv4 addresses 192.168.10.2 (master) and 192.168.10.3 (slave) -:: - - -- Multi-device example -- - - addr0=192.168.10.2, addr1=192.168.10.3 - - -- Two single devices example -- - - addr=192.168.10.2 - - addr=192.168.10.3 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Dual ethernet mode ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In dual ethernet mode, both devices in the configuration must be attached to the ethernet. -One of the devices in the configuration will be configured to provide synchronization. -This device will be referred to as the master, and the other device, the slave. -* The master provides reference clock and time synchronization to the slave. -* The devices require the special device address argument "mimo_mode" set. +* Only clock reference and time reference are communicated over the MIMO cable. * Both master and slave must have different IPv4 addresses in different subnets. -* The master and slave may be used individually or in a multi-device configuration. -* External clocking is optional, and should only be supplied to the master device. -Example device address string representation for 2 USRP2s with IPv4 addresses 192.168.10.2 (master) and 192.168.20.2 (slave) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Configuring the slave +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +In order for the slave to synchronize to the master over MIMO cable, +the following clock configuration must be set on the slave device: :: - -- Multi-device example -- - - addr0=192.168.10.2, mimo_mode0=master, addr1=192.168.20.2, mimo_mode1=slave - - -- Two single devices example -- - - addr=192.168.10.2, mimo_mode=master - - addr=192.168.20.2, mimo_mode=slave + uhd::clock_config_t clock_config; + clock_config.ref_source = uhd::clock_config_t::REF_MIMO; + clock_config.pps_source = uhd::clock_config_t::PPS_MIMO; + usrp->set_clock_config(clock_config, slave_index); ------------------------------------------------------------------------ Hardware setup notes @@ -406,11 +388,11 @@ In the single channel case, only one chain is ever used. To receive from both channels, the user must set the RX subdevice specification. This hardware has only one daughterboard slot, -which has been aptly named slot "0". +which has been aptly named slot "A". In the following example, a TVRX2 is installed. Channel 0 is sourced from subdevice RX1, channel 1 is sourced from subdevice RX2: :: - usrp->set_rx_subdev_spec("0:RX1 0:RX2"); + usrp->set_rx_subdev_spec("A:RX1 A:RX2"); diff --git a/host/docs/usrp_e1xx.rst b/host/docs/usrp_e1xx.rst index fcaa57716..4ac9d133a 100644 --- a/host/docs/usrp_e1xx.rst +++ b/host/docs/usrp_e1xx.rst @@ -53,21 +53,6 @@ Example: uhd_usrp_probe --args="master_clock_rate=52e6" -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Clock rate recovery - unbricking -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -It is possible to set a clock rate such that the UHD can no longer communicate with the FPGA. -When this occurs, it is necessary to use the usrp-e-utility to recover the clock generator. -The recovery utility works by loading a special pass-through FPGA image so the computer -can talk directly to the clock generator over a SPI interface. - -Run the following commands to restore the clock generator to a usable state: -:: - - cd <install-path>/share/uhd/usrp_e_utilities - ./usrp-e-utility --fpga=../images/usrp_e100_pt_fpga.bin --reclk - - ------------------------------------------------------------------------ Clock Synchronization ------------------------------------------------------------------------ diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 10d1fddc3..bad7b72a6 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -24,7 +24,7 @@ SET(example_sources rx_samples_to_file.cpp rx_samples_to_udp.cpp rx_timed_samples.cpp - test_async_messages.cpp + test_messages.cpp test_pps_input.cpp tx_bursts.cpp tx_samples_from_file.cpp diff --git a/host/examples/rx_multi_samples.cpp b/host/examples/rx_multi_samples.cpp index e820343ca..08b2d399d 100644 --- a/host/examples/rx_multi_samples.cpp +++ b/host/examples/rx_multi_samples.cpp @@ -44,7 +44,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("nsamps", po::value<size_t>(&total_num_samps)->default_value(10000), "total number of samples to receive") ("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of incoming samples") ("sync", po::value<std::string>(&sync)->default_value("now"), "synchronization method: now, pps") - ("subdev", po::value<std::string>(&subdev)->default_value(""), "subdev spec (homogeneous across motherboards)") + ("subdev", po::value<std::string>(&subdev), "subdev spec (homogeneous across motherboards)") ("dilv", "specify to disable inner-loop verbose") ; po::variables_map vm; diff --git a/host/examples/test_async_messages.cpp b/host/examples/test_messages.cpp index 7f922ed35..60d108184 100644 --- a/host/examples/test_async_messages.cpp +++ b/host/examples/test_messages.cpp @@ -18,6 +18,7 @@ #include <uhd/utils/thread_priority.hpp> #include <uhd/utils/safe_main.hpp> #include <uhd/utils/static.hpp> +#include <uhd/types/stream_cmd.hpp> #include <uhd/usrp/multi_usrp.hpp> #include <boost/assign/list_of.hpp> #include <boost/program_options.hpp> @@ -31,6 +32,107 @@ namespace po = boost::program_options; /*! + * Test the late command message: + * Issue a stream command with a time that is in the past. + * We expect to get an inline late command message. + */ +bool test_late_command_message(uhd::usrp::multi_usrp::sptr usrp){ + std::cout << "Test late command message... " << std::flush; + + usrp->set_time_now(uhd::time_spec_t(200.0)); //set time + + uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); + stream_cmd.num_samps = usrp->get_device()->get_max_recv_samps_per_packet(); + stream_cmd.stream_now = false; + stream_cmd.time_spec = uhd::time_spec_t(100.0); //time in the past + usrp->issue_stream_cmd(stream_cmd); + + std::vector<std::complex<float> > buff(usrp->get_device()->get_max_recv_samps_per_packet()); + uhd::rx_metadata_t md; + + const size_t nsamps = usrp->get_device()->recv( + &buff.front(), buff.size(), md, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_FULL_BUFF + ); + + switch(md.error_code){ + case uhd::rx_metadata_t::ERROR_CODE_LATE_COMMAND: + std::cout << boost::format( + "success:\n" + " Got error code late command message.\n" + ) << std::endl; + return true; + + case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT: + std::cout << boost::format( + "failed:\n" + " Inline message recv timed out.\n" + ) << std::endl; + return false; + + default: + std::cout << boost::format( + "failed:\n" + " Got unexpected error code 0x%x, nsamps %u.\n" + ) % md.error_code % nsamps << std::endl; + return false; + } +} + +/*! + * Test the broken chain message: + * Issue a stream command with num samps and more. + * We expect to get an inline broken chain message. + */ +bool test_broken_chain_message(uhd::usrp::multi_usrp::sptr usrp){ + std::cout << "Test broken chain message... " << std::flush; + + uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE); + stream_cmd.stream_now = true; + stream_cmd.num_samps = usrp->get_device()->get_max_recv_samps_per_packet(); + usrp->issue_stream_cmd(stream_cmd); + + std::vector<std::complex<float> > buff(usrp->get_device()->get_max_recv_samps_per_packet()); + uhd::rx_metadata_t md; + + usrp->get_device()->recv( //once for the requested samples + &buff.front(), buff.size(), md, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_FULL_BUFF + ); + + usrp->get_device()->recv( //again for the inline message + &buff.front(), buff.size(), md, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_FULL_BUFF + ); + + switch(md.error_code){ + case uhd::rx_metadata_t::ERROR_CODE_BROKEN_CHAIN: + std::cout << boost::format( + "success:\n" + " Got error code broken chain message.\n" + ) << std::endl; + return true; + + case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT: + std::cout << boost::format( + "failed:\n" + " Inline message recv timed out.\n" + ) << std::endl; + return false; + + default: + std::cout << boost::format( + "failed:\n" + " Got unexpected error code 0x%x.\n" + ) % md.error_code << std::endl; + return false; + } +} + +/*! * Test the burst ack message: * Send a burst of many samples that will fragment internally. * We expect to get an burst ack async message. @@ -169,9 +271,22 @@ bool test_time_error_message(uhd::usrp::multi_usrp::sptr usrp){ } } -void flush_async_md(uhd::usrp::multi_usrp::sptr usrp){ +void flush_async(uhd::usrp::multi_usrp::sptr usrp){ uhd::async_metadata_t async_md; - while (usrp->get_device()->recv_async_msg(async_md, 1.0)){} + while (usrp->get_device()->recv_async_msg(async_md)){} +} + +void flush_recv(uhd::usrp::multi_usrp::sptr usrp){ + std::vector<std::complex<float> > buff(usrp->get_device()->get_max_recv_samps_per_packet()); + uhd::rx_metadata_t md; + + do{ + usrp->get_device()->recv( + &buff.front(), buff.size(), md, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_FULL_BUFF + ); + } while (md.error_code != uhd::rx_metadata_t::ERROR_CODE_TIMEOUT); } int UHD_SAFE_MAIN(int argc, char *argv[]){ @@ -179,7 +294,6 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //variables to be set by po std::string args; - double rate; size_t ntests; //setup the program options @@ -187,8 +301,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ desc.add_options() ("help", "help message") ("args", po::value<std::string>(&args)->default_value(""), "multi uhd device address args") - ("rate", po::value<double>(&rate)->default_value(1.5e6), "rate of outgoing samples") - ("ntests", po::value<size_t>(&ntests)->default_value(10), "number of tests to run") + ("ntests", po::value<size_t>(&ntests)->default_value(50), "number of tests to run") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); @@ -196,7 +309,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //print the help message if (vm.count("help")){ - std::cout << boost::format("UHD Test Async Messages %s") % desc << std::endl; + std::cout << boost::format("UHD Test Messages %s") % desc << std::endl; return ~0; } @@ -206,19 +319,16 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args); std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl; - //set the tx sample rate - std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate/1e6) << std::endl; - usrp->set_tx_rate(rate); - std::cout << boost::format("Actual TX Rate: %f Msps...") % (usrp->get_tx_rate()/1e6) << std::endl << std::endl; - //------------------------------------------------------------------ - // begin asyc messages test + // begin messages test //------------------------------------------------------------------ static const uhd::dict<std::string, boost::function<bool(uhd::usrp::multi_usrp::sptr)> > tests = boost::assign::map_list_of ("Test Burst ACK ", &test_burst_ack_message) ("Test Underflow ", &test_underflow_message) ("Test Time Error", &test_time_error_message) + ("Test Late Command", &test_late_command_message) + ("Test Broken Chain", &test_broken_chain_message) ; //init result counts @@ -229,10 +339,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } //run the tests, pick at random + std::srand(uhd::time_spec_t::get_system_time().get_full_secs()); for (size_t n = 0; n < ntests; n++){ std::string key = tests.keys()[std::rand() % tests.size()]; bool pass = tests[key](usrp); - flush_async_md(usrp); + flush_async(usrp); + flush_recv(usrp); //store result if (pass) successes[key]++; @@ -243,7 +355,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << std::endl << "Summary:" << std::endl << std::endl; BOOST_FOREACH(const std::string &key, tests.keys()){ std::cout << boost::format( - "%s -> %3d successes, %3d failures" + "%s -> %3u successes, %3u failures" ) % key % successes[key] % failures[key] << std::endl; } diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index 74dc4a7d6..49562a7a0 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -26,6 +26,8 @@ INSTALL(FILES convert.hpp device.hpp exception.hpp + property_tree.ipp + property_tree.hpp version.hpp wax.hpp DESTINATION ${INCLUDE_DIR}/uhd diff --git a/host/include/uhd/property_tree.hpp b/host/include/uhd/property_tree.hpp new file mode 100644 index 000000000..cd8cba7e5 --- /dev/null +++ b/host/include/uhd/property_tree.hpp @@ -0,0 +1,143 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_PROPERTY_TREE_HPP +#define INCLUDED_UHD_PROPERTY_TREE_HPP + +#include <uhd/config.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/function.hpp> +#include <boost/filesystem/path.hpp> +#include <vector> + +namespace uhd{ + +/*! + * A templated property interface for holding a value + * and registering callbacks when that value changes. + */ +template <typename T> class property : boost::noncopyable{ +public: + typedef boost::function<void(const T &)> subscriber_type; + typedef boost::function<T(void)> publisher_type; + typedef boost::function<T(const T &)> coercer_type; + + /*! + * Register a coercer into the property. + * A coercer is a special subscribes that coerces the value. + * Only one coercer may be registered per property. + * Registering a coercer replaces the previous coercer. + * \param coercer the coercer callback function + * \return a reference to this property for chaining + */ + virtual property<T> &coerce(const coercer_type &coercer) = 0; + + /*! + * Register a publisher into the property. + * A publisher is a special callback the provides the value. + * Publishers are useful for creating read-only properties. + * Only one publisher may be registered per property. + * Registering a publisher replaces the previous publisher. + * \param publisher the publisher callback function + * \return a reference to this property for chaining + */ + virtual property<T> &publish(const publisher_type &publisher) = 0; + + /*! + * Register a subscriber into the property. + * All subscribers are called when the value changes. + * Once a subscriber is registered, it cannot be unregistered. + * \param subscriber the subscriber callback function + * \return a reference to this property for chaining + */ + virtual property<T> &subscribe(const subscriber_type &subscriber) = 0; + + /*! + * Update calls all subscribers w/ the current value. + * \return a reference to this property for chaining + */ + virtual property<T> &update(void) = 0; + + /*! + * Set the new value and call all subscribers. + * The coercer (when provided) is called initially, + * and the coerced value is used to set the subscribers. + * \param value the new value to set on this property + * \return a reference to this property for chaining + */ + virtual property<T> &set(const T &value) = 0; + + /*! + * Get the current value of this property. + * The publisher (when provided) yields the value, + * otherwise an internal shadow is used for the value. + * \return the current value in the property + */ + virtual T get(void) const = 0; + + /*! + * A property is empty if it has never been set. + * A property with a publisher is never empty. + * \return true if the property is empty + */ + virtual bool empty(void) const = 0; +}; + +/*! + * The property tree provides a file system structure for accessing properties. + */ +class UHD_API property_tree : boost::noncopyable{ +public: + typedef boost::shared_ptr<property_tree> sptr; + typedef boost::filesystem::path path_type; + + //! Create a new + empty property tree + static sptr make(void); + + //! Get a subtree with a new root starting at path + virtual sptr subtree(const path_type &path) const = 0; + + //! Remove a property or directory (recursive) + virtual void remove(const path_type &path) = 0; + + //! True if the path exists in the tree + virtual bool exists(const path_type &path) const = 0; + + //! Get an iterable to all things in the given path + virtual std::vector<std::string> list(const path_type &path) const = 0; + + //! Create a new property entry in the tree + template <typename T> property<T> &create(const path_type &path); + + //! Get access to a property in the tree + template <typename T> property<T> &access(const path_type &path); + +private: + //! Internal create property with wild-card type + virtual void _create(const path_type &path, const boost::shared_ptr<void> &prop) = 0; + + //! Internal access property with wild-card type + virtual boost::shared_ptr<void> &_access(const path_type &path) const = 0; + +}; + +} //namespace uhd + +#include <uhd/property_tree.ipp> + +#endif /* INCLUDED_UHD_PROPERTY_TREE_HPP */ diff --git a/host/include/uhd/property_tree.ipp b/host/include/uhd/property_tree.ipp new file mode 100644 index 000000000..868cba475 --- /dev/null +++ b/host/include/uhd/property_tree.ipp @@ -0,0 +1,95 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_PROPERTY_TREE_IPP +#define INCLUDED_UHD_PROPERTY_TREE_IPP + +#include <uhd/exception.hpp> +#include <boost/foreach.hpp> +#include <vector> + +/*********************************************************************** + * Implement templated property impl + **********************************************************************/ +namespace uhd{ namespace /*anon*/{ + +template <typename T> class property_impl : public property<T>{ +public: + + property<T> &coerce(const typename property<T>::coercer_type &coercer){ + _coercer = coercer; + return *this; + } + + property<T> &publish(const typename property<T>::publisher_type &publisher){ + _publisher = publisher; + return *this; + } + + property<T> &subscribe(const typename property<T>::subscriber_type &subscriber){ + _subscribers.push_back(subscriber); + return *this; + } + + property<T> &update(void){ + this->set(this->get()); + return *this; + } + + property<T> &set(const T &value){ + _value = boost::shared_ptr<T>(new T(_coercer.empty()? value : _coercer(value))); + BOOST_FOREACH(typename property<T>::subscriber_type &subscriber, _subscribers){ + subscriber(*_value); //let errors propagate + } + return *this; + } + + T get(void) const{ + if (empty()) throw uhd::runtime_error("Cannot get() on an empty property"); + return _publisher.empty()? *_value : _publisher(); + } + + bool empty(void) const{ + return _publisher.empty() and _value.get() == NULL; + } + +private: + std::vector<typename property<T>::subscriber_type> _subscribers; + typename property<T>::publisher_type _publisher; + typename property<T>::coercer_type _coercer; + boost::shared_ptr<T> _value; +}; + +}} //namespace uhd::/*anon*/ + +/*********************************************************************** + * Implement templated methods for the property tree + **********************************************************************/ +namespace uhd{ + + template <typename T> property<T> &property_tree::create(const path_type &path){ + this->_create(path, typename boost::shared_ptr<property<T> >(new property_impl<T>())); + return this->access<T>(path); + } + + template <typename T> property<T> &property_tree::access(const path_type &path){ + return *boost::static_pointer_cast<property<T> >(this->_access(path)); + } + +} //namespace uhd + +#endif /* INCLUDED_UHD_PROPERTY_TREE_IPP */ diff --git a/host/include/uhd/types/serial.hpp b/host/include/uhd/types/serial.hpp index 8281fd3ec..8a5ed1c32 100644 --- a/host/include/uhd/types/serial.hpp +++ b/host/include/uhd/types/serial.hpp @@ -19,6 +19,7 @@ #define INCLUDED_UHD_TYPES_SERIAL_HPP #include <uhd/config.hpp> +#include <boost/shared_ptr.hpp> #include <boost/cstdint.hpp> #include <vector> @@ -43,6 +44,8 @@ namespace uhd{ */ class UHD_API i2c_iface{ public: + typedef boost::shared_ptr<i2c_iface> sptr; + /*! * Write bytes over the i2c. * \param addr the address @@ -123,6 +126,8 @@ namespace uhd{ */ class UHD_API spi_iface{ public: + typedef boost::shared_ptr<spi_iface> sptr; + /*! * Perform a spi transaction. * \param which_slave the slave device number @@ -170,6 +175,28 @@ namespace uhd{ ); }; + /*! + * UART interface to write and read bytes. + */ + class UHD_API uart_iface{ + public: + typedef boost::shared_ptr<uart_iface> sptr; + + /*! + * Write to a serial port. + * \param dev which UART to write to + * \param buf the data to write + */ + virtual void write_uart(boost::uint8_t dev, const std::string &buf) = 0; + + /*! + * Read from a serial port. + * \param dev which UART to read from + * \return the data read from the serial port + */ + virtual std::string read_uart(boost::uint8_t dev) = 0; + }; + } //namespace uhd #endif /* INCLUDED_UHD_TYPES_SERIAL_HPP */ diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index e441433fd..ba38a67ea 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -17,13 +17,6 @@ INSTALL(FILES - #### props headers ### - codec_props.hpp - dboard_props.hpp - device_props.hpp - dsp_props.hpp - mboard_props.hpp - subdev_props.hpp #### dboard headers ### dboard_base.hpp @@ -33,12 +26,9 @@ INSTALL(FILES dboard_manager.hpp ### utilities ### - dsp_utils.hpp gps_ctrl.hpp mboard_eeprom.hpp - misc_utils.hpp subdev_spec.hpp - tune_helper.hpp ### interfaces ### single_usrp.hpp diff --git a/host/include/uhd/usrp/codec_props.hpp b/host/include/uhd/usrp/codec_props.hpp deleted file mode 100644 index b0a79e3f6..000000000 --- a/host/include/uhd/usrp/codec_props.hpp +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_USRP_CODEC_PROPS_HPP -#define INCLUDED_UHD_USRP_CODEC_PROPS_HPP - -#include <uhd/utils/props.hpp> - -namespace uhd{ namespace usrp{ - - /*! - * Possible device codec properties: - * A codec is expected to have a rate and gain elements. - * Other properties can be discovered through the others prop. - */ - enum codec_prop_t{ - CODEC_PROP_NAME, //ro, std::string - CODEC_PROP_OTHERS, //ro, prop_names_t - CODEC_PROP_GAIN_I, //rw, double - CODEC_PROP_GAIN_Q , //rw, double - CODEC_PROP_GAIN_RANGE, //ro, gain_range_t - CODEC_PROP_GAIN_NAMES //ro, prop_names_t - }; - - -}} //namespace - -#endif /* INCLUDED_UHD_USRP_CODEC_PROPS_HPP */ diff --git a/host/include/uhd/usrp/dboard_base.hpp b/host/include/uhd/usrp/dboard_base.hpp index 9b75d791f..7e9557a95 100644 --- a/host/include/uhd/usrp/dboard_base.hpp +++ b/host/include/uhd/usrp/dboard_base.hpp @@ -28,6 +28,43 @@ namespace uhd{ namespace usrp{ + /*! + * Possible subdev connection types: + * + * A complex subdevice is physically connected to both channels, + * which may be connected in one of two ways: IQ or QI (swapped). + * + * A real subdevice is only physically connected one channel, + * either only the I channel or only the Q channel. + */ + enum subdev_conn_t{ + SUBDEV_CONN_COMPLEX_IQ = 'C', + SUBDEV_CONN_COMPLEX_QI = 'c', + SUBDEV_CONN_REAL_I = 'R', + SUBDEV_CONN_REAL_Q = 'r' + }; + + /*! + * Possible device subdev properties + */ + enum subdev_prop_t{ + SUBDEV_PROP_NAME, //ro, std::string + SUBDEV_PROP_OTHERS, //ro, prop_names_t + SUBDEV_PROP_SENSOR, //ro, sensor_value_t + SUBDEV_PROP_SENSOR_NAMES, //ro, prop_names_t + SUBDEV_PROP_GAIN, //rw, double + SUBDEV_PROP_GAIN_RANGE, //ro, gain_range_t + SUBDEV_PROP_GAIN_NAMES, //ro, prop_names_t + SUBDEV_PROP_FREQ, //rw, double + SUBDEV_PROP_FREQ_RANGE, //ro, freq_range_t + SUBDEV_PROP_ANTENNA, //rw, std::string + SUBDEV_PROP_ANTENNA_NAMES, //ro, prop_names_t + SUBDEV_PROP_CONNECTION, //ro, subdev_conn_t + SUBDEV_PROP_ENABLED, //rw, bool + SUBDEV_PROP_USE_LO_OFFSET, //ro, bool + SUBDEV_PROP_BANDWIDTH //rw, double + }; + /*! * A daughter board dboard_base class for all dboards. * Only other dboard dboard_base classes should inherit this. diff --git a/host/include/uhd/usrp/dboard_eeprom.hpp b/host/include/uhd/usrp/dboard_eeprom.hpp index 394d71dd6..f0190e233 100644 --- a/host/include/uhd/usrp/dboard_eeprom.hpp +++ b/host/include/uhd/usrp/dboard_eeprom.hpp @@ -50,7 +50,7 @@ struct UHD_API dboard_eeprom_t{ * \param iface the serial interface with i2c * \param addr the i2c address for the eeprom */ - void store(i2c_iface &iface, boost::uint8_t addr); + void store(i2c_iface &iface, boost::uint8_t addr) const; }; diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp index 3c41c65a8..091769a5c 100644 --- a/host/include/uhd/usrp/dboard_manager.hpp +++ b/host/include/uhd/usrp/dboard_manager.hpp @@ -19,6 +19,7 @@ #define INCLUDED_UHD_USRP_DBOARD_MANAGER_HPP #include <uhd/config.hpp> +#include <uhd/property_tree.hpp> #include <uhd/utils/props.hpp> #include <uhd/usrp/dboard_base.hpp> #include <uhd/usrp/dboard_id.hpp> @@ -36,6 +37,11 @@ class UHD_API dboard_manager : boost::noncopyable{ public: typedef boost::shared_ptr<dboard_manager> sptr; + //! It does what it says... + static void populate_prop_tree_from_subdev( + property_tree::sptr subtree, wax::obj subdev + ); + //dboard constructor (each dboard should have a ::make with this signature) typedef dboard_base::sptr(*dboard_ctor_t)(dboard_base::ctor_args_t); diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp deleted file mode 100644 index 29211ec8c..000000000 --- a/host/include/uhd/usrp/dboard_props.hpp +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_USRP_DBOARD_PROPS_HPP -#define INCLUDED_UHD_USRP_DBOARD_PROPS_HPP - -#include <uhd/utils/props.hpp> - -namespace uhd{ namespace usrp{ - - /*! - * Possible device dboard properties: - * A dboard has an id, one or more subdevices, and a codec. - * A dboard is considered to be unidirectional (RX or TX). - */ - enum dboard_prop_t{ - DBOARD_PROP_NAME, //ro, std::string - DBOARD_PROP_SUBDEV, //ro, wax::obj - DBOARD_PROP_SUBDEV_NAMES, //ro, prop_names_t - DBOARD_PROP_DBOARD_EEPROM, //rw, dboard_eeprom_t - DBOARD_PROP_GBOARD_EEPROM, //rw, dboard_eeprom_t - DBOARD_PROP_DBOARD_IFACE, //ro, dboard_iface::sptr - DBOARD_PROP_CODEC, //ro, wax::obj - DBOARD_PROP_GAIN_GROUP //ro, gain_group - }; - -}} //namespace - -#endif /* INCLUDED_UHD_USRP_DBOARD_PROPS_HPP */ diff --git a/host/include/uhd/usrp/dsp_props.hpp b/host/include/uhd/usrp/dsp_props.hpp deleted file mode 100644 index e68e11deb..000000000 --- a/host/include/uhd/usrp/dsp_props.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_USRP_DSP_PROPS_HPP -#define INCLUDED_UHD_USRP_DSP_PROPS_HPP - -#include <uhd/utils/props.hpp> - -namespace uhd{ namespace usrp{ - - /*! - * Possible device dsp properties: - * A dsp is a black box fpga component found between - * the over-the-wire data and the codec pins. - * - * The host rate can be modified to control resampling. - * Resampling can take the form of decimation, interpolation, - * or more complex fractional resampling techniques. - * As usual, read back the host rate after setting it - * to get the actual rate that was set (implementation dependent). - * - * A dsp can also shift the digital stream in frequency. - * Set the shift property and read it back to get actual shift. - */ - enum dsp_prop_t{ - DSP_PROP_NAME, //ro, std::string - DSP_PROP_OTHERS, //ro, prop_names_t - DSP_PROP_STREAM_CMD, //wo, stream_cmd_t - DSP_PROP_FREQ_SHIFT, //rw, double Hz - DSP_PROP_CODEC_RATE, //ro, double Sps - DSP_PROP_HOST_RATE //rw, double Sps - }; - -}} //namespace - -#endif /* INCLUDED_UHD_USRP_DSP_PROPS_HPP */ diff --git a/host/include/uhd/usrp/dsp_utils.hpp b/host/include/uhd/usrp/dsp_utils.hpp deleted file mode 100644 index 5b81ce322..000000000 --- a/host/include/uhd/usrp/dsp_utils.hpp +++ /dev/null @@ -1,96 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_USRP_DSP_UTILS_HPP -#define INCLUDED_UHD_USRP_DSP_UTILS_HPP - -#include <uhd/config.hpp> -#include <uhd/types/stream_cmd.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <boost/cstdint.hpp> - -namespace uhd{ namespace usrp{ - -namespace dsp_type1{ - - /*! - * Calculate the rx mux word from properties. - * \param subdev_conn the subdev connection type - * \return the 32-bit rx mux control word - */ - UHD_API boost::uint32_t calc_rx_mux_word(subdev_conn_t subdev_conn); - - /*! - * Calculate the tx mux word from properties. - * \param subdev_conn the subdev connection type - * \return the 32-bit tx mux control word - */ - UHD_API boost::uint32_t calc_tx_mux_word(subdev_conn_t subdev_conn); - - /*! - * Calculate the cordic word from the frequency and clock rate. - * The frequency will be set to the actual (possible) frequency. - * - * \param freq the requested frequency in Hz - * \param codec_rate the dsp codec rate in Hz - * \return the 32-bit cordic control word - */ - UHD_API boost::uint32_t calc_cordic_word_and_update( - double &freq, double codec_rate - ); - - /*! - * Calculate the CIC filter word from the rate. - * Check if requested decim/interp rate is: - * multiple of 4, enable two halfband filters - * multiple of 2, enable one halfband filter - * handle remainder in CIC - * - * \param rate the requested rate in Sps - * \return the 32-bit cic filter control word - */ - UHD_API boost::uint32_t calc_cic_filter_word(unsigned rate); - - /*! - * Calculate the IQ scale factor word from I and Q components. - * \param i the I component of the scalar - * \param q the Q component of the scalar - * \return the 32-bit scale factor control word - */ - UHD_API boost::uint32_t calc_iq_scale_word( - boost::int16_t i, boost::int16_t q - ); - - /*! - * Calculate the IQ scale factor word from the rate. - * \param rate the requested rate in Sps - * \return the 32-bit scale factor control word - */ - UHD_API boost::uint32_t calc_iq_scale_word(unsigned rate); - - /*! - * Calculate the stream command word from the stream command struct. - * \param stream_cmd the requested stream command with mode, flags, timestamp - * \return the 32-bit stream command word - */ - UHD_API boost::uint32_t calc_stream_cmd_word(const stream_cmd_t &stream_cmd); - -} //namespace dsp_type1 - -}} //namespace - -#endif /* INCLUDED_UHD_USRP_DSP_UTILS_HPP */ diff --git a/host/include/uhd/usrp/mboard_eeprom.hpp b/host/include/uhd/usrp/mboard_eeprom.hpp index 52363b95c..ea66bb2e0 100644 --- a/host/include/uhd/usrp/mboard_eeprom.hpp +++ b/host/include/uhd/usrp/mboard_eeprom.hpp @@ -56,7 +56,7 @@ namespace uhd{ namespace usrp{ * \param iface the interface to i2c * \param map the map type enum */ - void commit(i2c_iface &iface, map_type map); + void commit(i2c_iface &iface, map_type map) const; }; diff --git a/host/include/uhd/usrp/mboard_iface.hpp b/host/include/uhd/usrp/mboard_iface.hpp index 784fbc7c5..bbee8f2de 100644 --- a/host/include/uhd/usrp/mboard_iface.hpp +++ b/host/include/uhd/usrp/mboard_iface.hpp @@ -33,7 +33,7 @@ namespace uhd{ namespace usrp{ * Provides a set of functions to implementation layer. * Including spi, peek, poke, control... */ -class mboard_iface : public uhd::i2c_iface, public uhd::spi_iface { +class mboard_iface : public uhd::i2c_iface, public uhd::spi_iface, public uhd::uart_iface { public: typedef boost::shared_ptr<mboard_iface> sptr; /*! @@ -64,20 +64,6 @@ public: */ virtual boost::uint16_t peek16(boost::uint32_t addr) = 0; - /*! - * Write to a serial port. - * \param dev which UART to write to - * \param buf the data to write - */ - virtual void write_uart(boost::uint8_t dev, const std::string &buf) = 0; - - /*! - * Read from a serial port. - * \param dev which UART to read from - * \return the data read from the serial port - */ - virtual std::string read_uart(boost::uint8_t dev) = 0; - }; }} diff --git a/host/include/uhd/usrp/mboard_props.hpp b/host/include/uhd/usrp/mboard_props.hpp deleted file mode 100644 index a2580954e..000000000 --- a/host/include/uhd/usrp/mboard_props.hpp +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_USRP_MBOARD_PROPS_HPP -#define INCLUDED_UHD_USRP_MBOARD_PROPS_HPP - -#include <uhd/utils/props.hpp> - -namespace uhd{ namespace usrp{ - - /*! - * Possible device mboard properties: - * The general mboard properties are listed below. - * Custom properties can be identified with a string - * and discovered though the others property. - */ - enum mboard_prop_t{ - MBOARD_PROP_NAME, //ro, std::string - MBOARD_PROP_OTHERS, //ro, prop_names_t - MBOARD_PROP_SENSOR, //ro, sensor_value_t - MBOARD_PROP_SENSOR_NAMES, //ro, prop_names_t - MBOARD_PROP_CLOCK_RATE, //rw, double - MBOARD_PROP_RX_DSP, //ro, wax::obj - MBOARD_PROP_RX_DSP_NAMES, //ro, prop_names_t - MBOARD_PROP_TX_DSP, //ro, wax::obj - MBOARD_PROP_TX_DSP_NAMES, //ro, prop_names_t - MBOARD_PROP_RX_DBOARD, //ro, wax::obj - MBOARD_PROP_RX_DBOARD_NAMES, //ro, prop_names_t - MBOARD_PROP_TX_DBOARD, //ro, wax::obj - MBOARD_PROP_TX_DBOARD_NAMES, //ro, prop_names_t - MBOARD_PROP_RX_SUBDEV_SPEC, //rw, subdev_spec_t - MBOARD_PROP_TX_SUBDEV_SPEC, //rw, subdev_spec_t - MBOARD_PROP_CLOCK_CONFIG, //rw, clock_config_t - MBOARD_PROP_TIME_NOW, //rw, time_spec_t - MBOARD_PROP_TIME_PPS, //wo, time_spec_t - MBOARD_PROP_EEPROM_MAP, //wr, mboard_eeprom_t - MBOARD_PROP_IFACE, //ro, mboard_iface::sptr - }; - -}} //namespace - -#endif /* INCLUDED_UHD_USRP_MBOARD_PROPS_HPP */ diff --git a/host/include/uhd/usrp/misc_utils.hpp b/host/include/uhd/usrp/misc_utils.hpp deleted file mode 100644 index 37860a1a5..000000000 --- a/host/include/uhd/usrp/misc_utils.hpp +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_USRP_MISC_UTILS_HPP -#define INCLUDED_UHD_USRP_MISC_UTILS_HPP - -#include <uhd/config.hpp> -#include <uhd/wax.hpp> -#include <uhd/usrp/dboard_id.hpp> -#include <uhd/usrp/subdev_spec.hpp> -#include <uhd/utils/gain_group.hpp> - -namespace uhd{ namespace usrp{ - - /*! - * Different policies for gain group prioritization. - */ - enum gain_group_policy_t{ - GAIN_GROUP_POLICY_RX = 'R', - GAIN_GROUP_POLICY_TX = 'T' - }; - - /*! - * Create a gain group that represents the subdevice and its codec. - * \param dboard_id the dboard id for this subdevice - * \param subdev the object with subdevice properties - * \param codec the object with codec properties - * \param gain_group_policy the policy to use - */ - UHD_API gain_group::sptr make_gain_group( - const dboard_id_t &dboard_id, - wax::obj subdev, wax::obj codec, - gain_group_policy_t gain_group_policy - ); - - /*! - * Verify the rx subdevice specification. - * If the subdev spec if empty, automatically fill it. - * \param subdev_spec the subdev spec to verify/fill - * \param mboard the motherboard properties object - * \throw exception when the subdev spec is invalid - */ - UHD_API void verify_rx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard); - - /*! - * Verify the tx subdevice specification. - * If the subdev spec if empty, automatically fill it. - * \param subdev_spec the subdev spec to verify/fill - * \param mboard the motherboard properties object - * \throw exception when the subdev spec is invalid - */ - UHD_API void verify_tx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard); - -}} //namespace - -#endif /* INCLUDED_UHD_USRP_MISC_UTILS_HPP */ - diff --git a/host/include/uhd/usrp/subdev_props.hpp b/host/include/uhd/usrp/subdev_props.hpp deleted file mode 100644 index 40b339703..000000000 --- a/host/include/uhd/usrp/subdev_props.hpp +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_USRP_SUBDEV_PROPS_HPP -#define INCLUDED_UHD_USRP_SUBDEV_PROPS_HPP - -#include <uhd/utils/props.hpp> - -namespace uhd{ namespace usrp{ - - /*! - * Possible subdev connection types: - * - * A complex subdevice is physically connected to both channels, - * which may be connected in one of two ways: IQ or QI (swapped). - * - * A real subdevice is only physically connected one channel, - * either only the I channel or only the Q channel. - */ - enum subdev_conn_t{ - SUBDEV_CONN_COMPLEX_IQ = 'C', - SUBDEV_CONN_COMPLEX_QI = 'c', - SUBDEV_CONN_REAL_I = 'R', - SUBDEV_CONN_REAL_Q = 'r' - }; - - /*! - * Possible device subdev properties - */ - enum subdev_prop_t{ - SUBDEV_PROP_NAME, //ro, std::string - SUBDEV_PROP_OTHERS, //ro, prop_names_t - SUBDEV_PROP_SENSOR, //ro, sensor_value_t - SUBDEV_PROP_SENSOR_NAMES, //ro, prop_names_t - SUBDEV_PROP_GAIN, //rw, double - SUBDEV_PROP_GAIN_RANGE, //ro, gain_range_t - SUBDEV_PROP_GAIN_NAMES, //ro, prop_names_t - SUBDEV_PROP_FREQ, //rw, double - SUBDEV_PROP_FREQ_RANGE, //ro, freq_range_t - SUBDEV_PROP_ANTENNA, //rw, std::string - SUBDEV_PROP_ANTENNA_NAMES, //ro, prop_names_t - SUBDEV_PROP_CONNECTION, //ro, subdev_conn_t - SUBDEV_PROP_ENABLED, //rw, bool - SUBDEV_PROP_USE_LO_OFFSET, //ro, bool - SUBDEV_PROP_BANDWIDTH //rw, double - }; - -}} //namespace - -#endif /* INCLUDED_UHD_USRP_SUBDEV_PROPS_HPP */ diff --git a/host/include/uhd/usrp/subdev_spec.hpp b/host/include/uhd/usrp/subdev_spec.hpp index b189724c9..62c1fc177 100644 --- a/host/include/uhd/usrp/subdev_spec.hpp +++ b/host/include/uhd/usrp/subdev_spec.hpp @@ -62,11 +62,6 @@ namespace uhd{ namespace usrp{ * The markup-string is a whitespace separated list of dboard:subdev pairs. * The first pair represents the subdevice for channel zero, * the second pair represents the subdevice for channel one, and so on. - * - * Special handling for empty conditions: - * - An empty subdevice specification means: select the first subdevice found in the configuration - * - An empty daughterboard name means: select the only daughterboard slot or error if multiple exist - * - An empty subdevice name means: select the only subdevice on that board or error if multiple exist */ class UHD_API subdev_spec_t : public std::vector<subdev_spec_pair_t>{ public: diff --git a/host/include/uhd/usrp/tune_helper.hpp b/host/include/uhd/usrp/tune_helper.hpp deleted file mode 100644 index 0d468a4e2..000000000 --- a/host/include/uhd/usrp/tune_helper.hpp +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_USRP_TUNE_HELPER_HPP -#define INCLUDED_UHD_USRP_TUNE_HELPER_HPP - -#include <uhd/config.hpp> -#include <uhd/wax.hpp> -#include <uhd/types/tune_request.hpp> -#include <uhd/types/tune_result.hpp> - -namespace uhd{ namespace usrp{ - - /*! - * Tune a rx chain to the desired frequency: - * The IF of the subdevice is set as close as possible to - * the given target frequency + the LO offset (when applicable). - * The ddc cordic is setup to bring the IF down to baseband. - * \param subdev the dboard subdevice object with properties - * \param ddc the mboard dsp object with properties - * \param tune_request tune request instructions - * \return a tune result struct - */ - UHD_API tune_result_t tune_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc, const tune_request_t &tune_request - ); - - /*! - * Calculate the overall frequency from the combination of dboard IF and DDC shift. - * \param subdev the dboard subdevice object with properties - * \param ddc the mboard dsp object with properties - * \return the overall tune frequency of the system in Hz - */ - UHD_API double derive_freq_from_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc - ); - - /*! - * Tune a tx chain to the desired frequency: - * The IF of the subdevice is set as close as possible to - * the given target frequency + the LO offset (when applicable). - * The duc cordic is setup to bring the baseband up to IF. - * \param subdev the dboard subdevice object with properties - * \param duc the mboard dsp object with properties - * \param tune_request tune request instructions - * \return a tune result struct - */ - UHD_API tune_result_t tune_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc, const tune_request_t &tune_request - ); - - /*! - * Calculate the overall frequency from the combination of dboard IF and DUC shift. - * \param subdev the dboard subdevice object with properties - * \param duc the mboard dsp object with properties - * \return the overall tune frequency of the system in Hz - */ - UHD_API double derive_freq_from_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc - ); - -}} - -#endif /* INCLUDED_UHD_USRP_TUNE_HELPER_HPP */ diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt index 88a0e612b..0bf98fb67 100644 --- a/host/include/uhd/utils/CMakeLists.txt +++ b/host/include/uhd/utils/CMakeLists.txt @@ -30,6 +30,7 @@ INSTALL(FILES safe_call.hpp safe_main.hpp static.hpp + tasks.hpp thread_priority.hpp DESTINATION ${INCLUDE_DIR}/uhd/utils COMPONENT headers diff --git a/host/include/uhd/utils/tasks.hpp b/host/include/uhd/utils/tasks.hpp new file mode 100644 index 000000000..38b2bddf0 --- /dev/null +++ b/host/include/uhd/utils/tasks.hpp @@ -0,0 +1,53 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_UTILS_TASKS_HPP +#define INCLUDED_UHD_UTILS_TASKS_HPP + +#include <uhd/config.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/function.hpp> +#include <boost/utility.hpp> + +namespace uhd{ + + class task : boost::noncopyable{ + public: + typedef boost::shared_ptr<task> sptr; + typedef boost::function<void(void)> task_fcn_type; + + /*! + * Create a new task object with function callback. + * The task function callback will be run in a loop. + * until the thread is interrupted by the deconstructor. + * + * A task should return in a reasonable amount of time + * or may block forever under the following conditions: + * - The blocking call is interruptible. + * - The task polls the interrupt condition. + * + * \param task_fcn the task callback function + * \return a new task object + */ + static sptr make(const task_fcn_type &task_fcn); + + }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_UTILS_TASKS_HPP */ + diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index ebb211566..60ddbce5b 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -89,6 +89,7 @@ SET_SOURCE_FILES_PROPERTIES( LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/device.cpp ${CMAKE_CURRENT_SOURCE_DIR}/exception.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/property_tree.cpp ${CMAKE_CURRENT_SOURCE_DIR}/version.cpp ${CMAKE_CURRENT_SOURCE_DIR}/wax.cpp ) diff --git a/host/lib/property_tree.cpp b/host/lib/property_tree.cpp new file mode 100644 index 000000000..469d59e0d --- /dev/null +++ b/host/lib/property_tree.cpp @@ -0,0 +1,132 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/property_tree.hpp> +#include <uhd/types/dict.hpp> +#include <boost/foreach.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/make_shared.hpp> +#include <iostream> + +class property_tree_impl : public uhd::property_tree{ +public: + + property_tree_impl(const path_type &root = path_type()): + _root(root) + { + _guts = boost::make_shared<tree_guts_type>(); + } + + sptr subtree(const path_type &path_) const{ + const path_type path = _root / path_; + boost::mutex::scoped_lock lock(_guts->mutex); + + property_tree_impl *subtree = new property_tree_impl(path); + subtree->_guts = this->_guts; //copy the guts sptr + return sptr(subtree); + } + + void remove(const path_type &path_){ + const path_type path = _root / path_; + boost::mutex::scoped_lock lock(_guts->mutex); + + node_type *parent = NULL; + node_type *node = &_guts->root; + BOOST_FOREACH(const std::string &branch, path){ + if (not node->has_key(branch)) throw_path_not_found(path); + parent = node; + node = &(*node)[branch]; + } + if (parent == NULL) throw uhd::runtime_error("Cannot uproot"); + parent->pop(path.leaf()); + } + + bool exists(const path_type &path_) const{ + const path_type path = _root / path_; + boost::mutex::scoped_lock lock(_guts->mutex); + + node_type *node = &_guts->root; + BOOST_FOREACH(const std::string &branch, path){ + if (not node->has_key(branch)) return false; + node = &(*node)[branch]; + } + return true; + } + + std::vector<std::string> list(const path_type &path_) const{ + const path_type path = _root / path_; + boost::mutex::scoped_lock lock(_guts->mutex); + + node_type *node = &_guts->root; + BOOST_FOREACH(const std::string &branch, path){ + if (not node->has_key(branch)) throw_path_not_found(path); + node = &(*node)[branch]; + } + + return node->keys(); + } + + void _create(const path_type &path_, const boost::shared_ptr<void> &prop){ + const path_type path = _root / path_; + boost::mutex::scoped_lock lock(_guts->mutex); + + node_type *node = &_guts->root; + BOOST_FOREACH(const std::string &branch, path){ + if (not node->has_key(branch)) (*node)[branch] = node_type(); + node = &(*node)[branch]; + } + if (node->prop.get() != NULL) throw uhd::runtime_error("Cannot create! Property already exists at: " + path.string()); + node->prop = prop; + } + + boost::shared_ptr<void> &_access(const path_type &path_) const{ + const path_type path = _root / path_; + boost::mutex::scoped_lock lock(_guts->mutex); + + node_type *node = &_guts->root; + BOOST_FOREACH(const std::string &branch, path){ + if (not node->has_key(branch)) throw_path_not_found(path); + node = &(*node)[branch]; + } + if (node->prop.get() == NULL) throw uhd::runtime_error("Cannot access! Property uninitialized at: " + path.string()); + return node->prop; + } + +private: + void throw_path_not_found(const path_type &path) const{ + throw uhd::lookup_error("Path not found in tree: " + path.string()); + } + + //basic structural node element + struct node_type : uhd::dict<std::string, node_type>{ + boost::shared_ptr<void> prop; + }; + + //tree guts which may be referenced in a subtree + struct tree_guts_type{ + node_type root; + boost::mutex mutex; + }; + + //members, the tree and root prefix + boost::shared_ptr<tree_guts_type> _guts; + const path_type _root; +}; + +uhd::property_tree::sptr uhd::property_tree::make(void){ + return sptr(new property_tree_impl()); +} diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 6d4df7875..9b4290c08 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -206,7 +206,7 @@ libusb::device_handle::sptr libusb::device_handle::get_cached_handle(device::spt handles[dev->get()] = new_handle; return new_handle; } - catch(const uhd::exception &e){ + catch(const uhd::exception &){ std::cerr << "USB open failed: see the application notes for your device." << std::endl; throw; } diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index f903907d0..bce3d4b0b 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -17,6 +17,7 @@ #include "libusb1_base.hpp" #include <uhd/transport/usb_control.hpp> +#include <boost/thread/mutex.hpp> using namespace uhd::transport; @@ -40,6 +41,7 @@ public: unsigned char *buff, boost::uint16_t length ){ + boost::mutex::scoped_lock lock(_mutex); return libusb_control_transfer(_handle->get(), request_type, request, @@ -52,6 +54,7 @@ public: private: libusb::device_handle::sptr _handle; + boost::mutex _mutex; }; /*********************************************************************** diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index f781f890d..0fa856d34 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -21,11 +21,11 @@ #include <uhd/transport/buffer_pool.hpp> #include <uhd/utils/thread_priority.hpp> #include <uhd/utils/msg.hpp> +#include <uhd/utils/tasks.hpp> #include <uhd/exception.hpp> #include <boost/function.hpp> #include <boost/foreach.hpp> #include <boost/thread/thread.hpp> -#include <boost/thread/barrier.hpp> #include <list> using namespace uhd; @@ -202,12 +202,10 @@ public: } //spawn the event handler threads - size_t concurrency = hints.cast<size_t>("concurrency_hint", 1); - boost::barrier spawn_barrier(concurrency+1); - for (size_t i = 0; i < concurrency; i++) _thread_group.create_thread( - boost::bind(&libusb_zero_copy_impl::run_event_loop, this, boost::ref(spawn_barrier)) - ); - spawn_barrier.wait(); + const size_t concurrency = hints.cast<size_t>("concurrency_hint", 1); + for (size_t i = 0; i < concurrency; i++) _event_loop_tasks.push_back(task::make( + boost::bind(&libusb_zero_copy_impl::run_event_loop, this) + )); } ~libusb_zero_copy_impl(void){ @@ -221,9 +219,6 @@ public: boost::this_thread::sleep(boost::posix_time::milliseconds(10)); } } - //shutdown the threads - _thread_group.interrupt_all(); - _thread_group.join_all(); } managed_recv_buffer::sptr get_recv_buff(double timeout){ @@ -275,20 +270,17 @@ private: std::list<libusb_transfer *> _all_luts; //! event handler threads - boost::thread_group _thread_group; + std::list<task::sptr> _event_loop_tasks; - void run_event_loop(boost::barrier &spawn_barrier){ - spawn_barrier.wait(); + void run_event_loop(void){ set_thread_priority_safe(); libusb_context *context = libusb::session::get_global_session()->get_context(); - try{ - while (not boost::this_thread::interruption_requested()){ - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 100000; //100ms - libusb_handle_events_timeout(context, &tv); - } - } catch(const boost::thread_interrupted &){} + while (not boost::this_thread::interruption_requested()){ + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100000; //100ms + libusb_handle_events_timeout(context, &tv); + } } }; diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp index 80ad17b6c..15bd78242 100644 --- a/host/lib/transport/super_recv_packet_handler.hpp +++ b/host/lib/transport/super_recv_packet_handler.hpp @@ -30,6 +30,7 @@ #include <uhd/transport/vrt_if_packet.hpp> #include <uhd/transport/zero_copy.hpp> #include <boost/thread/mutex.hpp> +#include <boost/dynamic_bitset.hpp> #include <boost/foreach.hpp> #include <boost/function.hpp> #include <boost/format.hpp> @@ -51,61 +52,6 @@ typedef boost::function<void(void)> handle_overflow_type; static inline void handle_overflow_nop(void){} /*********************************************************************** - * Alignment indexes class: - * - Access an integer set with very quick operations. - **********************************************************************/ -class alignment_indexes{ -public: - typedef boost::uint16_t index_type; //16 buffers - - alignment_indexes(void): - _indexes(0), - _sizes(256, 0), - _fronts(256, ~0) - { - //fill the O(1) look up tables for a single byte - for (size_t i = 0; i < 256; i++){ - for (size_t j = 0; j < 8; j++){ - if (i & (1 << j)){ - _sizes[i]++; - _fronts[i] = j; - } - } - } - } - - UHD_INLINE void reset(size_t len){_indexes = (1 << len) - 1;} - - UHD_INLINE size_t front(void){ - //check one byte per iteration - for (size_t i = 0; i < sizeof(_indexes)*8; i+=8){ - size_t front = _fronts[(_indexes >> i) & 0xff]; - if (front != size_t(~0)) return front + i; - } - if (empty()) throw uhd::runtime_error("cannot call front() when empty"); - UHD_THROW_INVALID_CODE_PATH(); - } - - UHD_INLINE void remove(size_t index){_indexes &= ~(1 << index);} - - UHD_INLINE bool empty(void){return _indexes == 0;} - - UHD_INLINE size_t size(void){ - size_t size = 0; - //check one byte per iteration - for (size_t i = 0; i < sizeof(_indexes)*8; i+=8){ - size += _sizes[(_indexes >> i) & 0xff]; - } - return size; - } - -private: - index_type _indexes; - std::vector<size_t> _sizes; - std::vector<size_t> _fronts; -}; - -/*********************************************************************** * Super receive packet handler * * A receive packet handler represents a group of channels. @@ -126,9 +72,9 @@ public: _queue_error_for_next_call(false), _buffers_infos_index(0) { - UHD_ASSERT_THROW(size <= sizeof(alignment_indexes::index_type)*8); this->resize(size); set_alignment_failure_threshold(1000); + this->set_scale_factor(1/32767.); } //! Resize the number of transport channels @@ -208,6 +154,11 @@ public: return boost::mutex::scoped_lock(_mutex); } + //! Set the scale factor used in float conversion + void set_scale_factor(const double scale_factor){ + _scale_factor = scale_factor; + } + /******************************************************************* * Receive: * The entry point for the fast-path receive calls. @@ -293,6 +244,7 @@ private: std::vector<void *> _io_buffs; //used in conversion size_t _bytes_per_item; //used in conversion std::vector<uhd::convert::function_type> _converters; //used in conversion + double _scale_factor; //! information stored for a received buffer struct per_buffer_info_type{ @@ -307,13 +259,12 @@ private: struct buffers_info_type : std::vector<per_buffer_info_type> { buffers_info_type(const size_t size): std::vector<per_buffer_info_type>(size), + indexes_todo(size, true), alignment_time_valid(false), data_bytes_to_copy(0), fragment_offset_in_samps(0) - { - indexes_to_do.reset(size); - } - alignment_indexes indexes_to_do; //used in alignment logic + {/* NOP */} + boost::dynamic_bitset<> indexes_todo; //used in alignment logic time_spec_t alignment_time; //used in alignment logic bool alignment_time_valid; //used in alignment logic size_t data_bytes_to_copy; //keeps track of state @@ -369,34 +320,30 @@ private: info.time = time_spec_t(time_t(info.ifpi.tsi), size_t(info.ifpi.tsf), _tick_rate); //assumes has_tsi and has_tsf are true info.copy_buff = reinterpret_cast<const char *>(info.vrt_hdr + info.ifpi.num_header_words32); - //store the packet count for the next iteration - #ifndef SRPH_DONT_CHECK_SEQUENCE - const size_t expected_packet_count = _props[index].packet_count; - _props[index].packet_count = (info.ifpi.packet_count + 1)%16; - #endif - //-------------------------------------------------------------- //-- Determine return conditions: //-- The order of these checks is HOLY. //-------------------------------------------------------------- - //1) check for out of order timestamps - if (info.ifpi.has_tsi and info.ifpi.has_tsf and prev_buffer_info[index].time > info.time){ - return PACKET_TIMESTAMP_ERROR; - } - - //2) check for inline IF message packets + //1) check for inline IF message packets if (info.ifpi.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ return PACKET_INLINE_MESSAGE; } - //3) check for sequence errors + //2) check for sequence errors #ifndef SRPH_DONT_CHECK_SEQUENCE + const size_t expected_packet_count = _props[index].packet_count; + _props[index].packet_count = (info.ifpi.packet_count + 1)%16; if (expected_packet_count != info.ifpi.packet_count){ return PACKET_SEQUENCE_ERROR; } #endif + //3) check for out of order timestamps + if (info.ifpi.has_tsi and info.ifpi.has_tsf and prev_buffer_info[index].time > info.time){ + return PACKET_TIMESTAMP_ERROR; + } + //4) otherwise the packet is normal! return PACKET_IF_DATA; } @@ -414,15 +361,15 @@ private: if (not info.alignment_time_valid or info[index].time > info.alignment_time){ info.alignment_time_valid = true; info.alignment_time = info[index].time; - info.indexes_to_do.reset(this->size()); - info.indexes_to_do.remove(index); + info.indexes_todo.set(); + info.indexes_todo.reset(index); info.data_bytes_to_copy = info[index].ifpi.num_payload_words32*sizeof(boost::uint32_t); } //if the sequence id matches: // remove this index from the list and continue else if (info[index].time == info.alignment_time){ - info.indexes_to_do.remove(index); + info.indexes_todo.reset(index); } //if the sequence id is older: @@ -448,10 +395,10 @@ private: // - Handle the packet type yielded by the receive. // - Check the timestamps for alignment conditions. size_t iterations = 0; - while (not curr_info.indexes_to_do.empty()){ + while (curr_info.indexes_todo.any()){ //get the index to process for this iteration - const size_t index = curr_info.indexes_to_do.front(); + const size_t index = curr_info.indexes_todo.find_first(); packet_type packet; //receive a single packet from the transport @@ -502,8 +449,10 @@ private: curr_info.metadata.start_of_burst = false; curr_info.metadata.end_of_burst = false; curr_info.metadata.error_code = rx_metadata_t::error_code_t(get_context_code(next_info[index].vrt_hdr, next_info[index].ifpi)); - if (curr_info.metadata.error_code == rx_metadata_t::ERROR_CODE_OVERFLOW) _props[index].handle_overflow(); - UHD_MSG(fastpath) << "O"; + if (curr_info.metadata.error_code == rx_metadata_t::ERROR_CODE_OVERFLOW){ + _props[index].handle_overflow(); + UHD_MSG(fastpath) << "O"; + } return; case PACKET_TIMEOUT_ERROR: @@ -589,7 +538,7 @@ private: //reset current buffer info members for reuse get_curr_buffer_info().fragment_offset_in_samps = 0; get_curr_buffer_info().alignment_time_valid = false; - get_curr_buffer_info().indexes_to_do.reset(this->size()); + get_curr_buffer_info().indexes_todo.set(); //perform receive with alignment logic get_aligned_buffs(timeout); @@ -616,7 +565,7 @@ private: } //copy-convert the samples from the recv buffer - _converters[io_type.tid](buff_info.copy_buff, _io_buffs, nsamps_to_copy_per_io_buff, 1/32767.); + _converters[io_type.tid](buff_info.copy_buff, _io_buffs, nsamps_to_copy_per_io_buff, _scale_factor); //update the rx copy buffer to reflect the bytes copied buff_info.copy_buff += bytes_to_copy; diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp index 8ebc264ef..d5d9e6fe3 100644 --- a/host/lib/transport/super_send_packet_handler.hpp +++ b/host/lib/transport/super_send_packet_handler.hpp @@ -58,6 +58,7 @@ public: _next_packet_seq(0) { this->resize(size); + this->set_scale_factor(32767.); } //! Resize the number of transport channels @@ -132,6 +133,11 @@ public: return boost::mutex::scoped_lock(_mutex); } + //! Set the scale factor used in float conversion + void set_scale_factor(const double scale_factor){ + _scale_factor = scale_factor; + } + /******************************************************************* * Send: * The entry point for the fast-path send calls. @@ -238,11 +244,12 @@ private: size_t _max_samples_per_packet; std::vector<const void *> _zero_buffs; size_t _next_packet_seq; + double _scale_factor; /******************************************************************* * Send a single packet: ******************************************************************/ - size_t send_one_packet( + UHD_INLINE size_t send_one_packet( const uhd::device::send_buffs_type &buffs, const size_t nsamps_per_buff, vrt::if_packet_info_t &if_packet_info, @@ -270,7 +277,7 @@ private: otw_mem += if_packet_info.num_header_words32; //copy-convert the samples into the send buffer - _converters[io_type.tid](_io_buffs, otw_mem, nsamps_per_buff, 32767.); + _converters[io_type.tid](_io_buffs, otw_mem, nsamps_per_buff, _scale_factor); //commit the samples to the zero-copy interface size_t num_bytes_total = (_header_offset_words32+if_packet_info.num_packet_words32)*sizeof(boost::uint32_t); diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 80f4bf45e..8ae379f73 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -24,18 +24,16 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/dboard_id.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dboard_manager.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dsp_utils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/gps_ctrl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mboard_eeprom.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/misc_utils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/multi_usrp.cpp ${CMAKE_CURRENT_SOURCE_DIR}/subdev_spec.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tune_helper.cpp ) +INCLUDE_SUBDIRECTORY(cores) INCLUDE_SUBDIRECTORY(dboard) -INCLUDE_SUBDIRECTORY(fx2) +INCLUDE_SUBDIRECTORY(common) INCLUDE_SUBDIRECTORY(usrp1) INCLUDE_SUBDIRECTORY(usrp2) INCLUDE_SUBDIRECTORY(b100) -INCLUDE_SUBDIRECTORY(usrp_e100) +INCLUDE_SUBDIRECTORY(e100) diff --git a/host/lib/usrp/b100/CMakeLists.txt b/host/lib/usrp/b100/CMakeLists.txt index e1618a49c..1237f52d1 100644 --- a/host/lib/usrp/b100/CMakeLists.txt +++ b/host/lib/usrp/b100/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2011 Ettus Research LLC +# Copyright 2011 Ettus Research LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,22 +26,11 @@ LIBUHD_REGISTER_COMPONENT("B100" ENABLE_B100 ON "ENABLE_LIBUHD;ENABLE_USB" OFF) IF(ENABLE_B100) LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/b100_ctrl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/b100_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/ctrl_packet.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_ctrl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_iface.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/b100_impl.hpp ) ENDIF(ENABLE_B100) diff --git a/host/lib/usrp/b100/b100_ctrl.cpp b/host/lib/usrp/b100/b100_ctrl.cpp index 40b6435ac..e08b47ce4 100644 --- a/host/lib/usrp/b100/b100_ctrl.cpp +++ b/host/lib/usrp/b100/b100_ctrl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -15,18 +15,19 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include "../../transport/super_recv_packet_handler.hpp" #include "b100_ctrl.hpp" -#include "b100_impl.hpp" +#include <uhd/transport/bounded_buffer.hpp> #include <uhd/transport/usb_zero_copy.hpp> #include <uhd/transport/zero_copy.hpp> #include <uhd/transport/vrt_if_packet.hpp> #include <uhd/utils/thread_priority.hpp> #include <uhd/utils/msg.hpp> +#include <uhd/utils/tasks.hpp> #include <uhd/types/metadata.hpp> #include <uhd/types/serial.hpp> #include "ctrl_packet.hpp" -#include <boost/thread.hpp> +#include <boost/thread/thread.hpp> +#include <boost/bind.hpp> #include <uhd/exception.hpp> using namespace uhd::transport; @@ -36,39 +37,67 @@ bool b100_ctrl_debug = false; class b100_ctrl_impl : public b100_ctrl { public: - b100_ctrl_impl(uhd::transport::usb_zero_copy::sptr ctrl_transport) : + b100_ctrl_impl(uhd::transport::zero_copy_if::sptr ctrl_transport): sync_ctrl_fifo(2), - async_msg_fifo(100), _ctrl_transport(ctrl_transport), _seq(0) { - boost::barrier spawn_barrier(2); - viking_marauders.create_thread(boost::bind(&b100_ctrl_impl::viking_marauder_loop, this, boost::ref(spawn_barrier))); - spawn_barrier.wait(); + viking_marauder = task::make(boost::bind(&b100_ctrl_impl::viking_marauder_loop, this)); } - + int write(boost::uint32_t addr, const ctrl_data_t &data); ctrl_data_t read(boost::uint32_t addr, size_t len); - - ~b100_ctrl_impl(void) { - viking_marauders.interrupt_all(); - viking_marauders.join_all(); - } - + bool get_ctrl_data(ctrl_data_t &pkt_data, double timeout); - bool recv_async_msg(uhd::async_metadata_t &async_metadata, double timeout); - + + void poke32(wb_addr_type addr, boost::uint32_t data){ + boost::mutex::scoped_lock lock(_ctrl_mutex); + + ctrl_data_t words(2); + words[0] = data & 0x0000FFFF; + words[1] = data >> 16; + this->write(addr, words); + } + + boost::uint32_t peek32(wb_addr_type addr){ + boost::mutex::scoped_lock lock(_ctrl_mutex); + + ctrl_data_t words = this->read(addr, 2); + return boost::uint32_t((boost::uint32_t(words[1]) << 16) | words[0]); + } + + void poke16(wb_addr_type addr, boost::uint16_t data){ + boost::mutex::scoped_lock lock(_ctrl_mutex); + + ctrl_data_t words(1); + words[0] = data; + this->write(addr, words); + } + + boost::uint16_t peek16(wb_addr_type addr){ + boost::mutex::scoped_lock lock(_ctrl_mutex); + + ctrl_data_t words = this->read(addr, 1); + return boost::uint16_t(words[0]); + } + + void set_async_cb(const async_cb_type &async_cb){ + boost::mutex::scoped_lock lock(_async_mutex); + _async_cb = async_cb; + } + private: int send_pkt(boost::uint16_t *cmd); - + //änd hërë wë gö ä-Vïkïng för äsynchronous control packets - void viking_marauder_loop(boost::barrier &); + void viking_marauder_loop(void); bounded_buffer<ctrl_data_t> sync_ctrl_fifo; - bounded_buffer<async_metadata_t> async_msg_fifo; - boost::thread_group viking_marauders; - - uhd::transport::usb_zero_copy::sptr _ctrl_transport; + async_cb_type _async_cb; + task::sptr viking_marauder; + + uhd::transport::zero_copy_if::sptr _ctrl_transport; boost::uint8_t _seq; + boost::mutex _ctrl_mutex, _async_mutex; }; /*********************************************************************** @@ -86,7 +115,7 @@ void pack_ctrl_pkt(boost::uint16_t *pkt_buff, pkt_buff[1] = pkt.pkt_meta.len; pkt_buff[2] = (pkt.pkt_meta.addr & 0x00000FFF); pkt_buff[3] = 0x0000; //address high bits always 0 on this device - + for(size_t i = 0; i < pkt.data.size(); i++) { pkt_buff[4+i] = pkt.data[i]; } @@ -99,7 +128,7 @@ void unpack_ctrl_pkt(const boost::uint16_t *pkt_buff, pkt.pkt_meta.len = pkt_buff[1]; pkt.pkt_meta.callbacks = 0; //callbacks aren't implemented yet pkt.pkt_meta.addr = pkt_buff[2] | boost::uint32_t(pkt_buff[3] << 16); - + //let's check this so we don't go pushing 64K of crap onto the pkt if(pkt.pkt_meta.len > CTRL_PACKET_DATA_LENGTH) { throw uhd::runtime_error("Received control packet too long"); @@ -113,7 +142,7 @@ int b100_ctrl_impl::send_pkt(boost::uint16_t *cmd) { if(!sbuf.get()) { throw uhd::runtime_error("Control channel send error"); } - + //FIXME there's a better way to do this for(size_t i = 0; i < (CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)); i++) { sbuf->cast<boost::uint16_t *>()[i] = cmd[i]; @@ -132,7 +161,7 @@ int b100_ctrl_impl::write(boost::uint32_t addr, const ctrl_data_t &data) { pkt.pkt_meta.len = pkt.data.size(); pkt.pkt_meta.addr = addr; boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)]; - + pack_ctrl_pkt(pkt_buff, pkt); size_t result = send_pkt(pkt_buff); return result; @@ -149,11 +178,18 @@ ctrl_data_t b100_ctrl_impl::read(boost::uint32_t addr, size_t len) { pkt.pkt_meta.addr = addr; boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)]; + //flush anything that might be in the queue + while (get_ctrl_data(pkt.data, 0.0)){ + UHD_MSG(error) << "B100: control read found unexpected packet." << std::endl; + } + pack_ctrl_pkt(pkt_buff, pkt); send_pkt(pkt_buff); - - //loop around waiting for the response to appear - while(!get_ctrl_data(pkt.data, 0.05)); + + //block with timeout waiting for the response to appear + if (not get_ctrl_data(pkt.data, 0.1)) throw uhd::runtime_error( + "B100: timeout waiting for control response packet." + ); return pkt.data; } @@ -165,61 +201,40 @@ ctrl_data_t b100_ctrl_impl::read(boost::uint32_t addr, size_t len) { * never have more than 1 message in it, since it's expected that we'll * wait for a control operation to finish before starting another one. **********************************************************************/ -void b100_ctrl_impl::viking_marauder_loop(boost::barrier &spawn_barrier) { - spawn_barrier.wait(); +void b100_ctrl_impl::viking_marauder_loop(void){ set_thread_priority_safe(); - + while (not boost::this_thread::interruption_requested()){ - managed_recv_buffer::sptr rbuf = _ctrl_transport->get_recv_buff(); - if(!rbuf.get()) continue; //that's ok, there are plenty of villages to pillage! + managed_recv_buffer::sptr rbuf = _ctrl_transport->get_recv_buff(1.0); + if(rbuf.get() == NULL) continue; //that's ok, there are plenty of villages to pillage! const boost::uint16_t *pkt_buf = rbuf->cast<const boost::uint16_t *>(); - + if(pkt_buf[0] >> 8 == CTRL_PACKET_HEADER_MAGIC) { //so it's got a control packet header, let's parse it. ctrl_pkt_t pkt; unpack_ctrl_pkt(pkt_buf, pkt); - + if(pkt.pkt_meta.seq != boost::uint8_t(_seq - 1)) { - throw uhd::runtime_error("Sequence error on control channel"); + UHD_MSG(error) + << "Sequence error on control channel." << std::endl + << "Exiting control loop." << std::endl + ; + return; } if(pkt.pkt_meta.len > (CTRL_PACKET_LENGTH - CTRL_PACKET_HEADER_LENGTH)) { - throw uhd::runtime_error("Control channel packet length too long"); + UHD_MSG(error) + << "Control channel packet length too long" << std::endl + << "Exiting control loop." << std::endl + ; + return; } - + //push it onto the queue - sync_ctrl_fifo.push_with_wait(pkt.data); - } else { //it's an async status pkt - //extract the vrt header packet info - vrt::if_packet_info_t if_packet_info; - if_packet_info.num_packet_words32 = rbuf->size()/sizeof(boost::uint32_t); - const boost::uint32_t *vrt_hdr = rbuf->cast<const boost::uint32_t *>(); - vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info); - - if( if_packet_info.sid == 0 - and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ - //fill in the async metadata - async_metadata_t metadata; - metadata.channel = 0; - metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; - metadata.time_spec = time_spec_t( - time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), 64e6 //FIXME get from clock_ctrl - ); - metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); - //print the famous U, and push the metadata into the message queue - if (metadata.event_code & - ( async_metadata_t::EVENT_CODE_UNDERFLOW - | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) ) - UHD_MSG(fastpath) << "U"; - - if (metadata.event_code & - ( async_metadata_t::EVENT_CODE_SEQ_ERROR - | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) ) - UHD_MSG(fastpath) << "S"; - - async_msg_fifo.push_with_pop_on_full(metadata); - continue; - } - throw uhd::runtime_error("Control: unknown async response"); + sync_ctrl_fifo.push_with_pop_on_full(pkt.data); + } + else{ //otherwise let the async callback handle it + boost::mutex::scoped_lock lock(_async_mutex); + if (not _async_cb.empty()) _async_cb(rbuf); } } } @@ -229,14 +244,9 @@ bool b100_ctrl_impl::get_ctrl_data(ctrl_data_t &pkt_data, double timeout){ return sync_ctrl_fifo.pop_with_timed_wait(pkt_data, timeout); } -bool b100_ctrl_impl::recv_async_msg(uhd::async_metadata_t &async_metadata, double timeout) { - boost::this_thread::disable_interruption di; //disable because the wait can throw - return async_msg_fifo.pop_with_timed_wait(async_metadata, timeout); -} - /*********************************************************************** * Public make function for b100_ctrl interface **********************************************************************/ -b100_ctrl::sptr b100_ctrl::make(uhd::transport::usb_zero_copy::sptr ctrl_transport){ +b100_ctrl::sptr b100_ctrl::make(uhd::transport::zero_copy_if::sptr ctrl_transport){ return sptr(new b100_ctrl_impl(ctrl_transport)); } diff --git a/host/lib/usrp/b100/b100_ctrl.hpp b/host/lib/usrp/b100/b100_ctrl.hpp index ae706dbb4..74884d525 100644 --- a/host/lib/usrp/b100/b100_ctrl.hpp +++ b/host/lib/usrp/b100/b100_ctrl.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,25 +18,28 @@ #ifndef INCLUDED_B100_CTRL_HPP #define INCLUDED_B100_CTRL_HPP -#include <uhd/transport/bounded_buffer.hpp> +#include "wb_iface.hpp" #include <uhd/transport/usb_zero_copy.hpp> -#include <uhd/types/metadata.hpp> #include <uhd/types/serial.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> #include "ctrl_packet.hpp" -#include <boost/thread.hpp> +#include <boost/function.hpp> -class b100_ctrl : boost::noncopyable{ +class b100_ctrl : boost::noncopyable, public wb_iface{ public: typedef boost::shared_ptr<b100_ctrl> sptr; + typedef boost::function<void(uhd::transport::managed_recv_buffer::sptr)> async_cb_type; /*! * Make a USRP control object from a data transport * \param ctrl_transport a USB data transport * \return a new b100 control object */ - static sptr make(uhd::transport::usb_zero_copy::sptr ctrl_transport); + static sptr make(uhd::transport::zero_copy_if::sptr ctrl_transport); + + //! set an async callback for messages + virtual void set_async_cb(const async_cb_type &async_cb) = 0; /*! * Write a byte vector to an FPGA register @@ -61,9 +64,7 @@ public: * \return true if it got something */ virtual bool get_ctrl_data(ctrl_data_t &pkt_data, double timeout) = 0; - - virtual bool recv_async_msg(uhd::async_metadata_t &async_metadata, double timeout) = 0; - + }; #endif /* INCLUDED_B100_CTRL_HPP */ diff --git a/host/lib/usrp/b100/b100_iface.cpp b/host/lib/usrp/b100/b100_iface.cpp deleted file mode 100644 index 17ea2e6ad..000000000 --- a/host/lib/usrp/b100/b100_iface.cpp +++ /dev/null @@ -1,336 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "b100_iface.hpp" -#include "usrp_commands.h" -#include <uhd/exception.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/safe_call.hpp> -#include <uhd/utils/msg.hpp> -#include <boost/format.hpp> -#include <iomanip> -#include <iostream> - -//FOR TESTING ONLY -#include "b100_regs.hpp" -#include <boost/thread/thread.hpp> -#include "usrp_i2c_addr.h" - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::transport; - -/*********************************************************************** - * Constants - **********************************************************************/ -static const bool iface_debug = true; -static const boost::uint16_t USRP_B_FW_COMPAT_NUM = 0x02; -static const boost::uint16_t USRP_B_FPGA_COMPAT_NUM = 0x03; - -/*********************************************************************** - * I2C + FX2 implementation wrapper - **********************************************************************/ -class b100_i2c_fx2_iface : public i2c_iface{ -public: - b100_i2c_fx2_iface(uhd::usrp::fx2_ctrl::sptr fx2_ctrl){ - _fx2_ctrl = fx2_ctrl; - } - - void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) - { - UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes); - - unsigned char buff[max_i2c_data_bytes]; - std::copy(bytes.begin(), bytes.end(), buff); - - int ret = _fx2_ctrl->usrp_i2c_write(addr & 0xff, - buff, - bytes.size()); - - if (iface_debug && (ret < 0)) - uhd::runtime_error("USRP: failed i2c write"); - } - - byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes) - { - UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes); - - unsigned char buff[max_i2c_data_bytes]; - int ret = _fx2_ctrl->usrp_i2c_read(addr & 0xff, - buff, - num_bytes); - - if (iface_debug && ((ret < 0) || (unsigned)ret < (num_bytes))) - uhd::runtime_error("USRP: failed i2c read"); - - byte_vector_t out_bytes; - for (size_t i = 0; i < num_bytes; i++) - out_bytes.push_back(buff[i]); - - return out_bytes; - } - -private: - static const size_t max_i2c_data_bytes = 64; - uhd::usrp::fx2_ctrl::sptr _fx2_ctrl; -}; - -/*********************************************************************** - * USRP-E100 interface implementation - **********************************************************************/ -class b100_iface_impl : public b100_iface{ -public: - /******************************************************************* - * Structors - ******************************************************************/ - b100_iface_impl(uhd::usrp::fx2_ctrl::sptr fx2_ctrl, - b100_ctrl::sptr fpga_ctrl) : - _fx2_i2c_iface(fx2_ctrl), - _fx2_ctrl(fx2_ctrl), - _fpga_ctrl(fpga_ctrl) - { - this->check_fw_compat(); - if (fpga_ctrl.get() != NULL){ - enable_gpif(1); - i2c_init(); - this->check_fpga_compat(); - } - mb_eeprom = mboard_eeprom_t(get_fx2_i2c_iface(), mboard_eeprom_t::MAP_B000); - } - - void check_fw_compat(void){ - unsigned char data[4]; //useless data buffer - const boost::uint16_t fw_compat_num = _fx2_ctrl->usrp_control_read( - VRQ_FW_COMPAT, 0, 0, data, sizeof(data) - ); - if (fw_compat_num != USRP_B_FW_COMPAT_NUM){ - throw uhd::runtime_error(str(boost::format( - "Expected firmware compatibility number 0x%x, but got 0x%x:\n" - "The firmware build is not compatible with the host code build." - ) % USRP_B_FW_COMPAT_NUM % fw_compat_num)); - } - } - - void check_fpga_compat(void){ - const boost::uint16_t fpga_compat_num = this->peek16(B100_REG_MISC_COMPAT); - if (fpga_compat_num != USRP_B_FPGA_COMPAT_NUM){ - throw uhd::runtime_error(str(boost::format( - "Expected FPGA compatibility number 0x%x, but got 0x%x:\n" - "The FPGA build is not compatible with the host code build." - ) % USRP_B_FPGA_COMPAT_NUM % fpga_compat_num)); - } - } - - ~b100_iface_impl(void) - { - /* NOP */ - } - - /******************************************************************* - * Peek and Poke - ******************************************************************/ - - void poke(boost::uint32_t addr, const ctrl_data_t &data) { - boost::mutex::scoped_lock lock(_ctrl_mutex); - _fpga_ctrl->write(addr, data); - } - - ctrl_data_t peek(boost::uint32_t addr, size_t len) { - boost::mutex::scoped_lock lock(_ctrl_mutex); - return _fpga_ctrl->read(addr, len); - } - - void poke16(boost::uint32_t addr, boost::uint16_t value) - { - ctrl_data_t words(1); - words[0] = value; - poke(addr, words); - } - - void poke32(boost::uint32_t addr, boost::uint32_t value) - { - //just a subset of poke() to maintain compatibility - ctrl_data_t words(2); - words[0] = value & 0x0000FFFF; - words[1] = value >> 16; - poke(addr, words); - } - - boost::uint32_t peek32(boost::uint32_t addr) - { - ctrl_data_t words = peek(addr, 2); - return boost::uint32_t((boost::uint32_t(words[1]) << 16) | words[0]); - } - - boost::uint16_t peek16(boost::uint32_t addr) - { - ctrl_data_t words = peek(addr, 1); - return boost::uint16_t(words[0]); - } - - /******************************************************************* - * I2C - ******************************************************************/ - static const boost::uint32_t i2c_datarate = 400000; - static const boost::uint32_t wishbone_clk = 64000000; //FIXME should go somewhere else - - void i2c_init(void) { - //init I2C FPGA interface. - poke16(B100_REG_I2C_CTRL, 0x0000); - //set prescalers to operate at 400kHz: WB_CLK is 64MHz... - boost::uint16_t prescaler = wishbone_clk / (i2c_datarate*5) - 1; - poke16(B100_REG_I2C_PRESCALER_LO, prescaler & 0xFF); - poke16(B100_REG_I2C_PRESCALER_HI, (prescaler >> 8) & 0xFF); - poke16(B100_REG_I2C_CTRL, I2C_CTRL_EN); //enable I2C core - } - - static const size_t max_i2c_data_bytes = 64; - - void i2c_wait_for_xfer(void) - { - while(this->peek16(B100_REG_I2C_CMD_STATUS) & I2C_ST_TIP) - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); - } - - bool wait_chk_ack(void) { - i2c_wait_for_xfer(); - return (this->peek16(B100_REG_I2C_CMD_STATUS) & I2C_ST_RXACK) == 0; - } - - void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) - { - poke16(B100_REG_I2C_DATA, (addr << 1) | 0); //addr and read bit (0) - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0)); - - //wait for previous transfer to complete - if(!wait_chk_ack()) { - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_STOP); - return; - } - - for(size_t i = 0; i < bytes.size(); i++) { - poke16(B100_REG_I2C_DATA, bytes[i]); - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0)); - if(!wait_chk_ack()) { - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_STOP); - return; - } - } - } - - byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes) - { - byte_vector_t bytes; - if(num_bytes == 0) return bytes; - - while (peek16(B100_REG_I2C_CMD_STATUS) & I2C_ST_BUSY); - - poke16(B100_REG_I2C_DATA, (addr << 1) | 1); //addr and read bit (1) - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START); - //wait for previous transfer to complete - if(!wait_chk_ack()) { - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_STOP); - } - - for(; num_bytes > 0; num_bytes--) { - poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_RD | ((num_bytes == 1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0)); - i2c_wait_for_xfer(); - boost::uint8_t readback = peek16(B100_REG_I2C_DATA) & 0xFF; - bytes.push_back(readback); - } - return bytes; - } - - i2c_iface &get_fx2_i2c_iface(void){ - return _fx2_i2c_iface; - } - - /******************************************************************* - * SPI interface - * Eventually this will be replaced with a control-channel system - * to let the firmware do the actual write/readback cycles. - * This keeps the bandwidth on the control channel down. - ******************************************************************/ - - void spi_wait(void) { - while(peek32(B100_REG_SPI_CTRL) & SPI_CTRL_GO_BSY); - } - - boost::uint32_t transact_spi(int which_slave, - const spi_config_t &config, - boost::uint32_t bits, - size_t num_bits, - bool readback) - { - UHD_ASSERT_THROW((num_bits <= 32) && !(num_bits % 8)); - - int edge_flags = ((config.miso_edge==spi_config_t::EDGE_FALL) ? SPI_CTRL_RXNEG : 0) | - ((config.mosi_edge==spi_config_t::EDGE_FALL) ? 0 : SPI_CTRL_TXNEG) - ; - - boost::uint16_t ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & num_bits) | edge_flags; - - poke16(B100_REG_SPI_DIV, 0x0001); // = fpga_clk / 4 - poke32(B100_REG_SPI_SS, which_slave & 0xFFFF); - poke32(B100_REG_SPI_TXRX0, bits); - poke16(B100_REG_SPI_CTRL, ctrl); - - poke16(B100_REG_SPI_CTRL, ctrl | SPI_CTRL_GO_BSY); - if(readback) { - spi_wait(); - return peek32(B100_REG_SPI_TXRX0); - } - else { - return 0; - } - } - - void reset_gpif(boost::uint16_t ep) { - _fx2_ctrl->usrp_control_write(VRQ_RESET_GPIF, ep, ep, 0, 0); - } - - void enable_gpif(bool en) { - _fx2_ctrl->usrp_control_write(VRQ_ENABLE_GPIF, en ? 1 : 0, 0, 0, 0); - } - - void clear_fpga_fifo(void) { - _fx2_ctrl->usrp_control_write(VRQ_CLEAR_FPGA_FIFO, 0, 0, 0, 0); - } - - void write_uart(boost::uint8_t, const std::string &) { - throw uhd::not_implemented_error("Unhandled command write_uart()"); - } - - std::string read_uart(boost::uint8_t) { - throw uhd::not_implemented_error("Unhandled command read_uart()"); - } - -private: - b100_i2c_fx2_iface _fx2_i2c_iface; - uhd::usrp::fx2_ctrl::sptr _fx2_ctrl; - b100_ctrl::sptr _fpga_ctrl; - boost::mutex _ctrl_mutex; -}; - -/*********************************************************************** - * Public Make Function - **********************************************************************/ -b100_iface::sptr b100_iface::make(uhd::usrp::fx2_ctrl::sptr fx2_ctrl, - b100_ctrl::sptr fpga_ctrl) -{ - return b100_iface::sptr(new b100_iface_impl(fx2_ctrl, fpga_ctrl)); -} diff --git a/host/lib/usrp/b100/b100_iface.hpp b/host/lib/usrp/b100/b100_iface.hpp deleted file mode 100644 index 57ed6a45c..000000000 --- a/host/lib/usrp/b100/b100_iface.hpp +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_B100_IFACE_HPP -#define INCLUDED_B100_IFACE_HPP - -#include <uhd/usrp/mboard_iface.hpp> -#include <uhd/usrp/mboard_eeprom.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> -#include <uhd/transport/usb_zero_copy.hpp> -#include "../fx2/fx2_ctrl.hpp" -#include "b100_ctrl.hpp" - -/*! - * The usrp1 interface class: - * Provides a set of functions to implementation layer. - * Including spi, peek, poke, control... - */ -class b100_iface : boost::noncopyable, public uhd::usrp::mboard_iface{ -public: - typedef boost::shared_ptr<b100_iface> sptr; - - /*! - * Make a new b100 interface with the control transport. - * \param fx2_ctrl the usrp control object - * \param fpga_ctrl the FPGA interface control object - * \return a new usrp1 interface object - */ - static sptr make(uhd::usrp::fx2_ctrl::sptr fx2_ctrl, - b100_ctrl::sptr fpga_ctrl = b100_ctrl::sptr() - ); - - /*! - * Reset the GPIF interface on the FX2 - * \param which endpoint to reset - * \return - */ - virtual void reset_gpif(boost::uint16_t ep) = 0; - - /*! - * Clear the GPIF FIFOs on the FPGA - * \return - */ - virtual void clear_fpga_fifo(void) = 0; - - /*! - * Enable/disable the GPIF interfaces on the FX2 - * \return - */ - virtual void enable_gpif(bool en) = 0; - - //! Get access to the FX2 I2C interface - virtual uhd::i2c_iface &get_fx2_i2c_iface(void) = 0; - - uhd::usrp::mboard_eeprom_t mb_eeprom; -}; - -#endif /* INCLUDED_USRP1_IFACE_HPP */ diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp index 7e733ddd9..2e2421ed3 100644 --- a/host/lib/usrp/b100/b100_impl.cpp +++ b/host/lib/usrp/b100/b100_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,11 +18,10 @@ #include "b100_impl.hpp" #include "b100_ctrl.hpp" #include "fpga_regs_standard.h" -#include "usrp_spi_defs.h" +#include "usrp_i2c_addr.h" +#include "usrp_commands.h" #include <uhd/transport/usb_control.hpp> #include "ctrl_packet.hpp" -#include <uhd/usrp/device_props.hpp> -#include <uhd/usrp/mboard_props.hpp> #include <uhd/utils/msg.hpp> #include <uhd/exception.hpp> #include <uhd/utils/static.hpp> @@ -72,7 +71,7 @@ static device_addrs_t b100_find(const device_addr_t &hint) //extract the firmware path for the b100 std::string b100_fw_image; try{ - b100_fw_image = find_image_path(hint.get("fw", "usrp_b100_fw.ihx")); + b100_fw_image = find_image_path(hint.get("fw", B100_FW_FILE_NAME)); } catch(...){ UHD_MSG(warning) << boost::format( @@ -97,20 +96,19 @@ static device_addrs_t b100_find(const device_addr_t &hint) BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { device_addr_t new_addr; new_addr["type"] = "b100"; + new_addr["serial"] = handle->get_serial(); //Attempt to read the name from the EEPROM and perform filtering. - //This operation can throw due to compatibility mismatch. try{ usb_control::sptr control = usb_control::make(handle); - b100_iface::sptr iface = b100_iface::make(fx2_ctrl::make(control)); - new_addr["name"] = iface->mb_eeprom["name"]; - new_addr["serial"] = handle->get_serial(); + fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(control); + const mboard_eeprom_t mb_eeprom = mboard_eeprom_t(*fx2_ctrl, mboard_eeprom_t::MAP_B000); + new_addr["name"] = mb_eeprom["name"]; } catch(const uhd::exception &){ //set these values as empty string so the device may still be found //and the filter's below can still operate on the discovered device new_addr["name"] = ""; - new_addr["serial"] = ""; } //this is a found b100 when the hint serial and name match or blank @@ -129,10 +127,21 @@ static device_addrs_t b100_find(const device_addr_t &hint) * Make **********************************************************************/ static device::sptr b100_make(const device_addr_t &device_addr){ + return device::sptr(new b100_impl(device_addr)); +} + +UHD_STATIC_BLOCK(register_b100_device){ + device::register_device(&b100_find, &b100_make); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +b100_impl::b100_impl(const device_addr_t &device_addr){ //extract the FPGA path for the B100 std::string b100_fpga_image = find_image_path( - device_addr.has_key("fpga")? device_addr["fpga"] : "usrp_b100_fpga.bin" + device_addr.has_key("fpga")? device_addr["fpga"] : B100_FPGA_FILE_NAME ); //try to match the given device address with something on the USB bus @@ -151,8 +160,11 @@ static device::sptr b100_make(const device_addr_t &device_addr){ //create control objects and a data transport usb_control::sptr fx2_transport = usb_control::make(handle); - fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(fx2_transport); - fx2_ctrl->usrp_load_fpga(b100_fpga_image); + _fx2_ctrl = fx2_ctrl::make(fx2_transport); + this->check_fw_compat(); //check after making fx2 + //-- setup clock after making fx2 and before loading fpga --// + _clock_ctrl = b100_clock_ctrl::make(_fx2_ctrl, device_addr.cast<double>("master_clock_rate", B100_DEFAULT_TICK_RATE)); + _fx2_ctrl->usrp_load_fpga(b100_fpga_image); device_addr_t data_xport_args; data_xport_args["recv_frame_size"] = device_addr.get("recv_frame_size", "16384"); @@ -160,7 +172,7 @@ static device::sptr b100_make(const device_addr_t &device_addr){ data_xport_args["send_frame_size"] = device_addr.get("send_frame_size", "16384"); data_xport_args["num_send_frames"] = device_addr.get("num_send_frames", "16"); - usb_zero_copy::sptr data_transport = usb_zero_copy::make_wrapper( + _data_transport = usb_zero_copy::make_wrapper( usb_zero_copy::make( handle, // identifier 6, // IN endpoint @@ -176,105 +188,280 @@ static device::sptr b100_make(const device_addr_t &device_addr){ ctrl_xport_args["send_frame_size"] = boost::lexical_cast<std::string>(CTRL_PACKET_LENGTH); ctrl_xport_args["num_send_frames"] = "4"; - usb_zero_copy::sptr ctrl_transport = usb_zero_copy::make( + _ctrl_transport = usb_zero_copy::make( handle, 8, 4, ctrl_xport_args ); - const double master_clock_rate = device_addr.cast<double>("master_clock_rate", 64e6); - - - //create the b100 implementation guts - return device::sptr(new b100_impl(data_transport, ctrl_transport, fx2_ctrl, master_clock_rate)); -} - -UHD_STATIC_BLOCK(register_b100_device){ - device::register_device(&b100_find, &b100_make); -} - -/*********************************************************************** - * Structors - **********************************************************************/ -b100_impl::b100_impl(uhd::transport::usb_zero_copy::sptr data_transport, - uhd::transport::usb_zero_copy::sptr ctrl_transport, - uhd::usrp::fx2_ctrl::sptr fx2_ctrl, - const double master_clock_rate) - : _data_transport(data_transport), _fx2_ctrl(fx2_ctrl) -{ - //this is the handler object for FPGA control packets - _fpga_ctrl = b100_ctrl::make(ctrl_transport); - - _iface = b100_iface::make(_fx2_ctrl, _fpga_ctrl); - - //create clock interface - _clock_ctrl = b100_clock_ctrl::make(_iface, master_clock_rate); - - //create codec interface - _codec_ctrl = b100_codec_ctrl::make(_iface); + //////////////////////////////////////////////////////////////////// + // Create controller objects + //////////////////////////////////////////////////////////////////// + _fpga_ctrl = b100_ctrl::make(_ctrl_transport); + this->enable_gpif(true); //TODO best place to put this? + this->check_fpga_compat(); //check after making control + _fpga_i2c_ctrl = i2c_core_100::make(_fpga_ctrl, B100_REG_SLAVE(3)); + _fpga_spi_ctrl = spi_core_100::make(_fpga_ctrl, B100_REG_SLAVE(2)); + + //////////////////////////////////////////////////////////////////// + // Initialize the properties tree + //////////////////////////////////////////////////////////////////// + _tree = property_tree::make(); + _tree->create<std::string>("/name").set("B-Series Device"); + const property_tree::path_type mb_path = "/mboards/0"; + _tree->create<std::string>(mb_path / "name").set("B100 (B-Hundo)"); + _tree->create<std::string>(mb_path / "load_eeprom") + .subscribe(boost::bind(&fx2_ctrl::usrp_load_eeprom, _fx2_ctrl, _1)); + + //////////////////////////////////////////////////////////////////// + // setup the mboard eeprom + //////////////////////////////////////////////////////////////////// + const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, mboard_eeprom_t::MAP_B000); + _tree->create<mboard_eeprom_t>(mb_path / "eeprom") + .set(mb_eeprom) + .subscribe(boost::bind(&b100_impl::set_mb_eeprom, this, _1)); + + //////////////////////////////////////////////////////////////////// + // create clock control objects + //////////////////////////////////////////////////////////////////// + //^^^ clock created up top, just reg props here... ^^^ + _tree->create<double>(mb_path / "tick_rate") + .publish(boost::bind(&b100_clock_ctrl::get_fpga_clock_rate, _clock_ctrl)) + .subscribe(boost::bind(&b100_impl::update_tick_rate, this, _1)); + + //////////////////////////////////////////////////////////////////// + // create codec control objects + //////////////////////////////////////////////////////////////////// + _codec_ctrl = b100_codec_ctrl::make(_fpga_spi_ctrl); + const property_tree::path_type rx_codec_path = mb_path / "rx_codecs/A"; + const property_tree::path_type tx_codec_path = mb_path / "tx_codecs/A"; + _tree->create<std::string>(rx_codec_path / "name").set("ad9522"); + _tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(b100_codec_ctrl::rx_pga_gain_range); + _tree->create<double>(rx_codec_path / "gains/pga/value") + .coerce(boost::bind(&b100_impl::update_rx_codec_gain, this, _1)); + _tree->create<std::string>(tx_codec_path / "name").set("ad9522"); + _tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(b100_codec_ctrl::tx_pga_gain_range); + _tree->create<double>(tx_codec_path / "gains/pga/value") + .subscribe(boost::bind(&b100_codec_ctrl::set_tx_pga_gain, _codec_ctrl, _1)) + .publish(boost::bind(&b100_codec_ctrl::get_tx_pga_gain, _codec_ctrl)); + + //////////////////////////////////////////////////////////////////// + // and do the misc mboard sensors + //////////////////////////////////////////////////////////////////// + //none for now... + _tree->create<int>(mb_path / "sensors"); //phony property so this dir exists + + //////////////////////////////////////////////////////////////////// + // create frontend control objects + //////////////////////////////////////////////////////////////////// + _rx_fe = rx_frontend_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_FRONT)); + _tx_fe = tx_frontend_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TX_FRONT)); + //TODO lots of properties to expose here for frontends + _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec") + .subscribe(boost::bind(&b100_impl::update_rx_subdev_spec, this, _1)); + _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec") + .subscribe(boost::bind(&b100_impl::update_tx_subdev_spec, this, _1)); + + //////////////////////////////////////////////////////////////////// + // create rx dsp control objects + //////////////////////////////////////////////////////////////////// + _rx_dsps.push_back(rx_dsp_core_200::make( + _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_DSP0), B100_REG_SR_ADDR(B100_SR_RX_CTRL0), B100_RX_SID_BASE + 0 + )); + _rx_dsps.push_back(rx_dsp_core_200::make( + _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_DSP1), B100_REG_SR_ADDR(B100_SR_RX_CTRL1), B100_RX_SID_BASE + 1 + )); + for (size_t dspno = 0; dspno < _rx_dsps.size(); dspno++){ + _rx_dsps[dspno]->set_link_rate(B100_LINK_RATE_BPS); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _rx_dsps[dspno], _1)); + property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno); + _tree->create<double>(rx_dsp_path / "rate/value") + .coerce(boost::bind(&rx_dsp_core_200::set_host_rate, _rx_dsps[dspno], _1)) + .subscribe(boost::bind(&b100_impl::update_rx_samp_rate, this, _1)); + _tree->create<double>(rx_dsp_path / "freq/value") + .coerce(boost::bind(&rx_dsp_core_200::set_freq, _rx_dsps[dspno], _1)); + _tree->create<meta_range_t>(rx_dsp_path / "freq/range") + .publish(boost::bind(&rx_dsp_core_200::get_freq_range, _rx_dsps[dspno])); + _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd") + .subscribe(boost::bind(&rx_dsp_core_200::issue_stream_command, _rx_dsps[dspno], _1)); + } - //initialize the codecs - codec_init(); + //////////////////////////////////////////////////////////////////// + // create tx dsp control objects + //////////////////////////////////////////////////////////////////// + _tx_dsp = tx_dsp_core_200::make( + _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TX_DSP), B100_REG_SR_ADDR(B100_SR_TX_CTRL), B100_TX_ASYNC_SID + ); + _tx_dsp->set_link_rate(B100_LINK_RATE_BPS); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _tx_dsp, _1)); + _tree->create<double>(mb_path / "tx_dsps/0/rate/value") + .coerce(boost::bind(&tx_dsp_core_200::set_host_rate, _tx_dsp, _1)) + .subscribe(boost::bind(&b100_impl::update_tx_samp_rate, this, _1)); + _tree->create<double>(mb_path / "tx_dsps/0/freq/value") + .coerce(boost::bind(&tx_dsp_core_200::set_freq, _tx_dsp, _1)); + _tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range") + .publish(boost::bind(&tx_dsp_core_200::get_freq_range, _tx_dsp)); + + //////////////////////////////////////////////////////////////////// + // create time control objects + //////////////////////////////////////////////////////////////////// + time64_core_200::readback_bases_type time64_rb_bases; + time64_rb_bases.rb_secs_now = B100_REG_RB_TIME_NOW_SECS; + time64_rb_bases.rb_ticks_now = B100_REG_RB_TIME_NOW_TICKS; + time64_rb_bases.rb_secs_pps = B100_REG_RB_TIME_PPS_SECS; + time64_rb_bases.rb_ticks_pps = B100_REG_RB_TIME_PPS_TICKS; + _time64 = time64_core_200::make( + _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TIME64), time64_rb_bases + ); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&time64_core_200::set_tick_rate, _time64, _1)); + _tree->create<time_spec_t>(mb_path / "time/now") + .publish(boost::bind(&time64_core_200::get_time_now, _time64)) + .subscribe(boost::bind(&time64_core_200::set_time_now, _time64, _1)); + _tree->create<time_spec_t>(mb_path / "time/pps") + .publish(boost::bind(&time64_core_200::get_time_last_pps, _time64)) + .subscribe(boost::bind(&time64_core_200::set_time_next_pps, _time64, _1)); + //setup time source props + _tree->create<std::string>(mb_path / "time_source/value") + .subscribe(boost::bind(&time64_core_200::set_time_source, _time64, _1)); + _tree->create<std::vector<std::string> >(mb_path / "time_source/options") + .publish(boost::bind(&time64_core_200::get_time_sources, _time64)); + //setup reference source props + _tree->create<std::string>(mb_path / "clock_source/value") + .subscribe(boost::bind(&b100_impl::update_clock_source, this, _1)); + static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("auto"); + _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources); + + //////////////////////////////////////////////////////////////////// + // create dboard control objects + //////////////////////////////////////////////////////////////////// + + //read the dboard eeprom to extract the dboard ids + dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom; + rx_db_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_RX_A); + tx_db_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_A); + gdb_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_A ^ 5); + + //create the properties and register subscribers + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/rx_eeprom") + .set(rx_db_eeprom) + .subscribe(boost::bind(&b100_impl::set_db_eeprom, this, "rx", _1)); + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/tx_eeprom") + .set(tx_db_eeprom) + .subscribe(boost::bind(&b100_impl::set_db_eeprom, this, "tx", _1)); + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/gdb_eeprom") + .set(gdb_eeprom) + .subscribe(boost::bind(&b100_impl::set_db_eeprom, this, "gdb", _1)); + + //create a new dboard interface and manager + _dboard_iface = make_b100_dboard_iface(_fpga_ctrl, _fpga_i2c_ctrl, _fpga_spi_ctrl, _clock_ctrl, _codec_ctrl); + _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_dboard_iface); + _dboard_manager = dboard_manager::make( + rx_db_eeprom.id, + ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id, + _dboard_iface + ); + BOOST_FOREACH(const std::string &name, _dboard_manager->get_rx_subdev_names()){ + dboard_manager::populate_prop_tree_from_subdev( + _tree->subtree(mb_path / "dboards/A/rx_frontends" / name), + _dboard_manager->get_rx_subdev(name) + ); + } + BOOST_FOREACH(const std::string &name, _dboard_manager->get_tx_subdev_names()){ + dboard_manager::populate_prop_tree_from_subdev( + _tree->subtree(mb_path / "dboards/A/tx_frontends" / name), + _dboard_manager->get_tx_subdev(name) + ); + } - //initialize the mboard - mboard_init(); + //initialize io handling + this->io_init(); - //initialize the dboards - dboard_init(); + //////////////////////////////////////////////////////////////////// + // do some post-init tasks + //////////////////////////////////////////////////////////////////// + _tree->access<double>(mb_path / "tick_rate").update() //update and then subscribe the clock callback + .subscribe(boost::bind(&b100_clock_ctrl::set_fpga_clock_rate, _clock_ctrl, _1)); - //initialize the dsps - rx_ddc_init(); + //and now that the tick rate is set, init the host rates to something + BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "rx_dsps")){ + _tree->access<double>(mb_path / "rx_dsps" / name / "rate" / "value").set(1e6); + } + BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "tx_dsps")){ + _tree->access<double>(mb_path / "tx_dsps" / name / "rate" / "value").set(1e6); + } - //initialize the dsps - tx_duc_init(); + _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_rx_subdev_names()[0])); + _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_tx_subdev_names()[0])); + _tree->access<std::string>(mb_path / "clock_source/value").set("internal"); + _tree->access<std::string>(mb_path / "time_source/value").set("none"); +} - //init the subdev specs - this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t()); - this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t()); +b100_impl::~b100_impl(void){ + //set an empty async callback now that we deconstruct + _fpga_ctrl->set_async_cb(b100_ctrl::async_cb_type()); +} - //initialize the send/recv buffs - io_init(); +void b100_impl::check_fw_compat(void){ + unsigned char data[4]; //useless data buffer + const boost::uint16_t fw_compat_num = _fx2_ctrl->usrp_control_read( + VRQ_FW_COMPAT, 0, 0, data, sizeof(data) + ); + if (fw_compat_num != B100_FW_COMPAT_NUM){ + throw uhd::runtime_error(str(boost::format( + "Expected firmware compatibility number 0x%x, but got 0x%x:\n" + "The firmware build is not compatible with the host code build." + ) % B100_FW_COMPAT_NUM % fw_compat_num)); + } } -b100_impl::~b100_impl(void){ - /* NOP */ +void b100_impl::check_fpga_compat(void){ + const boost::uint16_t fpga_compat_num = _fpga_ctrl->peek16(B100_REG_MISC_COMPAT); + if (fpga_compat_num != B100_FPGA_COMPAT_NUM){ + throw uhd::runtime_error(str(boost::format( + "Expected FPGA compatibility number 0x%x, but got 0x%x:\n" + "The FPGA build is not compatible with the host code build." + ) % B100_FPGA_COMPAT_NUM % fpga_compat_num)); + } } -bool b100_impl::recv_async_msg(uhd::async_metadata_t &md, double timeout){ - return _fpga_ctrl->recv_async_msg(md, timeout); +double b100_impl::update_rx_codec_gain(const double gain){ + //set gain on both I and Q, readback on one + //TODO in the future, gains should have individual control + _codec_ctrl->set_rx_pga_gain(gain, 'A'); + _codec_ctrl->set_rx_pga_gain(gain, 'B'); + return _codec_ctrl->get_rx_pga_gain('A'); } -/*********************************************************************** - * Device Get - **********************************************************************/ -void b100_impl::get(const wax::obj &key_, wax::obj &val) -{ - named_prop_t key = named_prop_t::extract(key_); +void b100_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){ + mb_eeprom.commit(*_fx2_ctrl, mboard_eeprom_t::MAP_B000); +} - //handle the get request conditioned on the key - switch(key.as<device_prop_t>()){ - case DEVICE_PROP_NAME: - val = std::string("USRP-B100 device"); - return; +void b100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){ + if (type == "rx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_RX_A); + if (type == "tx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_A); + if (type == "gdb") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_A ^ 5); +} - case DEVICE_PROP_MBOARD: - UHD_ASSERT_THROW(key.name == ""); - val = _mboard_proxy->get_link(); - return; +void b100_impl::update_clock_source(const std::string &source){ + if (source == "auto") _clock_ctrl->use_auto_ref(); + else if (source == "internal") _clock_ctrl->use_internal_ref(); + else if (source == "external") _clock_ctrl->use_external_ref(); + else throw uhd::runtime_error("unhandled clock configuration reference source: " + source); +} - case DEVICE_PROP_MBOARD_NAMES: - val = prop_names_t(1, ""); //vector of size 1 with empty string - return; +////////////////// some GPIF preparation related stuff ///////////////// +void b100_impl::reset_gpif(const boost::uint16_t ep) { + _fx2_ctrl->usrp_control_write(VRQ_RESET_GPIF, ep, ep, 0, 0); +} - default: UHD_THROW_PROP_GET_ERROR(); - } +void b100_impl::enable_gpif(const bool en) { + _fx2_ctrl->usrp_control_write(VRQ_ENABLE_GPIF, en ? 1 : 0, 0, 0, 0); } -/*********************************************************************** - * Device Set - **********************************************************************/ -void b100_impl::set(const wax::obj &, const wax::obj &) -{ - UHD_THROW_PROP_SET_ERROR(); +void b100_impl::clear_fpga_fifo(void) { + _fx2_ctrl->usrp_control_write(VRQ_CLEAR_FPGA_FIFO, 0, 0, 0, 0); } diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp index daec70bca..62a22674e 100644 --- a/host/lib/usrp/b100/b100_impl.hpp +++ b/host/lib/usrp/b100/b100_impl.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -15,74 +15,56 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include "b100_iface.hpp" +#ifndef INCLUDED_B100_IMPL_HPP +#define INCLUDED_B100_IMPL_HPP + +#include "fx2_ctrl.hpp" #include "b100_ctrl.hpp" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" +#include "spi_core_100.hpp" +#include "i2c_core_100.hpp" +#include "rx_frontend_core_200.hpp" +#include "tx_frontend_core_200.hpp" +#include "rx_dsp_core_200.hpp" +#include "tx_dsp_core_200.hpp" +#include "time64_core_200.hpp" #include <uhd/device.hpp> +#include <uhd/property_tree.hpp> #include <uhd/utils/pimpl.hpp> #include <uhd/types/dict.hpp> #include <uhd/types/otw_type.hpp> #include <uhd/types/clock_config.hpp> #include <uhd/types/stream_cmd.hpp> -#include <uhd/usrp/dboard_id.hpp> +#include <uhd/usrp/mboard_eeprom.hpp> #include <uhd/usrp/subdev_spec.hpp> #include <uhd/usrp/dboard_eeprom.hpp> #include <uhd/usrp/dboard_manager.hpp> #include <uhd/transport/usb_zero_copy.hpp> -#ifndef INCLUDED_B100_IMPL_HPP -#define INCLUDED_B100_IMPL_HPP +static const double B100_LINK_RATE_BPS = 256e6/8; //pratical link rate (< 480 Mbps) +static const std::string B100_FW_FILE_NAME = "usrp_b100_fw.ihx"; +static const std::string B100_FPGA_FILE_NAME = "usrp_b100_fpga.bin"; +static const boost::uint16_t B100_FW_COMPAT_NUM = 0x02; +static const boost::uint16_t B100_FPGA_COMPAT_NUM = 0x05; +static const boost::uint32_t B100_RX_SID_BASE = 2; +static const boost::uint32_t B100_TX_ASYNC_SID = 1; +static const double B100_DEFAULT_TICK_RATE = 64e6; -/*! - * Make a b100 dboard interface. - * \param iface the b100 interface object - * \param clock the clock control interface - * \param codec the codec control interface - * \return a sptr to a new dboard interface - */ +//! Make a b100 dboard interface uhd::usrp::dboard_iface::sptr make_b100_dboard_iface( - b100_iface::sptr iface, + wb_iface::sptr wb_iface, + uhd::i2c_iface::sptr i2c_iface, + uhd::spi_iface::sptr spi_iface, b100_clock_ctrl::sptr clock, b100_codec_ctrl::sptr codec ); -/*! - * Simple wax obj proxy class: - * Provides a wax obj interface for a set and a get function. - * This allows us to create nested properties structures - * while maintaining flattened code within the implementation. - */ -class wax_obj_proxy : public wax::obj { -public: - typedef boost::function<void(const wax::obj &, wax::obj &)> get_t; - typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t; - typedef boost::shared_ptr<wax_obj_proxy> sptr; - - static sptr make(const get_t &get, const set_t &set){ - return sptr(new wax_obj_proxy(get, set)); - } - -private: - get_t _get; set_t _set; - wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set) {}; - void get(const wax::obj &key, wax::obj &val) {return _get(key, val);} - void set(const wax::obj &key, const wax::obj &val) {return _set(key, val);} -}; - -/*! - * USRP1 implementation guts: - * The implementation details are encapsulated here. - * Handles properties on the mboard, dboard, dsps... - */ +//! Implementation guts class b100_impl : public uhd::device { public: //structors - b100_impl(uhd::transport::usb_zero_copy::sptr data_transport, - uhd::transport::usb_zero_copy::sptr ctrl_transport, - uhd::usrp::fx2_ctrl::sptr fx2_ctrl, - double master_clock_rate); - + b100_impl(const uhd::device_addr_t &); ~b100_impl(void); //the io interface @@ -91,114 +73,62 @@ public: const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double); - size_t recv(const recv_buffs_type &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double); - size_t get_max_send_samps_per_packet(void) const; - size_t get_max_recv_samps_per_packet(void) const; - bool recv_async_msg(uhd::async_metadata_t &, double); private: - //clock control + uhd::property_tree::sptr _tree; + + //controllers + spi_core_100::sptr _fpga_spi_ctrl; + i2c_core_100::sptr _fpga_i2c_ctrl; + rx_frontend_core_200::sptr _rx_fe; + tx_frontend_core_200::sptr _tx_fe; + std::vector<rx_dsp_core_200::sptr> _rx_dsps; + tx_dsp_core_200::sptr _tx_dsp; + time64_core_200::sptr _time64; b100_clock_ctrl::sptr _clock_ctrl; - - //interface to ioctls and file descriptor - b100_iface::sptr _iface; - - //handle io stuff - uhd::transport::zero_copy_if::sptr _data_transport; - UHD_PIMPL_DECL(io_impl) _io_impl; - void update_transport_channel_mapping(void); - void io_init(void); - void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd); - void handle_overrun(size_t); - - //otw types - uhd::otw_type_t _recv_otw_type; - uhd::otw_type_t _send_otw_type; - - //configuration shadows - uhd::clock_config_t _clock_config; - uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec; - - //ad9862 codec control interface b100_codec_ctrl::sptr _codec_ctrl; + b100_ctrl::sptr _fpga_ctrl; + uhd::usrp::fx2_ctrl::sptr _fx2_ctrl; - //codec properties interfaces - void codec_init(void); - void rx_codec_get(const wax::obj &, wax::obj &); - void rx_codec_set(const wax::obj &, const wax::obj &); - void tx_codec_get(const wax::obj &, wax::obj &); - void tx_codec_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _rx_codec_proxy, _tx_codec_proxy; - - //device functions and settings - void get(const wax::obj &, wax::obj &); - void set(const wax::obj &, const wax::obj &); - - //mboard functions and settings - void mboard_init(void); - void mboard_get(const wax::obj &, wax::obj &); - void mboard_set(const wax::obj &, const wax::obj &); - void update_clock_config(void); - wax_obj_proxy::sptr _mboard_proxy; - - /*! - * Make a usrp1 dboard interface. - * \param iface the usrp1 interface object - * \param clock the clock control interface - * \param codec the codec control interface - * \param dboard_slot the slot identifier - * \param rx_dboard_id the db id for the rx board (used for evil dbsrx purposes) - * \return a sptr to a new dboard interface - */ - static uhd::usrp::dboard_iface::sptr make_dboard_iface( - b100_iface::sptr iface, - b100_clock_ctrl::sptr clock, - b100_codec_ctrl::sptr codec, - const uhd::usrp::dboard_id_t &rx_dboard_id - ); + //transports + uhd::transport::zero_copy_if::sptr _data_transport, _ctrl_transport; - //xx dboard functions and settings - void dboard_init(void); + //dboard stuff uhd::usrp::dboard_manager::sptr _dboard_manager; uhd::usrp::dboard_iface::sptr _dboard_iface; - //rx dboard functions and settings - uhd::usrp::dboard_eeprom_t _rx_db_eeprom; - void rx_dboard_get(const wax::obj &, wax::obj &); - void rx_dboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _rx_dboard_proxy; - - //tx dboard functions and settings - uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom; - void tx_dboard_get(const wax::obj &, wax::obj &); - void tx_dboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _tx_dboard_proxy; - - //rx ddc functions and settings - void rx_ddc_init(void); - void rx_ddc_get(const wax::obj &, wax::obj &); - void rx_ddc_set(const wax::obj &, const wax::obj &); - double _ddc_freq; size_t _ddc_decim; - wax_obj_proxy::sptr _rx_ddc_proxy; - - //tx duc functions and settings - void tx_duc_init(void); - void tx_duc_get(const wax::obj &, wax::obj &); - void tx_duc_set(const wax::obj &, const wax::obj &); - double _duc_freq; size_t _duc_interp; - wax_obj_proxy::sptr _tx_duc_proxy; + //handle io stuff + uhd::otw_type_t _rx_otw_type, _tx_otw_type; + UHD_PIMPL_DECL(io_impl) _io_impl; + void io_init(void); - //transports - b100_ctrl::sptr _fpga_ctrl; - uhd::usrp::fx2_ctrl::sptr _fx2_ctrl; + //device properties interface + void get(const wax::obj &, wax::obj &val){ + val = _tree; //entry point into property tree + } + void check_fw_compat(void); + void check_fpga_compat(void); + double update_rx_codec_gain(const double); //sets A and B at once + void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &); + void set_db_eeprom(const std::string &, const uhd::usrp::dboard_eeprom_t &); + void update_tick_rate(const double rate); + void update_rx_samp_rate(const double rate); + void update_tx_samp_rate(const double rate); + void update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &); + void update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &); + void update_clock_source(const std::string &); + void reset_gpif(const boost::uint16_t); + void enable_gpif(const bool); + void clear_fpga_fifo(void); + void handle_async_message(uhd::transport::managed_recv_buffer::sptr); }; #endif /* INCLUDED_b100_IMPL_HPP */ diff --git a/host/lib/usrp/b100/b100_regs.hpp b/host/lib/usrp/b100/b100_regs.hpp index 010df283e..5e24f9937 100644 --- a/host/lib/usrp/b100/b100_regs.hpp +++ b/host/lib/usrp/b100/b100_regs.hpp @@ -10,14 +10,13 @@ // This means that address bit 0 is usually 0. // There are 11 bits of address for the control. -#ifndef __B100_REGS_H -#define __B100_REGS_H +#ifndef INCLUDED_B100_REGS_HPP +#define INCLUDED_B100_REGS_HPP ///////////////////////////////////////////////////// // Slave pointers #define B100_REG_SLAVE(n) ((n)<<7) -#define B100_REG_SR_ADDR(n) ((B100_REG_SETTINGS_BASE) + (4*(n))) ///////////////////////////////////////////////////// // Slave 0 -- Misc Regs @@ -51,64 +50,16 @@ //these are 32-bit registers mapped onto the 16-bit Wishbone bus. //Using peek32/poke32 should allow transparent use of these registers. #define B100_REG_SPI_BASE B100_REG_SLAVE(2) -#define B100_REG_SPI_TXRX0 B100_REG_SPI_BASE + 0 -#define B100_REG_SPI_TXRX1 B100_REG_SPI_BASE + 4 -#define B100_REG_SPI_TXRX2 B100_REG_SPI_BASE + 8 -#define B100_REG_SPI_TXRX3 B100_REG_SPI_BASE + 12 -#define B100_REG_SPI_CTRL B100_REG_SPI_BASE + 16 -#define B100_REG_SPI_DIV B100_REG_SPI_BASE + 20 -#define B100_REG_SPI_SS B100_REG_SPI_BASE + 24 //spi slave constants #define B100_SPI_SS_AD9862 (1 << 2) #define B100_SPI_SS_TX_DB (1 << 1) #define B100_SPI_SS_RX_DB (1 << 0) -//spi ctrl register bit definitions -#define SPI_CTRL_ASS (1<<13) -#define SPI_CTRL_IE (1<<12) -#define SPI_CTRL_LSB (1<<11) -#define SPI_CTRL_TXNEG (1<<10) //mosi edge, push on falling edge when 1 -#define SPI_CTRL_RXNEG (1<< 9) //miso edge, latch on falling edge when 1 -#define SPI_CTRL_GO_BSY (1<< 8) -#define SPI_CTRL_CHAR_LEN_MASK 0x7F - //////////////////////////////////////////////// // Slave 3 -- I2C Core #define B100_REG_I2C_BASE B100_REG_SLAVE(3) -#define B100_REG_I2C_PRESCALER_LO B100_REG_I2C_BASE + 0 -#define B100_REG_I2C_PRESCALER_HI B100_REG_I2C_BASE + 2 -#define B100_REG_I2C_CTRL B100_REG_I2C_BASE + 4 -#define B100_REG_I2C_DATA B100_REG_I2C_BASE + 6 -#define B100_REG_I2C_CMD_STATUS B100_REG_I2C_BASE + 8 - -//and while we're here... - -// -// STA, STO, RD, WR, and IACK bits are cleared automatically -// - -#define I2C_CTRL_EN (1 << 7) // core enable -#define I2C_CTRL_IE (1 << 6) // interrupt enable - -#define I2C_CMD_START (1 << 7) // generate (repeated) start condition -#define I2C_CMD_STOP (1 << 6) // generate stop condition -#define I2C_CMD_RD (1 << 5) // read from slave -#define I2C_CMD_WR (1 << 4) // write to slave -#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1) -#define I2C_CMD_RSVD_2 (1 << 2) // reserved -#define I2C_CMD_RSVD_1 (1 << 1) // reserved -#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt - -#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK) -#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected -#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration -#define I2C_ST_RSVD_4 (1 << 4) // reserved -#define I2C_ST_RSVD_3 (1 << 3) // reserved -#define I2C_ST_RSVD_2 (1 << 2) // reserved -#define I2C_ST_TIP (1 << 1) // Transfer-in-progress -#define I2C_ST_IP (1 << 0) // Interrupt pending //////////////////////////////////////////////// // Slave 4 -- GPIO @@ -164,101 +115,33 @@ // Output-only, no readback, 64 registers total // Each register must be written 32 bits at a time // First the address xxx_xx00 and then xxx_xx10 +// 64 total regs in address space +#define B100_SR_RX_CTRL0 0 // 9 regs (+0 to +8) +#define B100_SR_RX_DSP0 10 // 4 regs (+0 to +3) +#define B100_SR_RX_CTRL1 16 // 9 regs (+0 to +8) +#define B100_SR_RX_DSP1 26 // 4 regs (+0 to +3) +#define B100_SR_TX_CTRL 32 // 4 regs (+0 to +3) +#define B100_SR_TX_DSP 38 // 3 regs (+0 to +2) -#define B100_REG_SETTINGS_BASE_ADDR(n) (B100_REG_SLAVE(8) + (4*(n))) - -#define B100_REG_SR_MISC_TEST32 B100_REG_SETTINGS_BASE_ADDR(52) +#define B100_SR_TIME64 42 // 6 regs (+0 to +5) +#define B100_SR_RX_FRONT 48 // 5 regs (+0 to +4) +#define B100_SR_TX_FRONT 54 // 5 regs (+0 to +4) -///////////////////////////////////////////////// -// DSP RX Regs -//////////////////////////////////////////////// -#define B100_REG_DSP_RX_ADDR(n) (B100_REG_SETTINGS_BASE_ADDR(16) + (4*(n))) -#define B100_REG_DSP_RX_FREQ B100_REG_DSP_RX_ADDR(0) -#define B100_REG_DSP_RX_SCALE_IQ B100_REG_DSP_RX_ADDR(1) // {scale_i,scale_q} -#define B100_REG_DSP_RX_DECIM_RATE B100_REG_DSP_RX_ADDR(2) // hb and decim rate -#define B100_REG_DSP_RX_DCOFFSET_I B100_REG_DSP_RX_ADDR(3) // Bit 31 high sets fixed offset mode, using lower 14 bits, // otherwise it is automatic -#define B100_REG_DSP_RX_DCOFFSET_Q B100_REG_DSP_RX_ADDR(4) // Bit 31 high sets fixed offset mode, using lower 14 bits -#define B100_REG_DSP_RX_MUX B100_REG_DSP_RX_ADDR(5) +#define B100_SR_REG_TEST32 60 // 1 reg +#define B100_SR_CLEAR_RX_FIFO 61 // 1 reg +#define B100_SR_CLEAR_TX_FIFO 62 // 1 reg +#define B100_SR_GLOBAL_RESET 63 // 1 reg -/////////////////////////////////////////////////// -// VITA RX CTRL regs -/////////////////////////////////////////////////// -// The following 3 are logically a single command register. -// They are clocked into the underlying fifo when time_ticks is written. -#define B100_REG_CTRL_RX_ADDR(n) (B100_REG_SETTINGS_BASE_ADDR(0) + (4*(n))) -#define B100_REG_CTRL_RX_STREAM_CMD B100_REG_CTRL_RX_ADDR(0) // {now, chain, num_samples(30) -#define B100_REG_CTRL_RX_TIME_SECS B100_REG_CTRL_RX_ADDR(1) -#define B100_REG_CTRL_RX_TIME_TICKS B100_REG_CTRL_RX_ADDR(2) -#define B100_REG_CTRL_RX_CLEAR_OVERRUN B100_REG_CTRL_RX_ADDR(3) // write anything to clear overrun -#define B100_REG_CTRL_RX_VRT_HEADER B100_REG_CTRL_RX_ADDR(4) // word 0 of packet. FPGA fills in packet counter -#define B100_REG_CTRL_RX_VRT_STREAM_ID B100_REG_CTRL_RX_ADDR(5) // word 1 of packet. -#define B100_REG_CTRL_RX_VRT_TRAILER B100_REG_CTRL_RX_ADDR(6) -#define B100_REG_CTRL_RX_NSAMPS_PER_PKT B100_REG_CTRL_RX_ADDR(7) -#define B100_REG_CTRL_RX_NCHANNELS B100_REG_CTRL_RX_ADDR(8) // 1 in basic case, up to 4 for vector sources - -///////////////////////////////////////////////// -// DSP TX Regs -//////////////////////////////////////////////// -#define B100_REG_DSP_TX_ADDR(n) (B100_REG_SETTINGS_BASE_ADDR(32) + (4*(n))) -#define B100_REG_DSP_TX_FREQ B100_REG_DSP_TX_ADDR(0) -#define B100_REG_DSP_TX_SCALE_IQ B100_REG_DSP_TX_ADDR(1) // {scale_i,scale_q} -#define B100_REG_DSP_TX_INTERP_RATE B100_REG_DSP_TX_ADDR(2) -#define B100_REG_DSP_TX_UNUSED B100_REG_DSP_TX_ADDR(3) -#define B100_REG_DSP_TX_MUX B100_REG_DSP_TX_ADDR(4) - -///////////////////////////////////////////////// -// VITA TX CTRL regs -//////////////////////////////////////////////// -#define B100_REG_CTRL_TX_ADDR(n) (B100_REG_SETTINGS_BASE_ADDR(24) + (4*(n))) -#define B100_REG_CTRL_TX_NCHANNELS B100_REG_CTRL_TX_ADDR(0) -#define B100_REG_CTRL_TX_CLEAR_UNDERRUN B100_REG_CTRL_TX_ADDR(1) -#define B100_REG_CTRL_TX_REPORT_SID B100_REG_CTRL_TX_ADDR(2) -#define B100_REG_CTRL_TX_POLICY B100_REG_CTRL_TX_ADDR(3) +#define B100_REG_SR_ADDR(n) (B100_REG_SLAVE(8) + (4*(n))) -#define B100_FLAG_CTRL_TX_POLICY_WAIT (0x1 << 0) -#define B100_FLAG_CTRL_TX_POLICY_NEXT_PACKET (0x1 << 1) -#define B100_FLAG_CTRL_TX_POLICY_NEXT_BURST (0x1 << 2) +#define B100_REG_SR_MISC_TEST32 B100_REG_SR_ADDR(B100_SR_REG_TEST32) ///////////////////////////////////////////////// -// VITA49 64 bit time (write only) +// Magic reset regs //////////////////////////////////////////////// - /*! - * \brief Time 64 flags - * - * <pre> - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-----------------------------------------------------------+-+-+ - * | |S|P| - * +-----------------------------------------------------------+-+-+ - * - * P - PPS edge selection (0=negedge, 1=posedge, default=0) - * S - Source (0=sma, 1=mimo, 0=default) - * - * </pre> - */ -#define B100_REG_TIME64_ADDR(n) (B100_REG_SETTINGS_BASE_ADDR(40) + (4*(n))) -#define B100_REG_TIME64_SECS B100_REG_TIME64_ADDR(0) // value to set absolute secs to on next PPS -#define B100_REG_TIME64_TICKS B100_REG_TIME64_ADDR(1) // value to set absolute ticks to on next PPS -#define B100_REG_TIME64_FLAGS B100_REG_TIME64_ADDR(2) // flags - see chart above -#define B100_REG_TIME64_IMM B100_REG_TIME64_ADDR(3) // set immediate (0=latch on next pps, 1=latch immediate, default=0) -#define B100_REG_TIME64_TPS B100_REG_TIME64_ADDR(4) // clock ticks per second (counter rollover) - -//pps flags (see above) -#define B100_FLAG_TIME64_PPS_NEGEDGE (0 << 0) -#define B100_FLAG_TIME64_PPS_POSEDGE (1 << 0) -#define B100_FLAG_TIME64_PPS_SMA (0 << 1) -#define B100_FLAG_TIME64_PPS_MIMO (1 << 1) - -#define B100_FLAG_TIME64_LATCH_NOW 1 -#define B100_FLAG_TIME64_LATCH_NEXT_PPS 0 - -#define B100_REG_CLEAR_RX_FIFO B100_REG_SETTINGS_BASE_ADDR(48) -#define B100_REG_CLEAR_TX_FIFO B100_REG_SETTINGS_BASE_ADDR(49) - -#define B100_REG_GLOBAL_RESET B100_REG_SETTINGS_BASE_ADDR(50) -#define B100_REG_TEST32 B100_REG_SETTINGS_BASE_ADDR(52) +#define B100_REG_CLEAR_RX B100_REG_SR_ADDR(B100_SR_CLEAR_RX_FIFO) +#define B100_REG_CLEAR_TX B100_REG_SR_ADDR(B100_SR_CLEAR_RX_FIFO) +#define B100_REG_GLOBAL_RESET B100_REG_SR_ADDR(B100_SR_GLOBAL_RESET) #endif diff --git a/host/lib/usrp/b100/clock_ctrl.cpp b/host/lib/usrp/b100/clock_ctrl.cpp index e138242d1..c93ff64c7 100644 --- a/host/lib/usrp/b100/clock_ctrl.cpp +++ b/host/lib/usrp/b100/clock_ctrl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -169,11 +169,17 @@ static clock_settings_type get_clock_settings(double rate){ **********************************************************************/ class b100_clock_ctrl_impl : public b100_clock_ctrl{ public: - b100_clock_ctrl_impl(b100_iface::sptr iface, double master_clock_rate){ + b100_clock_ctrl_impl(i2c_iface::sptr iface, double master_clock_rate){ _iface = iface; _chan_rate = 0.0; _out_rate = 0.0; + //perform soft-reset + _ad9522_regs.soft_reset = 1; + this->send_reg(0x000); + this->latch_regs(); + _ad9522_regs.soft_reset = 0; + //init the clock gen registers _ad9522_regs.sdo_active = ad9522_regs_t::SDO_ACTIVE_SDO_SDIO; _ad9522_regs.enb_stat_eeprom_at_stat_pin = 0; //use status pin @@ -294,7 +300,6 @@ public: //clock rate changed! update dboard clocks and FPGA ticks per second set_rx_dboard_clock_rate(rate); set_tx_dboard_clock_rate(rate); - _iface->poke32(B100_REG_TIME64_TPS, boost::uint32_t(get_fpga_clock_rate())); } double get_fpga_clock_rate(void){ @@ -428,7 +433,7 @@ public: } private: - b100_iface::sptr _iface; + i2c_iface::sptr _iface; ad9522_regs_t _ad9522_regs; double _out_rate; //rate at the fpga and codec double _chan_rate; //rate before final dividers @@ -447,16 +452,16 @@ private: buf.push_back(boost::uint8_t(reg >> 8)); buf.push_back(boost::uint8_t(reg & 0xff)); - _iface->get_fx2_i2c_iface().write_i2c(0x5C, buf); + _iface->write_i2c(0x5C, buf); } boost::uint8_t read_reg(boost::uint16_t addr){ byte_vector_t buf; buf.push_back(boost::uint8_t(addr >> 8)); buf.push_back(boost::uint8_t(addr & 0xff)); - _iface->get_fx2_i2c_iface().write_i2c(0x5C, buf); + _iface->write_i2c(0x5C, buf); - buf = _iface->get_fx2_i2c_iface().read_i2c(0x5C, 1); + buf = _iface->read_i2c(0x5C, 1); return boost::uint32_t(buf[0] & 0xFF); } @@ -520,6 +525,6 @@ private: /*********************************************************************** * Clock Control Make **********************************************************************/ -b100_clock_ctrl::sptr b100_clock_ctrl::make(b100_iface::sptr iface, double master_clock_rate){ +b100_clock_ctrl::sptr b100_clock_ctrl::make(i2c_iface::sptr iface, double master_clock_rate){ return sptr(new b100_clock_ctrl_impl(iface, master_clock_rate)); } diff --git a/host/lib/usrp/b100/clock_ctrl.hpp b/host/lib/usrp/b100/clock_ctrl.hpp index 2a2e74024..5ef231281 100644 --- a/host/lib/usrp/b100/clock_ctrl.hpp +++ b/host/lib/usrp/b100/clock_ctrl.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ #ifndef INCLUDED_B100_CLOCK_CTRL_HPP #define INCLUDED_B100_CLOCK_CTRL_HPP -#include "b100_iface.hpp" +#include <uhd/types/serial.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> #include <vector> @@ -34,11 +34,11 @@ public: /*! * Make a new clock control object. - * \param iface the b100 iface object + * \param iface the controller iface object * \param master_clock_rate the master FPGA/sample clock rate * \return the clock control object */ - static sptr make(b100_iface::sptr iface, double master_clock_rate); + static sptr make(uhd::i2c_iface::sptr iface, double master_clock_rate); /*! * Set the rate of the fpga clock line. diff --git a/host/lib/usrp/b100/codec_ctrl.cpp b/host/lib/usrp/b100/codec_ctrl.cpp index 4d118b68b..4f9036039 100644 --- a/host/lib/usrp/b100/codec_ctrl.cpp +++ b/host/lib/usrp/b100/codec_ctrl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -39,7 +39,7 @@ const gain_range_t b100_codec_ctrl::rx_pga_gain_range(0, 20, 1); class b100_codec_ctrl_impl : public b100_codec_ctrl{ public: //structors - b100_codec_ctrl_impl(b100_iface::sptr iface); + b100_codec_ctrl_impl(spi_iface::sptr iface); ~b100_codec_ctrl_impl(void); //aux adc and dac control @@ -53,7 +53,7 @@ public: double get_rx_pga_gain(char); private: - b100_iface::sptr _iface; + spi_iface::sptr _iface; ad9862_regs_t _ad9862_regs; void send_reg(boost::uint8_t addr); void recv_reg(boost::uint8_t addr); @@ -62,7 +62,7 @@ private: /*********************************************************************** * Codec Control Structors **********************************************************************/ -b100_codec_ctrl_impl::b100_codec_ctrl_impl(b100_iface::sptr iface){ +b100_codec_ctrl_impl::b100_codec_ctrl_impl(spi_iface::sptr iface){ _iface = iface; //soft reset @@ -278,6 +278,6 @@ void b100_codec_ctrl_impl::recv_reg(boost::uint8_t addr){ /*********************************************************************** * Codec Control Make **********************************************************************/ -b100_codec_ctrl::sptr b100_codec_ctrl::make(b100_iface::sptr iface){ +b100_codec_ctrl::sptr b100_codec_ctrl::make(spi_iface::sptr iface){ return sptr(new b100_codec_ctrl_impl(iface)); } diff --git a/host/lib/usrp/b100/codec_ctrl.hpp b/host/lib/usrp/b100/codec_ctrl.hpp index 1bd579190..1f7bdef09 100644 --- a/host/lib/usrp/b100/codec_ctrl.hpp +++ b/host/lib/usrp/b100/codec_ctrl.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ #ifndef INCLUDED_B100_CODEC_CTRL_HPP #define INCLUDED_B100_CODEC_CTRL_HPP -#include "b100_iface.hpp" +#include <uhd/types/serial.hpp> #include <uhd/types/ranges.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> @@ -40,7 +40,7 @@ public: * \param iface the usrp_e iface object * \return the codec control object */ - static sptr make(b100_iface::sptr iface); + static sptr make(uhd::spi_iface::sptr iface); //! aux adc identifier constants enum aux_adc_t{ diff --git a/host/lib/usrp/b100/codec_impl.cpp b/host/lib/usrp/b100/codec_impl.cpp deleted file mode 100644 index de3ca3a66..000000000 --- a/host/lib/usrp/b100/codec_impl.cpp +++ /dev/null @@ -1,149 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "b100_impl.hpp" -#include <uhd/exception.hpp> -#include <uhd/usrp/codec_props.hpp> -#include <boost/bind.hpp> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Helper Methods - **********************************************************************/ -void b100_impl::codec_init(void){ - //make proxies - _rx_codec_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::rx_codec_get, this, _1, _2), - boost::bind(&b100_impl::rx_codec_set, this, _1, _2) - ); - _tx_codec_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::tx_codec_get, this, _1, _2), - boost::bind(&b100_impl::tx_codec_set, this, _1, _2) - ); -} - -/*********************************************************************** - * RX Codec Properties - **********************************************************************/ -static const std::string ad9862_pga_gain_name = "ad9862 pga"; - -void b100_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_NAME: - val = std::string("b100 adc - ad9522"); - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - val = prop_names_t(1, ad9862_pga_gain_name); - return; - - case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = b100_codec_ctrl::rx_pga_gain_range; - return; - - case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_rx_pga_gain('A'); - return; - - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_rx_pga_gain('B'); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void b100_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the set request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'A'); - return; - - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'B'); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX Codec Properties - **********************************************************************/ -void b100_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_NAME: - val = std::string("b100 dac - ad9522"); - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - val = prop_names_t(1, ad9862_pga_gain_name); - return; - - case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = b100_codec_ctrl::tx_pga_gain_range; - return; - - case CODEC_PROP_GAIN_I: //only one gain for I and Q - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_tx_pga_gain(); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void b100_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the set request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_GAIN_I: //only one gain for I and Q - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_tx_pga_gain(val.as<double>()); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/b100/ctrl_packet.hpp b/host/lib/usrp/b100/ctrl_packet.hpp index f504fc5aa..bab1f0de1 100644 --- a/host/lib/usrp/b100/ctrl_packet.hpp +++ b/host/lib/usrp/b100/ctrl_packet.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/host/lib/usrp/b100/dboard_iface.cpp b/host/lib/usrp/b100/dboard_iface.cpp index ec3da6220..33c4b355d 100644 --- a/host/lib/usrp/b100/dboard_iface.cpp +++ b/host/lib/usrp/b100/dboard_iface.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -15,7 +15,8 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include "b100_iface.hpp" +#include "wb_iface.hpp" +#include <uhd/types/serial.hpp> #include "b100_regs.hpp" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" @@ -33,11 +34,15 @@ class b100_dboard_iface : public dboard_iface{ public: b100_dboard_iface( - b100_iface::sptr iface, + wb_iface::sptr wb_iface, + i2c_iface::sptr i2c_iface, + spi_iface::sptr spi_iface, b100_clock_ctrl::sptr clock, b100_codec_ctrl::sptr codec ){ - _iface = iface; + _wb_iface = wb_iface; + _i2c_iface = i2c_iface; + _spi_iface = spi_iface; _clock = clock; _codec = codec; @@ -45,8 +50,8 @@ public: this->set_clock_rate(UNIT_RX, _clock->get_fpga_clock_rate()); this->set_clock_rate(UNIT_TX, _clock->get_fpga_clock_rate()); - _iface->poke16(B100_REG_GPIO_RX_DBG, 0); - _iface->poke16(B100_REG_GPIO_TX_DBG, 0); + _wb_iface->poke16(B100_REG_GPIO_RX_DBG, 0); + _wb_iface->poke16(B100_REG_GPIO_TX_DBG, 0); } ~b100_dboard_iface(void){ @@ -94,7 +99,9 @@ public: double get_codec_rate(unit_t); private: - b100_iface::sptr _iface; + wb_iface::sptr _wb_iface; + i2c_iface::sptr _i2c_iface; + spi_iface::sptr _spi_iface; b100_clock_ctrl::sptr _clock; b100_codec_ctrl::sptr _codec; uhd::dict<unit_t, double> _clock_rates; @@ -104,11 +111,13 @@ private: * Make Function **********************************************************************/ dboard_iface::sptr make_b100_dboard_iface( - b100_iface::sptr iface, + wb_iface::sptr wb_iface, + i2c_iface::sptr i2c_iface, + spi_iface::sptr spi_iface, b100_clock_ctrl::sptr clock, b100_codec_ctrl::sptr codec ){ - return dboard_iface::sptr(new b100_dboard_iface(iface, clock, codec)); + return dboard_iface::sptr(new b100_dboard_iface(wb_iface, i2c_iface, spi_iface, clock, codec)); } /*********************************************************************** @@ -151,29 +160,29 @@ double b100_dboard_iface::get_codec_rate(unit_t){ void b100_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){ UHD_ASSERT_THROW(GPIO_SEL_ATR == 1); //make this assumption switch(unit){ - case UNIT_RX: _iface->poke16(B100_REG_GPIO_RX_SEL, value); return; - case UNIT_TX: _iface->poke16(B100_REG_GPIO_TX_SEL, value); return; + case UNIT_RX: _wb_iface->poke16(B100_REG_GPIO_RX_SEL, value); return; + case UNIT_TX: _wb_iface->poke16(B100_REG_GPIO_TX_SEL, value); return; } } void b100_dboard_iface::_set_gpio_ddr(unit_t unit, boost::uint16_t value){ switch(unit){ - case UNIT_RX: _iface->poke16(B100_REG_GPIO_RX_DDR, value); return; - case UNIT_TX: _iface->poke16(B100_REG_GPIO_TX_DDR, value); return; + case UNIT_RX: _wb_iface->poke16(B100_REG_GPIO_RX_DDR, value); return; + case UNIT_TX: _wb_iface->poke16(B100_REG_GPIO_TX_DDR, value); return; } } void b100_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){ switch(unit){ - case UNIT_RX: _iface->poke16(B100_REG_GPIO_RX_IO, value); return; - case UNIT_TX: _iface->poke16(B100_REG_GPIO_TX_IO, value); return; + case UNIT_RX: _wb_iface->poke16(B100_REG_GPIO_RX_IO, value); return; + case UNIT_TX: _wb_iface->poke16(B100_REG_GPIO_TX_IO, value); return; } } boost::uint16_t b100_dboard_iface::read_gpio(unit_t unit){ switch(unit){ - case UNIT_RX: return _iface->peek16(B100_REG_GPIO_RX_IO); - case UNIT_TX: return _iface->peek16(B100_REG_GPIO_TX_IO); + case UNIT_RX: return _wb_iface->peek16(B100_REG_GPIO_RX_IO); + case UNIT_TX: return _wb_iface->peek16(B100_REG_GPIO_TX_IO); default: UHD_THROW_INVALID_CODE_PATH(); } } @@ -196,7 +205,7 @@ void b100_dboard_iface::_set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t (ATR_REG_FULL_DUPLEX, B100_REG_ATR_FULL_TXSIDE) ) ; - _iface->poke16(unit_to_atr_to_addr[unit][atr], value); + _wb_iface->poke16(unit_to_atr_to_addr[unit][atr], value); } void b100_dboard_iface::set_gpio_debug(unit_t unit, int which){ @@ -211,13 +220,13 @@ void b100_dboard_iface::set_gpio_debug(unit_t unit, int which){ //set the debug on and which debug selection switch(unit){ case UNIT_RX: - _iface->poke16(B100_REG_GPIO_RX_DBG, 0xffff); - _iface->poke16(B100_REG_GPIO_RX_SEL, dbg_sels); + _wb_iface->poke16(B100_REG_GPIO_RX_DBG, 0xffff); + _wb_iface->poke16(B100_REG_GPIO_RX_SEL, dbg_sels); return; case UNIT_TX: - _iface->poke16(B100_REG_GPIO_TX_DBG, 0xffff); - _iface->poke16(B100_REG_GPIO_TX_SEL, dbg_sels); + _wb_iface->poke16(B100_REG_GPIO_TX_DBG, 0xffff); + _wb_iface->poke16(B100_REG_GPIO_TX_SEL, dbg_sels); return; } } @@ -244,7 +253,7 @@ void b100_dboard_iface::write_spi( boost::uint32_t data, size_t num_bits ){ - _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, false /*no rb*/); + _spi_iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, false /*no rb*/); } boost::uint32_t b100_dboard_iface::read_write_spi( @@ -253,18 +262,18 @@ boost::uint32_t b100_dboard_iface::read_write_spi( boost::uint32_t data, size_t num_bits ){ - return _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, true /*rb*/); + return _spi_iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, true /*rb*/); } /*********************************************************************** * I2C **********************************************************************/ void b100_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ - return _iface->write_i2c(addr, bytes); + return _i2c_iface->write_i2c(addr, bytes); } byte_vector_t b100_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ - return _iface->read_i2c(addr, num_bytes); + return _i2c_iface->read_i2c(addr, num_bytes); } /*********************************************************************** diff --git a/host/lib/usrp/b100/dboard_impl.cpp b/host/lib/usrp/b100/dboard_impl.cpp deleted file mode 100644 index ba3776728..000000000 --- a/host/lib/usrp/b100/dboard_impl.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "b100_impl.hpp" -#include "b100_regs.hpp" -#include <uhd/exception.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/usrp/misc_utils.hpp> -#include <boost/bind.hpp> -#include "usrp_i2c_addr.h" - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Dboard Initialization - **********************************************************************/ -void b100_impl::dboard_init(void){ - //read the tx and rx dboard eeproms - _rx_db_eeprom.load(*_iface, I2C_ADDR_RX_A); - _tx_db_eeprom.load(*_iface, I2C_ADDR_TX_A); - _gdb_eeprom.load(*_iface, I2C_ADDR_TX_A ^ 5); - - //create a new dboard interface and manager - _dboard_iface = make_b100_dboard_iface( - _iface, _clock_ctrl, _codec_ctrl - ); - _dboard_manager = dboard_manager::make( - _rx_db_eeprom.id, - ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id, - _dboard_iface - ); - - //setup the dboard proxies - _rx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::rx_dboard_get, this, _1, _2), - boost::bind(&b100_impl::rx_dboard_set, this, _1, _2) - ); - _tx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::tx_dboard_get, this, _1, _2), - boost::bind(&b100_impl::tx_dboard_set, this, _1, _2) - ); -} - -/*********************************************************************** - * RX Dboard Get - **********************************************************************/ -void b100_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_NAME: - val = std::string("b100 dboard (rx unit)"); - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_rx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_rx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _rx_db_eeprom; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; - return; - - case DBOARD_PROP_CODEC: - val = _rx_codec_proxy->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _rx_db_eeprom.id, - _dboard_manager->get_rx_subdev(key.name), - _rx_codec_proxy->get_link(), - GAIN_GROUP_POLICY_RX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * RX Dboard Set - **********************************************************************/ -void b100_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_DBOARD_EEPROM: - _rx_db_eeprom = val.as<dboard_eeprom_t>(); - _rx_db_eeprom.store(*_iface, I2C_ADDR_RX_A); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX Dboard Get - **********************************************************************/ -void b100_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_NAME: - val = std::string("b100 dboard (tx unit)"); - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_tx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_tx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _tx_db_eeprom; - return; - - case DBOARD_PROP_GBOARD_EEPROM: - val = _gdb_eeprom; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; - return; - - case DBOARD_PROP_CODEC: - val = _tx_codec_proxy->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _tx_db_eeprom.id, - _dboard_manager->get_tx_subdev(key.name), - _tx_codec_proxy->get_link(), - GAIN_GROUP_POLICY_TX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * TX Dboard Set - **********************************************************************/ -void b100_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_DBOARD_EEPROM: - _tx_db_eeprom = val.as<dboard_eeprom_t>(); - _tx_db_eeprom.store(*_iface, I2C_ADDR_TX_A); - return; - - case DBOARD_PROP_GBOARD_EEPROM: - _gdb_eeprom = val.as<dboard_eeprom_t>(); - _gdb_eeprom.store(*_iface, I2C_ADDR_TX_A ^ 5); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/b100/dsp_impl.cpp b/host/lib/usrp/b100/dsp_impl.cpp deleted file mode 100644 index c1bf6bedd..000000000 --- a/host/lib/usrp/b100/dsp_impl.cpp +++ /dev/null @@ -1,189 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "b100_impl.hpp" -#include "b100_regs.hpp" -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/dsp_props.hpp> -#include <boost/math/special_functions/round.hpp> -#include <boost/bind.hpp> - -#define rint boost::math::iround - -using namespace uhd; -using namespace uhd::usrp; - -static const double MASTER_CLOCK_RATE = 64e6; //TODO get from clock control - -/*********************************************************************** - * RX DDC Initialization - **********************************************************************/ -void b100_impl::rx_ddc_init(void){ - _rx_ddc_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::rx_ddc_get, this, _1, _2), - boost::bind(&b100_impl::rx_ddc_set, this, _1, _2) - ); - - //initial config and update - rx_ddc_set(DSP_PROP_FREQ_SHIFT, double(0)); - rx_ddc_set(DSP_PROP_HOST_RATE, double(16e6)); -} - -/*********************************************************************** - * RX DDC Get - **********************************************************************/ -void b100_impl::rx_ddc_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_NAME: - val = std::string("USRP-B100 RX DSP"); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); //empty - return; - - case DSP_PROP_FREQ_SHIFT: - val = _ddc_freq; - return; - - case DSP_PROP_CODEC_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_fpga_clock_rate()/_ddc_decim; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * RX DDC Set - **********************************************************************/ -void b100_impl::rx_ddc_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_STREAM_CMD: - issue_stream_cmd(val.as<stream_cmd_t>()); - return; - - case DSP_PROP_FREQ_SHIFT:{ - double new_freq = val.as<double>(); - _iface->poke32(B100_REG_DSP_RX_FREQ, - dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate()) - ); - _ddc_freq = new_freq; //shadow - } - return; - - case DSP_PROP_HOST_RATE:{ - //set the decimation - _ddc_decim = rint(_clock_ctrl->get_fpga_clock_rate()/val.as<double>()); - _iface->poke32(B100_REG_DSP_RX_DECIM_RATE, dsp_type1::calc_cic_filter_word(_ddc_decim)); - - //set the scaling - static const boost::int16_t default_rx_scale_iq = 1024; - _iface->poke32(B100_REG_DSP_RX_SCALE_IQ, - dsp_type1::calc_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq) - ); - } - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX DUC Initialization - **********************************************************************/ -void b100_impl::tx_duc_init(void){ - _tx_duc_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::tx_duc_get, this, _1, _2), - boost::bind(&b100_impl::tx_duc_set, this, _1, _2) - ); - - //initial config and update - tx_duc_set(DSP_PROP_FREQ_SHIFT, double(0)); - tx_duc_set(DSP_PROP_HOST_RATE, double(16e6)); -} - -/*********************************************************************** - * TX DUC Get - **********************************************************************/ -void b100_impl::tx_duc_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_NAME: - val = std::string("USRP-B100 TX DSP"); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); //empty - return; - - case DSP_PROP_FREQ_SHIFT: - val = _duc_freq; - return; - - case DSP_PROP_CODEC_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_fpga_clock_rate()/_duc_interp; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * TX DUC Set - **********************************************************************/ -void b100_impl::tx_duc_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - - case DSP_PROP_FREQ_SHIFT:{ - double new_freq = val.as<double>(); - _iface->poke32(B100_REG_DSP_TX_FREQ, - dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate()) - ); - _duc_freq = new_freq; //shadow - } - return; - - case DSP_PROP_HOST_RATE:{ - _duc_interp = rint(_clock_ctrl->get_fpga_clock_rate()/val.as<double>()); - - //set the interpolation - _iface->poke32(B100_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_duc_interp)); - - //set the scaling - _iface->poke32(B100_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_duc_interp)); - } - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/b100/io_impl.cpp b/host/lib/usrp/b100/io_impl.cpp index 3978bea75..d841188c0 100644 --- a/host/lib/usrp/b100/io_impl.cpp +++ b/host/lib/usrp/b100/io_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -15,132 +15,192 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include "recv_packet_demuxer.hpp" +#include "validate_subdev_spec.hpp" #include "../../transport/super_recv_packet_handler.hpp" #include "../../transport/super_send_packet_handler.hpp" #include "usrp_commands.h" #include "b100_impl.hpp" #include "b100_regs.hpp" -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/dsp_props.hpp> #include <uhd/utils/thread_priority.hpp> #include <uhd/transport/bounded_buffer.hpp> #include <boost/bind.hpp> #include <boost/format.hpp> -#include <boost/asio.hpp> #include <boost/bind.hpp> #include <boost/thread.hpp> #include <uhd/utils/msg.hpp> #include <uhd/utils/log.hpp> -#include <iostream> using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; -namespace asio = boost::asio; /*********************************************************************** * IO Implementation Details **********************************************************************/ struct b100_impl::io_impl{ - io_impl(zero_copy_if::sptr data_transport): - data_transport(data_transport) - { - /* NOP */ - } - - ~io_impl(void){ - //drain the rx buffs - //while(data_transport->get_recv_buff().get() != NULL){ - /* NOP */ - //} - } - - zero_copy_if::sptr &data_transport; + io_impl(void): + async_msg_fifo(100/*messages deep*/) + { /* NOP */ } + zero_copy_if::sptr data_transport; + bounded_buffer<async_metadata_t> async_msg_fifo; + recv_packet_demuxer::sptr demuxer; sph::recv_packet_handler recv_handler; sph::send_packet_handler send_handler; - bool continuous_streaming; }; /*********************************************************************** * Initialize internals within this file **********************************************************************/ void b100_impl::io_init(void){ - _recv_otw_type.width = 16; - _recv_otw_type.shift = 0; - _recv_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - - _send_otw_type.width = 16; - _send_otw_type.shift = 0; - _send_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - - _iface->reset_gpif(6); - - //reset state machines - _iface->poke32(B100_REG_CTRL_TX_CLEAR_UNDERRUN, 0); - _iface->poke32(B100_REG_CTRL_RX_CLEAR_OVERRUN, 0); - - _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); - - //setup rx data path - _iface->poke32(B100_REG_CTRL_RX_NSAMPS_PER_PKT, get_max_recv_samps_per_packet()); - UHD_LOGV(always) << "IO: Using " << get_max_recv_samps_per_packet() << " samples per packet" << std::endl; - _iface->poke32(B100_REG_CTRL_RX_NCHANNELS, 1); - _iface->poke32(B100_REG_CTRL_RX_VRT_HEADER, 0 - | (0x1 << 28) //if data with stream id - | (0x1 << 26) //has trailer - | (0x3 << 22) //integer time other - | (0x1 << 20) //fractional time sample count - ); - _iface->poke32(B100_REG_CTRL_RX_VRT_TRAILER, 0); - //set the streamid to reset the seq num - _iface->poke32(B100_REG_CTRL_TX_REPORT_SID, 0); - //setup the tx policy - _iface->poke32(B100_REG_CTRL_TX_POLICY, B100_FLAG_CTRL_TX_POLICY_NEXT_PACKET); - + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN; + + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN; + + //TODO best place to put this? + this->reset_gpif(6); + //set the expected packet size in USB frames - _iface->poke32(B100_REG_MISC_RX_LEN, 4); + _fpga_ctrl->poke32(B100_REG_MISC_RX_LEN, 4); + + //create new io impl + _io_impl = UHD_PIMPL_MAKE(io_impl, ()); + _io_impl->demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), B100_RX_SID_BASE); + + //now its safe to register the async callback + _fpga_ctrl->set_async_cb(boost::bind(&b100_impl::handle_async_message, this, _1)); + + //init some handler stuff + _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le); + _io_impl->recv_handler.set_converter(_rx_otw_type); + _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le); + _io_impl->send_handler.set_converter(_tx_otw_type); + _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); +} + +void b100_impl::handle_async_message(managed_recv_buffer::sptr rbuf){ + vrt::if_packet_info_t if_packet_info; + if_packet_info.num_packet_words32 = rbuf->size()/sizeof(boost::uint32_t); + const boost::uint32_t *vrt_hdr = rbuf->cast<const boost::uint32_t *>(); + try{ + vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info); + } + catch(const std::exception &e){ + UHD_MSG(error) << "Error (handle_async_message): " << e.what() << std::endl; + } - update_transport_channel_mapping(); + if (if_packet_info.sid == B100_TX_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ + //fill in the async metadata + async_metadata_t metadata; + metadata.channel = 0; + metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; + metadata.time_spec = time_spec_t( + time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), _clock_ctrl->get_fpga_clock_rate() + ); + metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); + _io_impl->async_msg_fifo.push_with_pop_on_full(metadata); + if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_UNDERFLOW + | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) + ) UHD_MSG(fastpath) << "U"; + else if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_SEQ_ERROR + | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) + ) UHD_MSG(fastpath) << "S"; + } + else UHD_MSG(error) << "Unknown async packet" << std::endl; } -void b100_impl::update_transport_channel_mapping(void){ - if (_io_impl.get() == NULL) return; //not inited yet +void b100_impl::update_tick_rate(const double rate){ + boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); + _io_impl->recv_handler.set_tick_rate(rate); + boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); + _io_impl->send_handler.set_tick_rate(rate); +} - //set all of the relevant properties on the handler +void b100_impl::update_rx_samp_rate(const double rate){ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); - _io_impl->recv_handler.resize(_rx_subdev_spec.size()); - _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le); - _io_impl->recv_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate()); - _io_impl->recv_handler.set_samp_rate(_rx_ddc_proxy->get_link()[DSP_PROP_HOST_RATE].as<double>()); - for (size_t chan = 0; chan < _io_impl->recv_handler.size(); chan++){ - _io_impl->recv_handler.set_xport_chan_get_buff(chan, boost::bind( - &uhd::transport::zero_copy_if::get_recv_buff, _io_impl->data_transport, _1 - )); - _io_impl->recv_handler.set_overflow_handler(chan, boost::bind( - &b100_impl::handle_overrun, this, chan + _io_impl->recv_handler.set_samp_rate(rate); + const double adj = _rx_dsps.front()->get_scaling_adjustment(); + _io_impl->recv_handler.set_scale_factor(adj/32767.); +} + +void b100_impl::update_tx_samp_rate(const double rate){ + boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); + _io_impl->send_handler.set_samp_rate(rate); +} + +void b100_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ + boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); + property_tree::path_type root = "/mboards/0/dboards"; + + //sanity checking + validate_subdev_spec(_tree, spec, "rx"); + + //setup mux for this spec + bool fe_swapped = false; + for (size_t i = 0; i < spec.size(); i++){ + const std::string conn = _tree->access<std::string>(root / spec[i].db_name / "rx_frontends" / spec[i].sd_name / "connection").get(); + if (i == 0 and (conn == "QI" or conn == "Q")) fe_swapped = true; + _rx_dsps[i]->set_mux(conn, fe_swapped); + } + _rx_fe->set_mux(fe_swapped); + + //resize for the new occupancy + _io_impl->recv_handler.resize(spec.size()); + + //bind new callbacks for the handler + for (size_t i = 0; i < _io_impl->recv_handler.size(); i++){ + _rx_dsps[i]->set_nsamps_per_packet(get_max_recv_samps_per_packet()); //seems to be a good place to set this + _io_impl->recv_handler.set_xport_chan_get_buff(i, boost::bind( + &recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, i, _1 )); + _io_impl->recv_handler.set_overflow_handler(i, boost::bind(&rx_dsp_core_200::handle_overflow, _rx_dsps[i])); } - _io_impl->recv_handler.set_converter(_recv_otw_type); +} - //set all of the relevant properties on the handler +void b100_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); - _io_impl->send_handler.resize(_tx_subdev_spec.size()); - _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le); - _io_impl->send_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate()); - _io_impl->send_handler.set_samp_rate(_tx_duc_proxy->get_link()[DSP_PROP_HOST_RATE].as<double>()); - for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){ - _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind( - &uhd::transport::zero_copy_if::get_send_buff, _io_impl->data_transport, _1 + property_tree::path_type root = "/mboards/0/dboards"; + + //sanity checking + validate_subdev_spec(_tree, spec, "tx"); + + //set the mux for this spec + const std::string conn = _tree->access<std::string>(root / spec[0].db_name / "tx_frontends" / spec[0].sd_name / "connection").get(); + _tx_fe->set_mux(conn); + + //resize for the new occupancy + _io_impl->send_handler.resize(spec.size()); + + //bind new callbacks for the handler + for (size_t i = 0; i < _io_impl->send_handler.size(); i++){ + _io_impl->send_handler.set_xport_chan_get_buff(i, boost::bind( + &zero_copy_if::get_send_buff, _data_transport, _1 )); } - _io_impl->send_handler.set_converter(_send_otw_type); - _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); } /*********************************************************************** - * Data send + helper functions + * Async Data + **********************************************************************/ +bool b100_impl::recv_async_msg( + async_metadata_t &async_metadata, double timeout +){ + boost::this_thread::disable_interruption di; //disable because the wait can throw + return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout); +} + +/*********************************************************************** + * Send Data **********************************************************************/ size_t b100_impl::get_max_send_samps_per_packet(void) const { static const size_t hdr_size = 0 @@ -148,14 +208,14 @@ size_t b100_impl::get_max_send_samps_per_packet(void) const { - sizeof(vrt::if_packet_info_t().cid) //no class id ever used ; static const size_t bpp = 2048 - hdr_size; - return bpp / _send_otw_type.get_sample_size(); + return bpp / _tx_otw_type.get_sample_size(); } size_t b100_impl::send( const send_buffs_type &buffs, size_t nsamps_per_buff, const tx_metadata_t &metadata, const io_type_t &io_type, send_mode_t send_mode, double timeout -){ +){ return _io_impl->send_handler.send( buffs, nsamps_per_buff, metadata, io_type, @@ -164,9 +224,8 @@ size_t b100_impl::send( } /*********************************************************************** - * Data recv + helper functions + * Receive Data **********************************************************************/ - size_t b100_impl::get_max_recv_samps_per_packet(void) const { static const size_t hdr_size = 0 + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) @@ -174,7 +233,7 @@ size_t b100_impl::get_max_recv_samps_per_packet(void) const { - sizeof(vrt::if_packet_info_t().cid) //no class id ever used ; size_t bpp = 2048 - hdr_size; //limited by FPGA pkt buffer size - return bpp/_recv_otw_type.get_sample_size(); + return bpp/_rx_otw_type.get_sample_size(); } size_t b100_impl::recv( @@ -188,23 +247,3 @@ size_t b100_impl::recv( recv_mode, timeout ); } - -void b100_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd) -{ - _io_impl->continuous_streaming = (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - _iface->poke32(B100_REG_CTRL_RX_STREAM_CMD, dsp_type1::calc_stream_cmd_word(stream_cmd)); - _iface->poke32(B100_REG_CTRL_RX_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs())); - _iface->poke32(B100_REG_CTRL_RX_TIME_TICKS, stream_cmd.time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate())); - - if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) { - while(_io_impl->data_transport->get_recv_buff().get() != NULL){ - /* NOP */ - } - } -} - -void b100_impl::handle_overrun(size_t){ - if (_io_impl->continuous_streaming){ - this->issue_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - } -} diff --git a/host/lib/usrp/b100/mboard_impl.cpp b/host/lib/usrp/b100/mboard_impl.cpp deleted file mode 100644 index c651ff2a2..000000000 --- a/host/lib/usrp/b100/mboard_impl.cpp +++ /dev/null @@ -1,246 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "b100_impl.hpp" -#include "usrp_commands.h" -#include "fpga_regs_standard.h" -#include "fpga_regs_common.h" -#include "b100_regs.hpp" -#include "usrp_i2c_addr.h" -#include <uhd/usrp/misc_utils.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/utils/msg.hpp> -#include <uhd/exception.hpp> -#include <uhd/utils/images.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/foreach.hpp> -#include <boost/bind.hpp> -#include <boost/thread/thread.hpp> -#include <uhd/usrp/dsp_utils.hpp> - -using namespace uhd; -using namespace uhd::usrp; - -static const bool b100_mboard_verbose = true; - -/*********************************************************************** - * Mboard Initialization - **********************************************************************/ -void b100_impl::mboard_init(void) -{ - _mboard_proxy = wax_obj_proxy::make( - boost::bind(&b100_impl::mboard_get, this, _1, _2), - boost::bind(&b100_impl::mboard_set, this, _1, _2)); - - //set the ticks per seconds into the vita time control - _iface->poke32(B100_REG_TIME64_TPS, - boost::uint32_t(_clock_ctrl->get_fpga_clock_rate()) - ); - - //init the clock config - _clock_config = clock_config_t::internal(); - update_clock_config(); -} - -void b100_impl::update_clock_config(void){ - boost::uint32_t pps_flags = 0; - - //translate pps polarity enums - switch(_clock_config.pps_polarity){ - case clock_config_t::PPS_POS: pps_flags |= B100_FLAG_TIME64_PPS_POSEDGE; break; - case clock_config_t::PPS_NEG: pps_flags |= B100_FLAG_TIME64_PPS_NEGEDGE; break; - default: throw uhd::runtime_error("unhandled clock configuration pps polarity"); - } - - //set the pps flags - _iface->poke32(B100_REG_TIME64_FLAGS, pps_flags); - - //clock source ref 10mhz - switch(_clock_config.ref_source){ - case clock_config_t::REF_AUTO: _clock_ctrl->use_auto_ref(); break; - case clock_config_t::REF_INT: _clock_ctrl->use_internal_ref(); break; - case clock_config_t::REF_SMA: _clock_ctrl->use_auto_ref(); break; - default: throw uhd::runtime_error("unhandled clock configuration ref source"); - } -} - -/*********************************************************************** - * Mboard Get - **********************************************************************/ -void b100_impl::mboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<mboard_prop_t>()){ - case MBOARD_PROP_NAME: - val = std::string("USRP-B100 mboard"); - return; - - case MBOARD_PROP_OTHERS: - val = prop_names_t(); - return; - - case MBOARD_PROP_RX_DBOARD: - UHD_ASSERT_THROW(key.name == ""); - val = _rx_dboard_proxy->get_link(); - return; - - case MBOARD_PROP_RX_DBOARD_NAMES: - val = prop_names_t(1, ""); //vector of size 1 with empty string - return; - - case MBOARD_PROP_TX_DBOARD: - UHD_ASSERT_THROW(key.name == ""); - val = _tx_dboard_proxy->get_link(); - return; - - case MBOARD_PROP_TX_DBOARD_NAMES: - val = prop_names_t(1, ""); //vector of size 1 with empty string - return; - - case MBOARD_PROP_RX_DSP: - UHD_ASSERT_THROW(key.name == ""); - val = _rx_ddc_proxy->get_link(); - return; - - case MBOARD_PROP_RX_DSP_NAMES: - val = prop_names_t(1, ""); - return; - - case MBOARD_PROP_TX_DSP: - UHD_ASSERT_THROW(key.name == ""); - val = _tx_duc_proxy->get_link(); - return; - - case MBOARD_PROP_TX_DSP_NAMES: - val = prop_names_t(1, ""); - return; - - case MBOARD_PROP_CLOCK_CONFIG: - val = _clock_config; - return; - - case MBOARD_PROP_RX_SUBDEV_SPEC: - val = _rx_subdev_spec; - return; - - case MBOARD_PROP_TX_SUBDEV_SPEC: - val = _tx_subdev_spec; - return; - - case MBOARD_PROP_EEPROM_MAP: - val = _iface->mb_eeprom; - return; - - case MBOARD_PROP_TIME_NOW:while(true){ - uint32_t secs = _iface->peek32(B100_REG_RB_TIME_NOW_SECS); - uint32_t ticks = _iface->peek32(B100_REG_RB_TIME_NOW_TICKS); - if (secs != _iface->peek32(B100_REG_RB_TIME_NOW_SECS)) continue; - val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); - return; - } - - case MBOARD_PROP_TIME_PPS: while(true){ - uint32_t secs = _iface->peek32(B100_REG_RB_TIME_PPS_SECS); - uint32_t ticks = _iface->peek32(B100_REG_RB_TIME_PPS_TICKS); - if (secs != _iface->peek32(B100_REG_RB_TIME_PPS_SECS)) continue; - val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); - return; - } - - case MBOARD_PROP_CLOCK_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * Mboard Set - **********************************************************************/ -void b100_impl::mboard_set(const wax::obj &key, const wax::obj &val) -{ - if(key.type() == typeid(std::string)) { - if(key.as<std::string>() == "load_eeprom") { - std::string b100_eeprom_image = val.as<std::string>(); - UHD_MSG(status) << "B100 EEPROM image: " << b100_eeprom_image << std::endl; - _fx2_ctrl->usrp_load_eeprom(val.as<std::string>()); - } - return; - } - - //handle the get request conditioned on the key - switch(key.as<mboard_prop_t>()){ - case MBOARD_PROP_TIME_NOW: - case MBOARD_PROP_TIME_PPS:{ - time_spec_t time_spec = val.as<time_spec_t>(); - _iface->poke32(B100_REG_TIME64_TICKS, time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate())); - boost::uint32_t imm_flags = (key.as<mboard_prop_t>() == MBOARD_PROP_TIME_NOW)? 1 : 0; - _iface->poke32(B100_REG_TIME64_IMM, imm_flags); - _iface->poke32(B100_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs())); - } - return; - - case MBOARD_PROP_RX_SUBDEV_SPEC: - _rx_subdev_spec = val.as<subdev_spec_t>(); - verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link()); - UHD_ASSERT_THROW(_rx_subdev_spec.size() == 1); - //set the mux - _iface->poke32(B100_REG_DSP_RX_MUX, dsp_type1::calc_rx_mux_word( - _dboard_manager->get_rx_subdev(_rx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() - )); - return; - - case MBOARD_PROP_TX_SUBDEV_SPEC: - _tx_subdev_spec = val.as<subdev_spec_t>(); - verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link()); - UHD_ASSERT_THROW(_tx_subdev_spec.size() == 1); - //set the mux and set the number of tx channels - _iface->poke32(B100_REG_DSP_TX_MUX, dsp_type1::calc_tx_mux_word( - _dboard_manager->get_tx_subdev(_tx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() - )); - return; - - case MBOARD_PROP_EEPROM_MAP: - // Step1: commit the map, writing only those values set. - // Step2: readback the entire eeprom map into the iface. - val.as<mboard_eeprom_t>().commit(*_iface, mboard_eeprom_t::MAP_B000); - _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_B000); - return; - - case MBOARD_PROP_CLOCK_CONFIG: - _clock_config = val.as<clock_config_t>(); - update_clock_config(); - return; - - case MBOARD_PROP_CLOCK_RATE: - UHD_MSG(warning) - << "You are setting the master clock rate from the API.\n" - << "You may want to pass this into the device address as master_clock_rate=<rate>.\n" - << "This way, the clock rate is guaranteed to be initialized first.\n" - << "See the application notes for USRP-B100 for further instructions.\n" - ; - _clock_ctrl->set_fpga_clock_rate(val.as<double>()); - update_transport_channel_mapping(); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/fx2/CMakeLists.txt b/host/lib/usrp/common/CMakeLists.txt index 9d1e15e16..ec8b60fec 100644 --- a/host/lib/usrp/fx2/CMakeLists.txt +++ b/host/lib/usrp/common/CMakeLists.txt @@ -16,11 +16,19 @@ # ######################################################################## +# This file included, use CMake directory variables +######################################################################## IF(ENABLE_USB) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/common) LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/fx2_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/fx2_ctrl.hpp ) ENDIF(ENABLE_USB) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/validate_subdev_spec.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/recv_packet_demuxer.cpp +) diff --git a/host/lib/usrp/fx2/fx2_ctrl.cpp b/host/lib/usrp/common/fx2_ctrl.cpp index 06ca51c25..8f2206221 100644 --- a/host/lib/usrp/fx2/fx2_ctrl.cpp +++ b/host/lib/usrp/common/fx2_ctrl.cpp @@ -240,9 +240,9 @@ public: while (not file.eof()) { file.read((char *)buf, sizeof(buf)); - size_t n = file.gcount(); + const std::streamsize n = file.gcount(); if(n == 0) continue; - int ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, n); + int ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, boost::uint16_t(n)); if (ret < 0 or size_t(ret) != n) { throw uhd::io_error("usrp_load_fpga: fpga load error"); } @@ -262,11 +262,10 @@ public: void usrp_load_eeprom(std::string filestring) { + if (load_img_msg) UHD_MSG(status) << "Loading EEPROM image: " << filestring << "..." << std::flush; const char *filename = filestring.c_str(); const boost::uint16_t i2c_addr = 0x50; - //FIXME: verify types - int len; unsigned int addr; unsigned char data[256]; unsigned char sendbuf[17]; @@ -279,7 +278,7 @@ public: } file.read((char *)data, 256); - len = file.gcount(); + std::streamsize len = file.gcount(); if(len == 256) { throw uhd::io_error("usrp_load_eeprom: image size too large"); @@ -289,8 +288,8 @@ public: addr = 0; while(len > 0) { sendbuf[0] = addr; - memcpy(sendbuf+1, &data[addr], len > pagesize ? pagesize : len); - int ret = usrp_i2c_write(i2c_addr, sendbuf, (len > pagesize ? pagesize : len)+1); + memcpy(sendbuf+1, &data[addr], len > pagesize ? pagesize : size_t(len)); + int ret = usrp_i2c_write(i2c_addr, sendbuf, (len > pagesize ? pagesize : size_t(len))+1); if (ret < 0) { throw uhd::io_error("usrp_load_eeprom: usrp_i2c_write failed"); } @@ -299,6 +298,7 @@ public: boost::this_thread::sleep(boost::posix_time::milliseconds(100)); } file.close(); + if (load_img_msg) UHD_MSG(status) << " done" << std::endl; } @@ -409,6 +409,42 @@ public: return usrp_control_read(VRQ_I2C_READ, i2c_addr, 0, buf, len); } + static const bool iface_debug = false; + static const size_t max_i2c_data_bytes = 64; + + void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) + { + UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes); + + unsigned char buff[max_i2c_data_bytes]; + std::copy(bytes.begin(), bytes.end(), buff); + + int ret = this->usrp_i2c_write(addr & 0xff, + buff, + bytes.size()); + + if (iface_debug && (ret < 0)) + uhd::runtime_error("USRP: failed i2c write"); + } + + byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes) + { + UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes); + + unsigned char buff[max_i2c_data_bytes]; + int ret = this->usrp_i2c_read(addr & 0xff, + buff, + num_bytes); + + if (iface_debug && ((ret < 0) || (unsigned)ret < (num_bytes))) + uhd::runtime_error("USRP: failed i2c read"); + + byte_vector_t out_bytes; + for (size_t i = 0; i < num_bytes; i++) + out_bytes.push_back(buff[i]); + + return out_bytes; + } private: diff --git a/host/lib/usrp/fx2/fx2_ctrl.hpp b/host/lib/usrp/common/fx2_ctrl.hpp index 37fa09605..691d64275 100644 --- a/host/lib/usrp/fx2/fx2_ctrl.hpp +++ b/host/lib/usrp/common/fx2_ctrl.hpp @@ -15,16 +15,17 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#ifndef INCLUDED_USRP_CTRL_HPP -#define INCLUDED_USRP_CTRL_HPP +#ifndef INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP +#define INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP -#include <uhd/transport/usb_control.hpp> +#include <uhd/transport/usb_control.hpp> +#include <uhd/types/serial.hpp> //i2c iface #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> namespace uhd{ namespace usrp{ -class fx2_ctrl : boost::noncopyable{ +class fx2_ctrl : boost::noncopyable, public uhd::i2c_iface{ public: typedef boost::shared_ptr<fx2_ctrl> sptr; @@ -119,4 +120,4 @@ public: }} //namespace uhd::usrp -#endif /* INCLUDED_USRP_CTRL_HPP */ +#endif /* INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP */ diff --git a/host/lib/usrp/common/recv_packet_demuxer.cpp b/host/lib/usrp/common/recv_packet_demuxer.cpp new file mode 100644 index 000000000..f2cfe3bb0 --- /dev/null +++ b/host/lib/usrp/common/recv_packet_demuxer.cpp @@ -0,0 +1,87 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "recv_packet_demuxer.hpp" +#include <uhd/utils/msg.hpp> +#include <uhd/utils/byteswap.hpp> +#include <boost/thread/mutex.hpp> +#include <queue> +#include <deque> +#include <vector> + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::transport; + +static UHD_INLINE boost::uint32_t extract_sid(managed_recv_buffer::sptr &buff){ + //ASSUME that the data is in little endian format + return uhd::wtohx(buff->cast<const boost::uint32_t *>()[1]); +} + +class recv_packet_demuxer_impl : public uhd::usrp::recv_packet_demuxer{ +public: + recv_packet_demuxer_impl( + transport::zero_copy_if::sptr transport, + const size_t size, + const boost::uint32_t sid_base + ): + _transport(transport), _sid_base(sid_base), _queues(size) + { + /* NOP */ + } + + managed_recv_buffer::sptr get_recv_buff(const size_t index, const double timeout){ + boost::mutex::scoped_lock lock(_mutex); + managed_recv_buffer::sptr buff; + + //there is already an entry in the queue, so pop that + if (not _queues[index].wrapper.empty()){ + std::swap(buff, _queues[index].wrapper.front()); + _queues[index].wrapper.pop(); + return buff; + } + + while (true){ + //otherwise call into the transport + buff = _transport->get_recv_buff(timeout); + if (buff.get() == NULL) return buff; //timeout + + //check the stream id to know which channel + const size_t rx_index = extract_sid(buff) - _sid_base; + if (rx_index == index) return buff; //got expected message + + //otherwise queue and try again + if (rx_index < _queues.size()) _queues[rx_index].wrapper.push(buff); + else UHD_MSG(error) << "Got a data packet with unknown SID " << extract_sid(buff) << std::endl; + } + } + +private: + transport::zero_copy_if::sptr _transport; + const boost::uint32_t _sid_base; + boost::mutex _mutex; + struct channel_guts_type{ + channel_guts_type(void): wrapper(container){} + std::deque<managed_recv_buffer::sptr> container; + std::queue<managed_recv_buffer::sptr> wrapper; + }; + std::vector<channel_guts_type> _queues; +}; + +recv_packet_demuxer::sptr recv_packet_demuxer::make(transport::zero_copy_if::sptr transport, const size_t size, const boost::uint32_t sid_base){ + return sptr(new recv_packet_demuxer_impl(transport, size, sid_base)); +} diff --git a/host/lib/usrp/common/recv_packet_demuxer.hpp b/host/lib/usrp/common/recv_packet_demuxer.hpp new file mode 100644 index 000000000..fde756d27 --- /dev/null +++ b/host/lib/usrp/common/recv_packet_demuxer.hpp @@ -0,0 +1,41 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_COMMON_RECV_PACKET_DEMUXER_HPP +#define INCLUDED_LIBUHD_USRP_COMMON_RECV_PACKET_DEMUXER_HPP + +#include <uhd/config.hpp> +#include <uhd/transport/zero_copy.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/cstdint.hpp> + +namespace uhd{ namespace usrp{ + + class recv_packet_demuxer{ + public: + typedef boost::shared_ptr<recv_packet_demuxer> sptr; + + //! Make a new demuxer from a transport and parameters + static sptr make(transport::zero_copy_if::sptr transport, const size_t size, const boost::uint32_t sid_base); + + //! Get a buffer at the given index from the transport + virtual transport::managed_recv_buffer::sptr get_recv_buff(const size_t index, const double timeout) = 0; + }; + +}} //namespace uhd::usrp + +#endif /* INCLUDED_LIBUHD_USRP_COMMON_RECV_PACKET_DEMUXER_HPP */ diff --git a/host/lib/usrp/common/validate_subdev_spec.cpp b/host/lib/usrp/common/validate_subdev_spec.cpp new file mode 100644 index 000000000..fab40b204 --- /dev/null +++ b/host/lib/usrp/common/validate_subdev_spec.cpp @@ -0,0 +1,73 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "validate_subdev_spec.hpp" +#include <uhd/exception.hpp> +#include <uhd/utils/assert_has.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> + +using namespace uhd; +using namespace uhd::usrp; + +namespace uhd{ namespace usrp{ + + static std::ostream& operator<< (std::ostream &out, const subdev_spec_pair_t &pair){ + out << pair.db_name << ":" << pair.sd_name; + return out; + } + +}} + +void uhd::usrp::validate_subdev_spec( + property_tree::sptr tree, + const subdev_spec_t &spec, + const std::string &type, + const std::string &mb +){ + const size_t num_dsps = tree->list(str(boost::format("/mboards/%s/%s_dsps") % mb % type)).size(); + + //sanity checking on the length + if (spec.size() == 0) throw uhd::value_error(str(boost::format( + "Empty %s subdevice specification is not supported.\n" + ) % type)); + if (spec.size() > num_dsps) throw uhd::value_error(str(boost::format( + "The subdevice specification \"%s\" is too long.\n" + "The user specified %u channels, but there are only %u %s dsps on mboard %s.\n" + ) % spec.to_string() % spec.size() % num_dsps % type % mb)); + + //make a list of all possible specs + subdev_spec_t all_specs; + BOOST_FOREACH(const std::string &db, tree->list(str(boost::format("/mboards/%s/dboards") % mb))){ + BOOST_FOREACH(const std::string &sd, tree->list(str(boost::format("/mboards/%s/dboards/%s/%s_frontends") % mb % db % type))){ + all_specs.push_back(subdev_spec_pair_t(db, sd)); + } + } + + //validate that the spec is possible + BOOST_FOREACH(const subdev_spec_pair_t &pair, spec){ + uhd::assert_has(all_specs, pair, str(boost::format("%s subdevice specification on mboard %s") % type % mb)); + } + + //enable selected frontends, disable others + BOOST_FOREACH(const subdev_spec_pair_t &pair, all_specs){ + const bool enb = uhd::has(spec, pair); + tree->access<bool>(str(boost::format( + "/mboards/%s/dboards/%s/%s_frontends/%s/enabled" + ) % mb % pair.db_name % type % pair.sd_name)).set(enb); + } +} diff --git a/host/include/uhd/usrp/device_props.hpp b/host/lib/usrp/common/validate_subdev_spec.hpp index 3c8f7e225..7d9e2c309 100644 --- a/host/include/uhd/usrp/device_props.hpp +++ b/host/lib/usrp/common/validate_subdev_spec.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -15,25 +15,24 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#ifndef INCLUDED_UHD_USRP_DEVICE_PROPS_HPP -#define INCLUDED_UHD_USRP_DEVICE_PROPS_HPP +#ifndef INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP +#define INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP -#include <uhd/utils/props.hpp> +#include <uhd/config.hpp> +#include <uhd/usrp/subdev_spec.hpp> +#include <uhd/property_tree.hpp> +#include <string> namespace uhd{ namespace usrp{ - /*! - * Possible device properties: - * In general, a device will have a single mboard. - * In certain mimo applications, multiple boards - * will be present in the interface for configuration. - */ - enum device_prop_t{ - DEVICE_PROP_NAME, //ro, std::string - DEVICE_PROP_MBOARD, //ro, wax::obj - DEVICE_PROP_MBOARD_NAMES, //ro, prop_names_t - }; + //! Validate a subdev spec against a property tree + void validate_subdev_spec( + property_tree::sptr tree, + const subdev_spec_t &spec, + const std::string &type, //rx or tx + const std::string &mb = "0" + ); -}} //namespace +}} //namespace uhd::usrp -#endif /* INCLUDED_UHD_USRP_DEVICE_PROPS_HPP */ +#endif /* INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP */ diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt new file mode 100644 index 000000000..4476c9424 --- /dev/null +++ b/host/lib/usrp/cores/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# Copyright 2011 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +# This file included, use CMake directory variables +######################################################################## + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_100.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/spi_core_100.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/time64_core_200.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rx_dsp_core_200.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tx_dsp_core_200.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rx_frontend_core_200.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tx_frontend_core_200.cpp +) diff --git a/host/lib/usrp/cores/i2c_core_100.cpp b/host/lib/usrp/cores/i2c_core_100.cpp new file mode 100644 index 000000000..12352f108 --- /dev/null +++ b/host/lib/usrp/cores/i2c_core_100.cpp @@ -0,0 +1,138 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "i2c_core_100.hpp" +#include <uhd/exception.hpp> +#include <uhd/utils/msg.hpp> +#include <boost/thread/thread.hpp> //sleep + +#define REG_I2C_PRESCALER_LO _base + 0 +#define REG_I2C_PRESCALER_HI _base + 2 +#define REG_I2C_CTRL _base + 4 +#define REG_I2C_DATA _base + 6 +#define REG_I2C_CMD_STATUS _base + 8 + +// +// STA, STO, RD, WR, and IACK bits are cleared automatically +// + +#define I2C_CTRL_EN (1 << 7) // core enable +#define I2C_CTRL_IE (1 << 6) // interrupt enable + +#define I2C_CMD_START (1 << 7) // generate (repeated) start condition +#define I2C_CMD_STOP (1 << 6) // generate stop condition +#define I2C_CMD_RD (1 << 5) // read from slave +#define I2C_CMD_WR (1 << 4) // write to slave +#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1) +#define I2C_CMD_RSVD_2 (1 << 2) // reserved +#define I2C_CMD_RSVD_1 (1 << 1) // reserved +#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt + +#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK) +#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected +#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration +#define I2C_ST_RSVD_4 (1 << 4) // reserved +#define I2C_ST_RSVD_3 (1 << 3) // reserved +#define I2C_ST_RSVD_2 (1 << 2) // reserved +#define I2C_ST_TIP (1 << 1) // Transfer-in-progress +#define I2C_ST_IP (1 << 0) // Interrupt pending + +using namespace uhd; + +class i2c_core_100_impl : public i2c_core_100{ +public: + i2c_core_100_impl(wb_iface::sptr iface, const size_t base): + _iface(iface), _base(base) + { + //init I2C FPGA interface. + _iface->poke16(REG_I2C_CTRL, 0x0000); + //set prescalers to operate at 400kHz: WB_CLK is 64MHz... + static const boost::uint32_t i2c_datarate = 400000; + static const boost::uint32_t wishbone_clk = 64000000; //FIXME should go somewhere else + boost::uint16_t prescaler = wishbone_clk / (i2c_datarate*5) - 1; + _iface->poke16(REG_I2C_PRESCALER_LO, prescaler & 0xFF); + _iface->poke16(REG_I2C_PRESCALER_HI, (prescaler >> 8) & 0xFF); + _iface->poke16(REG_I2C_CTRL, I2C_CTRL_EN); //enable I2C core + } + + void write_i2c( + boost::uint8_t addr, + const byte_vector_t &bytes + ){ + _iface->poke16(REG_I2C_DATA, (addr << 1) | 0); //addr and read bit (0) + _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0)); + + //wait for previous transfer to complete + if (not wait_chk_ack()) { + _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_STOP); + return; + } + + for (size_t i = 0; i < bytes.size(); i++) { + _iface->poke16(REG_I2C_DATA, bytes[i]); + _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0)); + if(!wait_chk_ack()) { + _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_STOP); + return; + } + } + } + + byte_vector_t read_i2c( + boost::uint8_t addr, + size_t num_bytes + ){ + byte_vector_t bytes; + if (num_bytes == 0) return bytes; + + while (_iface->peek16(REG_I2C_CMD_STATUS) & I2C_ST_BUSY); + + _iface->poke16(REG_I2C_DATA, (addr << 1) | 1); //addr and read bit (1) + _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START); + //wait for previous transfer to complete + if (not wait_chk_ack()) { + _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_STOP); + } + for (size_t i = 0; i < num_bytes; i++) { + _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_RD | ((num_bytes == i+1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0)); + i2c_wait(); + bytes.push_back(boost::uint8_t(_iface->peek16(REG_I2C_DATA))); + } + return bytes; + } + +private: + void i2c_wait(void) { + for (size_t i = 0; i < 100; i++){ + if ((_iface->peek16(REG_I2C_CMD_STATUS) & I2C_ST_TIP) == 0) return; + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + } + UHD_MSG(error) << "i2c_core_100: i2c_wait timeout" << std::endl; + } + + bool wait_chk_ack(void){ + i2c_wait(); + return (_iface->peek16(REG_I2C_CMD_STATUS) & I2C_ST_RXACK) == 0; + } + + wb_iface::sptr _iface; + const size_t _base; +}; + +i2c_core_100::sptr i2c_core_100::make(wb_iface::sptr iface, const size_t base){ + return sptr(new i2c_core_100_impl(iface, base)); +} diff --git a/fpga/usrp2/top/E1x0/passthru.v b/host/lib/usrp/cores/i2c_core_100.hpp index 486257366..f7a5ae4f7 100644 --- a/fpga/usrp2/top/E1x0/passthru.v +++ b/host/lib/usrp/cores/i2c_core_100.hpp @@ -15,21 +15,21 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -`timescale 1ns / 1ps -////////////////////////////////////////////////////////////////////////////////// +#ifndef INCLUDED_LIBUHD_USRP_I2C_CORE_100_HPP +#define INCLUDED_LIBUHD_USRP_I2C_CORE_100_HPP -module passthru - (input overo_gpio145, - output cgen_sclk, - output cgen_sen_b, - output cgen_mosi, - input fpga_cfg_din, - input fpga_cfg_cclk - ); - - assign cgen_sclk = fpga_cfg_cclk; - assign cgen_sen_b = overo_gpio145; - assign cgen_mosi = fpga_cfg_din; - - -endmodule // passthru +#include <uhd/config.hpp> +#include <uhd/types/serial.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include "wb_iface.hpp" + +class i2c_core_100 : boost::noncopyable, public uhd::i2c_iface{ +public: + typedef boost::shared_ptr<i2c_core_100> sptr; + + //! makes a new i2c core from iface and slave base + static sptr make(wb_iface::sptr iface, const size_t base); +}; + +#endif /* INCLUDED_LIBUHD_USRP_I2C_CORE_100_HPP */ diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp new file mode 100644 index 000000000..82bc7c1bf --- /dev/null +++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp @@ -0,0 +1,202 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "rx_dsp_core_200.hpp" +#include <uhd/types/dict.hpp> +#include <uhd/exception.hpp> +#include <uhd/utils/algorithm.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/math/special_functions/round.hpp> +#include <boost/math/special_functions/sign.hpp> +#include <algorithm> +#include <cmath> + +#define REG_DSP_RX_FREQ _dsp_base + 0 +//skip one right here +#define REG_DSP_RX_DECIM _dsp_base + 8 +#define REG_DSP_RX_MUX _dsp_base + 12 + +#define FLAG_DSP_RX_MUX_SWAP_IQ (1 << 0) +#define FLAG_DSP_RX_MUX_REAL_MODE (1 << 1) + +#define REG_RX_CTRL_STREAM_CMD _ctrl_base + 0 +#define REG_RX_CTRL_TIME_SECS _ctrl_base + 4 +#define REG_RX_CTRL_TIME_TICKS _ctrl_base + 8 +#define REG_RX_CTRL_CLEAR _ctrl_base + 12 +#define REG_RX_CTRL_VRT_HDR _ctrl_base + 16 +#define REG_RX_CTRL_VRT_SID _ctrl_base + 20 +#define REG_RX_CTRL_VRT_TLR _ctrl_base + 24 +#define REG_RX_CTRL_NSAMPS_PP _ctrl_base + 28 +#define REG_RX_CTRL_NCHANNELS _ctrl_base + 32 + +template <class T> T ceil_log2(T num){ + return std::ceil(std::log(num)/std::log(T(2))); +} + +using namespace uhd; + +class rx_dsp_core_200_impl : public rx_dsp_core_200{ +public: + rx_dsp_core_200_impl( + wb_iface::sptr iface, + const size_t dsp_base, const size_t ctrl_base, + const boost::uint32_t sid, const bool lingering_packet + ): + _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base) + { + //This is a hack/fix for the lingering packet problem. + //The caller should also flush the recv transports + if (lingering_packet){ + stream_cmd_t stream_cmd(stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); + stream_cmd.num_samps = 1; + issue_stream_command(stream_cmd); + } + + _iface->poke32(REG_RX_CTRL_CLEAR, 1); //reset + _iface->poke32(REG_RX_CTRL_NCHANNELS, 1); + _iface->poke32(REG_RX_CTRL_VRT_HDR, 0 + | (0x1 << 28) //if data with stream id + | (0x1 << 26) //has trailer + | (0x3 << 22) //integer time other + | (0x1 << 20) //fractional time sample count + ); + _iface->poke32(REG_RX_CTRL_VRT_SID, sid); + _iface->poke32(REG_RX_CTRL_VRT_TLR, 0); + } + + void set_nsamps_per_packet(const size_t nsamps){ + _iface->poke32(REG_RX_CTRL_NSAMPS_PP, nsamps); + } + + void issue_stream_command(const stream_cmd_t &stream_cmd){ + UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x3fffffff); + _continuous_streaming = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS; + + //setup the mode to instruction flags + typedef boost::tuple<bool, bool, bool> inst_t; + static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of + //reload, chain, samps + (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false)) + (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false)) + (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true)) + (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true)) + ; + + //setup the instruction flag values + bool inst_reload, inst_chain, inst_samps; + boost::tie(inst_reload, inst_chain, inst_samps) = mode_to_inst[stream_cmd.stream_mode]; + + //calculate the word from flags and length + boost::uint32_t cmd_word = 0; + cmd_word |= boost::uint32_t((stream_cmd.stream_now)? 1 : 0) << 31; + cmd_word |= boost::uint32_t((inst_chain)? 1 : 0) << 30; + cmd_word |= boost::uint32_t((inst_reload)? 1 : 0) << 29; + cmd_word |= (inst_samps)? stream_cmd.num_samps : ((inst_chain)? 1 : 0); + + //issue the stream command + _iface->poke32(REG_RX_CTRL_STREAM_CMD, cmd_word); + _iface->poke32(REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs())); + _iface->poke32(REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(_tick_rate)); //latches the command + } + + void set_mux(const std::string &mode, const bool fe_swapped){ + static const uhd::dict<std::string, boost::uint32_t> mode_to_mux = boost::assign::map_list_of + ("IQ", 0) + ("QI", FLAG_DSP_RX_MUX_SWAP_IQ) + ("I", FLAG_DSP_RX_MUX_REAL_MODE) + ("Q", FLAG_DSP_RX_MUX_SWAP_IQ | FLAG_DSP_RX_MUX_REAL_MODE) + ; + _iface->poke32(REG_DSP_RX_MUX, mode_to_mux[mode] ^ (fe_swapped? FLAG_DSP_RX_MUX_SWAP_IQ : 0)); + } + + void set_tick_rate(const double rate){ + _tick_rate = rate; + } + + void set_link_rate(const double rate){ + _link_rate = rate/sizeof(boost::uint32_t); //in samps/s + } + + double set_host_rate(const double rate){ + const size_t decim_rate = uhd::clip<size_t>( + boost::math::iround(_tick_rate/rate), size_t(std::ceil(_tick_rate/_link_rate)), 512 + ); + size_t decim = decim_rate; + + //determine which half-band filters are activated + int hb0 = 0, hb1 = 0; + if (decim % 2 == 0){ + hb0 = 1; + decim /= 2; + } + if (decim % 2 == 0){ + hb1 = 1; + decim /= 2; + } + + _iface->poke32(REG_DSP_RX_DECIM, (hb1 << 9) | (hb0 << 8) | (decim & 0xff)); + + // Calculate CIC decimation (i.e., without halfband decimators) + // Calculate closest multiplier constant to reverse gain absent scale multipliers + const double rate_pow = std::pow(double(decim & 0xff), 4); + _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow); + + return _tick_rate/decim_rate; + } + + double get_scaling_adjustment(void){ + return _scaling_adjustment; + } + + double set_freq(const double freq_){ + //correct for outside of rate (wrap around) + double freq = std::fmod(freq_, _tick_rate); + if (std::abs(freq) > _tick_rate/2.0) + freq -= boost::math::sign(freq)*_tick_rate; + + //calculate the freq register word (signed) + UHD_ASSERT_THROW(std::abs(freq) <= _tick_rate/2.0); + static const double scale_factor = std::pow(2.0, 32); + const boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / _tick_rate) * scale_factor)); + + //update the actual frequency + const double actual_freq = (double(freq_word) / scale_factor) * _tick_rate; + + _iface->poke32(REG_DSP_RX_FREQ, boost::uint32_t(freq_word)); + + return actual_freq; + } + + uhd::meta_range_t get_freq_range(void){ + return uhd::meta_range_t(-_tick_rate/2, +_tick_rate/2, _tick_rate/std::pow(2.0, 32)); + } + + void handle_overflow(void){ + if (_continuous_streaming) issue_stream_command(stream_cmd_t::STREAM_MODE_START_CONTINUOUS); + } + +private: + wb_iface::sptr _iface; + const size_t _dsp_base, _ctrl_base; + double _tick_rate, _link_rate; + bool _continuous_streaming; + double _scaling_adjustment; +}; + +rx_dsp_core_200::sptr rx_dsp_core_200::make(wb_iface::sptr iface, const size_t dsp_base, const size_t ctrl_base, const boost::uint32_t sid, const bool lingering_packet){ + return sptr(new rx_dsp_core_200_impl(iface, dsp_base, ctrl_base, sid, lingering_packet)); +} diff --git a/host/lib/usrp/cores/rx_dsp_core_200.hpp b/host/lib/usrp/cores/rx_dsp_core_200.hpp new file mode 100644 index 000000000..391cc8441 --- /dev/null +++ b/host/lib/usrp/cores/rx_dsp_core_200.hpp @@ -0,0 +1,61 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP +#define INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP + +#include <uhd/config.hpp> +#include <uhd/types/ranges.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include <uhd/types/stream_cmd.hpp> +#include "wb_iface.hpp" +#include <string> + +class rx_dsp_core_200 : boost::noncopyable{ +public: + typedef boost::shared_ptr<rx_dsp_core_200> sptr; + + static sptr make( + wb_iface::sptr iface, + const size_t dsp_base, const size_t ctrl_base, + const boost::uint32_t sid, const bool lingering_packet = false + ); + + virtual void set_nsamps_per_packet(const size_t nsamps) = 0; + + virtual void issue_stream_command(const uhd::stream_cmd_t &stream_cmd) = 0; + + virtual void set_mux(const std::string &mode, const bool fe_swapped = false) = 0; + + virtual void set_tick_rate(const double rate) = 0; + + virtual void set_link_rate(const double rate) = 0; + + virtual double set_host_rate(const double rate) = 0; + + virtual double get_scaling_adjustment(void) = 0; + + virtual uhd::meta_range_t get_freq_range(void) = 0; + + virtual double set_freq(const double freq) = 0; + + virtual void handle_overflow(void) = 0; + +}; + +#endif /* INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP */ diff --git a/host/lib/usrp/cores/rx_frontend_core_200.cpp b/host/lib/usrp/cores/rx_frontend_core_200.cpp new file mode 100644 index 000000000..0e8220b49 --- /dev/null +++ b/host/lib/usrp/cores/rx_frontend_core_200.cpp @@ -0,0 +1,61 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "rx_frontend_core_200.hpp" +#include <boost/math/special_functions/round.hpp> + +#define REG_RX_FE_SWAP_IQ _base + 0 //lower bit +#define REG_RX_FE_MAG_CORRECTION _base + 4 //18 bits +#define REG_RX_FE_PHASE_CORRECTION _base + 8 //18 bits +#define REG_RX_FE_OFFSET_I _base + 12 //18 bits +#define REG_RX_FE_OFFSET_Q _base + 16 //18 bits + +static boost::uint32_t fs_to_bits(const double num, const size_t bits){ + return boost::int32_t(boost::math::round(num * (1 << (bits-1)))); +} + + +class rx_frontend_core_200_impl : public rx_frontend_core_200{ +public: + rx_frontend_core_200_impl(wb_iface::sptr iface, const size_t base): + _iface(iface), _base(base) + { + //NOP + } + + void set_mux(const bool swap){ + _iface->poke32(REG_RX_FE_SWAP_IQ, swap? 1 : 0); + } + + void set_offset(const std::complex<double> &off){ + _iface->poke32(REG_RX_FE_OFFSET_I, fs_to_bits(off.real(), 24)); + _iface->poke32(REG_RX_FE_OFFSET_Q, fs_to_bits(off.imag(), 24)); + } + + void set_correction(const std::complex<double> &cor){ + _iface->poke32(REG_RX_FE_MAG_CORRECTION, fs_to_bits(std::abs(cor), 18)); + _iface->poke32(REG_RX_FE_PHASE_CORRECTION, fs_to_bits(std::atan2(cor.real(), cor.imag()), 18)); + } + +private: + wb_iface::sptr _iface; + const size_t _base; +}; + +rx_frontend_core_200::sptr rx_frontend_core_200::make(wb_iface::sptr iface, const size_t base){ + return sptr(new rx_frontend_core_200_impl(iface, base)); +} diff --git a/host/lib/usrp/cores/rx_frontend_core_200.hpp b/host/lib/usrp/cores/rx_frontend_core_200.hpp new file mode 100644 index 000000000..a950e2bb7 --- /dev/null +++ b/host/lib/usrp/cores/rx_frontend_core_200.hpp @@ -0,0 +1,42 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_TX_FRONTEND_CORE_200_HPP +#define INCLUDED_LIBUHD_USRP_TX_FRONTEND_CORE_200_HPP + +#include <uhd/config.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include "wb_iface.hpp" +#include <complex> +#include <string> + +class rx_frontend_core_200 : boost::noncopyable{ +public: + typedef boost::shared_ptr<rx_frontend_core_200> sptr; + + static sptr make(wb_iface::sptr iface, const size_t base); + + virtual void set_mux(const bool swap) = 0; + + virtual void set_offset(const std::complex<double> &off) = 0; + + virtual void set_correction(const std::complex<double> &cor) = 0; + +}; + +#endif /* INCLUDED_LIBUHD_USRP_TX_FRONTEND_CORE_200_HPP */ diff --git a/host/lib/usrp/cores/spi_core_100.cpp b/host/lib/usrp/cores/spi_core_100.cpp new file mode 100644 index 000000000..d11a499a9 --- /dev/null +++ b/host/lib/usrp/cores/spi_core_100.cpp @@ -0,0 +1,88 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "spi_core_100.hpp" +#include <uhd/exception.hpp> +#include <uhd/utils/msg.hpp> +#include <boost/thread/thread.hpp> //sleep + +#define REG_SPI_TXRX0 _base + 0 +#define REG_SPI_TXRX1 _base + 4 +#define REG_SPI_TXRX2 _base + 8 +#define REG_SPI_TXRX3 _base + 12 +#define REG_SPI_CTRL _base + 16 +#define REG_SPI_DIV _base + 20 +#define REG_SPI_SS _base + 24 + +//spi ctrl register bit definitions +#define SPI_CTRL_ASS (1<<13) +#define SPI_CTRL_IE (1<<12) +#define SPI_CTRL_LSB (1<<11) +#define SPI_CTRL_TXNEG (1<<10) //mosi edge, push on falling edge when 1 +#define SPI_CTRL_RXNEG (1<< 9) //miso edge, latch on falling edge when 1 +#define SPI_CTRL_GO_BSY (1<< 8) +#define SPI_CTRL_CHAR_LEN_MASK 0x7F + +using namespace uhd; + +class spi_core_100_impl : public spi_core_100{ +public: + spi_core_100_impl(wb_iface::sptr iface, const size_t base): + _iface(iface), _base(base) { /* NOP */} + + boost::uint32_t transact_spi( + int which_slave, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits, + bool readback + ){ + UHD_ASSERT_THROW(num_bits <= 32 and (num_bits % 8) == 0); + + int edge_flags = ((config.miso_edge==spi_config_t::EDGE_FALL) ? SPI_CTRL_RXNEG : 0) | + ((config.mosi_edge==spi_config_t::EDGE_FALL) ? 0 : SPI_CTRL_TXNEG) + ; + boost::uint16_t ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & num_bits) | edge_flags; + + spi_wait(); + _iface->poke16(REG_SPI_DIV, 0x0001); // = fpga_clk / 4 + _iface->poke32(REG_SPI_SS, which_slave & 0xFFFF); + _iface->poke32(REG_SPI_TXRX0, data); + _iface->poke16(REG_SPI_CTRL, ctrl); + _iface->poke16(REG_SPI_CTRL, ctrl | SPI_CTRL_GO_BSY); + + if (not readback) return 0; + spi_wait(); + return _iface->peek32(REG_SPI_TXRX0); + } + +private: + void spi_wait(void) { + for (size_t i = 0; i < 100; i++){ + if ((_iface->peek16(REG_SPI_CTRL) & SPI_CTRL_GO_BSY) == 0) return; + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + } + UHD_MSG(error) << "spi_core_100: spi_wait timeout" << std::endl; + } + + wb_iface::sptr _iface; + const size_t _base; +}; + +spi_core_100::sptr spi_core_100::make(wb_iface::sptr iface, const size_t base){ + return sptr(new spi_core_100_impl(iface, base)); +} diff --git a/host/lib/usrp/cores/spi_core_100.hpp b/host/lib/usrp/cores/spi_core_100.hpp new file mode 100644 index 000000000..87d328aaa --- /dev/null +++ b/host/lib/usrp/cores/spi_core_100.hpp @@ -0,0 +1,35 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_SPI_CORE_100_HPP +#define INCLUDED_LIBUHD_USRP_SPI_CORE_100_HPP + +#include <uhd/config.hpp> +#include <uhd/types/serial.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include "wb_iface.hpp" + +class spi_core_100 : boost::noncopyable, public uhd::spi_iface{ +public: + typedef boost::shared_ptr<spi_core_100> sptr; + + //! makes a new spi core from iface and slave base + static sptr make(wb_iface::sptr iface, const size_t base); +}; + +#endif /* INCLUDED_LIBUHD_USRP_SPI_CORE_100_HPP */ diff --git a/host/lib/usrp/cores/time64_core_200.cpp b/host/lib/usrp/cores/time64_core_200.cpp new file mode 100644 index 000000000..23d1bdea2 --- /dev/null +++ b/host/lib/usrp/cores/time64_core_200.cpp @@ -0,0 +1,132 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "time64_core_200.hpp" +#include <uhd/exception.hpp> +#include <uhd/utils/assert_has.hpp> +#include <boost/math/special_functions/round.hpp> + +#define REG_TIME64_SECS _base + 0 +#define REG_TIME64_TICKS _base + 4 +#define REG_TIME64_FLAGS _base + 8 +#define REG_TIME64_IMM _base + 12 +#define REG_TIME64_TPS _base + 16 +#define REG_TIME64_MIMO_SYNC _base + 20 //lower byte is delay cycles + +//pps flags (see above) +#define FLAG_TIME64_PPS_NEGEDGE (0 << 0) +#define FLAG_TIME64_PPS_POSEDGE (1 << 0) +#define FLAG_TIME64_PPS_SMA (0 << 1) +#define FLAG_TIME64_PPS_MIMO (1 << 1) //apparently not used + +#define FLAG_TIME64_LATCH_NOW 1 +#define FLAG_TIME64_LATCH_NEXT_PPS 0 + +#define FLAG_TIME64_MIMO_SYNC (1 << 8) + +using namespace uhd; + +class time64_core_200_impl : public time64_core_200{ +public: + time64_core_200_impl( + wb_iface::sptr iface, const size_t base, + const readback_bases_type &readback_bases, + const size_t mimo_delay_cycles + ): + _iface(iface), _base(base), + _readback_bases(readback_bases), + _mimo_delay_cycles(mimo_delay_cycles) + { + _sources.push_back("none"); + _sources.push_back("external"); + _sources.push_back("_external_"); + if (_mimo_delay_cycles != 0) _sources.push_back("mimo"); + } + + void set_tick_rate(const double rate){ + _tick_rate = rate; + _iface->poke32(REG_TIME64_TPS, boost::math::iround(rate)); + } + + uhd::time_spec_t get_time_now(void){ + for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously + const boost::uint32_t secs = _iface->peek32(_readback_bases.rb_secs_now); + const boost::uint32_t ticks = _iface->peek32(_readback_bases.rb_ticks_now); + if (secs != _iface->peek32(_readback_bases.rb_secs_now)) continue; + return time_spec_t(secs, ticks, _tick_rate); + } + throw uhd::runtime_error("time64_core_200: get time now timeout"); + } + + uhd::time_spec_t get_time_last_pps(void){ + for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously + const boost::uint32_t secs = _iface->peek32(_readback_bases.rb_secs_pps); + const boost::uint32_t ticks = _iface->peek32(_readback_bases.rb_ticks_pps); + if (secs != _iface->peek32(_readback_bases.rb_secs_pps)) continue; + return time_spec_t(secs, ticks, _tick_rate); + } + throw uhd::runtime_error("time64_core_200: get time last pps timeout"); + } + + void set_time_now(const uhd::time_spec_t &time){ + _iface->poke32(REG_TIME64_TICKS, time.get_tick_count(_tick_rate)); + _iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NOW); + _iface->poke32(REG_TIME64_SECS, boost::uint32_t(time.get_full_secs())); //latches all 3 + } + + void set_time_next_pps(const uhd::time_spec_t &time){ + _iface->poke32(REG_TIME64_TICKS, time.get_tick_count(_tick_rate)); + _iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NEXT_PPS); + _iface->poke32(REG_TIME64_SECS, boost::uint32_t(time.get_full_secs())); //latches all 3 + } + + void set_time_source(const std::string &source){ + assert_has(_sources, source, "time source"); + + //setup pps flags + if (source == "external"){ + _iface->poke32(REG_TIME64_FLAGS, FLAG_TIME64_PPS_SMA | FLAG_TIME64_PPS_POSEDGE); + } + else if (source == "_external_"){ + _iface->poke32(REG_TIME64_FLAGS, FLAG_TIME64_PPS_SMA | FLAG_TIME64_PPS_NEGEDGE); + } + + //setup mimo flags + if (source == "mimo"){ + _iface->poke32(REG_TIME64_MIMO_SYNC, FLAG_TIME64_MIMO_SYNC | (_mimo_delay_cycles & 0xff)); + } + else{ + _iface->poke32(REG_TIME64_MIMO_SYNC, 0); + } + } + + std::vector<std::string> get_time_sources(void){ + return _sources; + } + +private: + wb_iface::sptr _iface; + const size_t _base; + const readback_bases_type _readback_bases; + double _tick_rate; + const size_t _mimo_delay_cycles; + std::vector<std::string> _sources; +}; + +time64_core_200::sptr time64_core_200::make(wb_iface::sptr iface, const size_t base, const readback_bases_type &readback_bases, const size_t mimo_delay_cycles){ + return sptr(new time64_core_200_impl(iface, base, readback_bases, mimo_delay_cycles)); +} diff --git a/host/lib/usrp/cores/time64_core_200.hpp b/host/lib/usrp/cores/time64_core_200.hpp new file mode 100644 index 000000000..ebd51a02f --- /dev/null +++ b/host/lib/usrp/cores/time64_core_200.hpp @@ -0,0 +1,61 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_TIME64_CORE_200_HPP +#define INCLUDED_LIBUHD_USRP_TIME64_CORE_200_HPP + +#include <uhd/config.hpp> +#include <uhd/types/time_spec.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include "wb_iface.hpp" +#include <string> +#include <vector> + +class time64_core_200 : boost::noncopyable{ +public: + typedef boost::shared_ptr<time64_core_200> sptr; + + struct readback_bases_type{ + size_t rb_secs_now, rb_ticks_now; + size_t rb_secs_pps, rb_ticks_pps; + }; + + //! makes a new time64 core from iface and slave base + static sptr make( + wb_iface::sptr iface, const size_t base, + const readback_bases_type &readback_bases, + const size_t mimo_delay_cycles = 0 // 0 means no-mimo + ); + + virtual void set_tick_rate(const double rate) = 0; + + virtual uhd::time_spec_t get_time_now(void) = 0; + + virtual uhd::time_spec_t get_time_last_pps(void) = 0; + + virtual void set_time_now(const uhd::time_spec_t &time) = 0; + + virtual void set_time_next_pps(const uhd::time_spec_t &time) = 0; + + virtual void set_time_source(const std::string &source) = 0; + + virtual std::vector<std::string> get_time_sources(void) = 0; + +}; + +#endif /* INCLUDED_LIBUHD_USRP_TIME64_CORE_200_HPP */ diff --git a/host/lib/usrp/cores/tx_dsp_core_200.cpp b/host/lib/usrp/cores/tx_dsp_core_200.cpp new file mode 100644 index 000000000..222ba589a --- /dev/null +++ b/host/lib/usrp/cores/tx_dsp_core_200.cpp @@ -0,0 +1,140 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "tx_dsp_core_200.hpp" +#include <uhd/types/dict.hpp> +#include <uhd/exception.hpp> +#include <uhd/utils/algorithm.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/math/special_functions/round.hpp> +#include <boost/math/special_functions/sign.hpp> +#include <algorithm> +#include <cmath> + +#define REG_DSP_TX_FREQ _dsp_base + 0 +#define REG_DSP_TX_SCALE_IQ _dsp_base + 4 +#define REG_DSP_TX_INTERP _dsp_base + 8 + +#define REG_TX_CTRL_NUM_CHAN _ctrl_base + 0 +#define REG_TX_CTRL_CLEAR_STATE _ctrl_base + 4 +#define REG_TX_CTRL_REPORT_SID _ctrl_base + 8 +#define REG_TX_CTRL_POLICY _ctrl_base + 12 +#define REG_TX_CTRL_CYCLES_PER_UP _ctrl_base + 16 +#define REG_TX_CTRL_PACKETS_PER_UP _ctrl_base + 20 + +#define FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0) +#define FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1) +#define FLAG_TX_CTRL_POLICY_NEXT_BURST (0x1 << 2) + +//enable flag for registers: cycles and packets per update packet +#define FLAG_TX_CTRL_UP_ENB (1ul << 31) + +template <class T> T ceil_log2(T num){ + return std::ceil(std::log(num)/std::log(T(2))); +} + +using namespace uhd; + +class tx_dsp_core_200_impl : public tx_dsp_core_200{ +public: + tx_dsp_core_200_impl( + wb_iface::sptr iface, + const size_t dsp_base, const size_t ctrl_base, + const boost::uint32_t sid + ): + _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base) + { + //init the tx control registers + _iface->poke32(REG_TX_CTRL_CLEAR_STATE, 1); //reset + _iface->poke32(REG_TX_CTRL_NUM_CHAN, 0); //1 channel + _iface->poke32(REG_TX_CTRL_REPORT_SID, sid); + _iface->poke32(REG_TX_CTRL_POLICY, FLAG_TX_CTRL_POLICY_NEXT_PACKET); + } + + void set_tick_rate(const double rate){ + _tick_rate = rate; + } + + void set_link_rate(const double rate){ + _link_rate = rate/sizeof(boost::uint32_t); //in samps/s + } + + double set_host_rate(const double rate){ + const size_t interp_rate = uhd::clip<size_t>( + boost::math::iround(_tick_rate/rate), size_t(std::ceil(_tick_rate/_link_rate)), 512 + ); + size_t interp = interp_rate; + + //determine which half-band filters are activated + int hb0 = 0, hb1 = 0; + if (interp % 2 == 0){ + hb0 = 1; + interp /= 2; + } + if (interp % 2 == 0){ + hb1 = 1; + interp /= 2; + } + + _iface->poke32(REG_DSP_TX_INTERP, (hb1 << 9) | (hb0 << 8) | (interp & 0xff)); + + // Calculate CIC interpolation (i.e., without halfband interpolators) + // Calculate closest multiplier constant to reverse gain absent scale multipliers + double rate_cubed = std::pow(double(interp & 0xff), 3); + const boost::int16_t scale = boost::math::iround((4096*std::pow(2, ceil_log2(rate_cubed)))/(1.65*rate_cubed)); + _iface->poke32(REG_DSP_TX_SCALE_IQ, (boost::uint32_t(scale) << 16) | (boost::uint32_t(scale) << 0)); + + return _tick_rate/interp_rate; + } + + double set_freq(const double freq_){ + //correct for outside of rate (wrap around) + double freq = std::fmod(freq_, _tick_rate); + if (std::abs(freq) > _tick_rate/2.0) + freq -= boost::math::sign(freq)*_tick_rate; + + //calculate the freq register word (signed) + UHD_ASSERT_THROW(std::abs(freq) <= _tick_rate/2.0); + static const double scale_factor = std::pow(2.0, 32); + const boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / _tick_rate) * scale_factor)); + + //update the actual frequency + const double actual_freq = (double(freq_word) / scale_factor) * _tick_rate; + + _iface->poke32(REG_DSP_TX_FREQ, boost::uint32_t(freq_word)); + + return actual_freq; + } + + uhd::meta_range_t get_freq_range(void){ + return uhd::meta_range_t(-_tick_rate/2, +_tick_rate/2, _tick_rate/std::pow(2.0, 32)); + } + + void set_updates(const size_t cycles_per_up, const size_t packets_per_up){ + _iface->poke32(REG_TX_CTRL_CYCLES_PER_UP, (cycles_per_up == 0)? 0 : (FLAG_TX_CTRL_UP_ENB | cycles_per_up)); + _iface->poke32(REG_TX_CTRL_PACKETS_PER_UP, (packets_per_up == 0)? 0 : (FLAG_TX_CTRL_UP_ENB | packets_per_up)); + } + +private: + wb_iface::sptr _iface; + const size_t _dsp_base, _ctrl_base; + double _tick_rate, _link_rate; +}; + +tx_dsp_core_200::sptr tx_dsp_core_200::make(wb_iface::sptr iface, const size_t dsp_base, const size_t ctrl_base, const boost::uint32_t sid){ + return sptr(new tx_dsp_core_200_impl(iface, dsp_base, ctrl_base, sid)); +} diff --git a/host/lib/usrp/cores/tx_dsp_core_200.hpp b/host/lib/usrp/cores/tx_dsp_core_200.hpp new file mode 100644 index 000000000..65f822558 --- /dev/null +++ b/host/lib/usrp/cores/tx_dsp_core_200.hpp @@ -0,0 +1,51 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP +#define INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP + +#include <uhd/config.hpp> +#include <uhd/types/ranges.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include "wb_iface.hpp" + +class tx_dsp_core_200 : boost::noncopyable{ +public: + typedef boost::shared_ptr<tx_dsp_core_200> sptr; + + static sptr make( + wb_iface::sptr iface, + const size_t dsp_base, const size_t ctrl_base, + const boost::uint32_t sid + ); + + virtual void set_tick_rate(const double rate) = 0; + + virtual void set_link_rate(const double rate) = 0; + + virtual double set_host_rate(const double rate) = 0; + + virtual uhd::meta_range_t get_freq_range(void) = 0; + + virtual double set_freq(const double freq) = 0; + + virtual void set_updates(const size_t cycles_per_up, const size_t packets_per_up) = 0; + +}; + +#endif /* INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP */ diff --git a/host/lib/usrp/cores/tx_frontend_core_200.cpp b/host/lib/usrp/cores/tx_frontend_core_200.cpp new file mode 100644 index 000000000..a7568a81e --- /dev/null +++ b/host/lib/usrp/cores/tx_frontend_core_200.cpp @@ -0,0 +1,70 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "tx_frontend_core_200.hpp" +#include <uhd/types/dict.hpp> +#include <uhd/exception.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/math/special_functions/round.hpp> + +#define REG_TX_FE_DC_OFFSET_I _base + 0 //24 bits +#define REG_TX_FE_DC_OFFSET_Q _base + 4 //24 bits +#define REG_TX_FE_MAG_CORRECTION _base + 8 //18 bits +#define REG_TX_FE_PHASE_CORRECTION _base + 12 //18 bits +#define REG_TX_FE_MUX _base + 16 //8 bits (std output = 0x10, reversed = 0x01) + +static boost::uint32_t fs_to_bits(const double num, const size_t bits){ + return boost::int32_t(boost::math::round(num * (1 << (bits-1)))); +} + + +class tx_frontend_core_200_impl : public tx_frontend_core_200{ +public: + tx_frontend_core_200_impl(wb_iface::sptr iface, const size_t base): + _iface(iface), _base(base) + { + //NOP + } + + void set_mux(const std::string &mode){ + static const uhd::dict<std::string, boost::uint32_t> mode_to_mux = boost::assign::map_list_of + ("IQ", (0x1 << 4) | (0x0 << 0)) //DAC0Q=DUC0Q, DAC0I=DUC0I + ("QI", (0x0 << 4) | (0x1 << 0)) //DAC0Q=DUC0I, DAC0I=DUC0Q + ("I", (0xf << 4) | (0x0 << 0)) //DAC0Q=ZERO, DAC0I=DUC0I + ("Q", (0x0 << 4) | (0xf << 0)) //DAC0Q=DUC0I, DAC0I=ZERO + ; + _iface->poke32(REG_TX_FE_MUX, mode_to_mux[mode]); + } + + void set_dc_offset(const std::complex<double> &off){ + _iface->poke32(REG_TX_FE_DC_OFFSET_I, fs_to_bits(off.real(), 24)); + _iface->poke32(REG_TX_FE_DC_OFFSET_Q, fs_to_bits(off.imag(), 24)); + } + + void set_correction(const std::complex<double> &cor){ + _iface->poke32(REG_TX_FE_MAG_CORRECTION, fs_to_bits(std::abs(cor), 18)); + _iface->poke32(REG_TX_FE_PHASE_CORRECTION, fs_to_bits(std::atan2(cor.real(), cor.imag()), 18)); + } + +private: + wb_iface::sptr _iface; + const size_t _base; +}; + +tx_frontend_core_200::sptr tx_frontend_core_200::make(wb_iface::sptr iface, const size_t base){ + return sptr(new tx_frontend_core_200_impl(iface, base)); +} diff --git a/host/lib/usrp/cores/tx_frontend_core_200.hpp b/host/lib/usrp/cores/tx_frontend_core_200.hpp new file mode 100644 index 000000000..9e4a7bc79 --- /dev/null +++ b/host/lib/usrp/cores/tx_frontend_core_200.hpp @@ -0,0 +1,42 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_RX_FRONTEND_CORE_200_HPP +#define INCLUDED_LIBUHD_USRP_RX_FRONTEND_CORE_200_HPP + +#include <uhd/config.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include "wb_iface.hpp" +#include <complex> +#include <string> + +class tx_frontend_core_200 : boost::noncopyable{ +public: + typedef boost::shared_ptr<tx_frontend_core_200> sptr; + + static sptr make(wb_iface::sptr iface, const size_t base); + + virtual void set_mux(const std::string &mode) = 0; + + virtual void set_dc_offset(const std::complex<double> &off) = 0; + + virtual void set_correction(const std::complex<double> &cor) = 0; + +}; + +#endif /* INCLUDED_LIBUHD_USRP_RX_FRONTEND_CORE_200_HPP */ diff --git a/host/lib/usrp/cores/wb_iface.hpp b/host/lib/usrp/cores/wb_iface.hpp new file mode 100644 index 000000000..982594b21 --- /dev/null +++ b/host/lib/usrp/cores/wb_iface.hpp @@ -0,0 +1,60 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_WB_IFACE_HPP +#define INCLUDED_LIBUHD_USRP_WB_IFACE_HPP + +#include <uhd/config.hpp> +#include <boost/cstdint.hpp> +#include <boost/shared_ptr.hpp> + +class wb_iface{ +public: + typedef boost::shared_ptr<wb_iface> sptr; + typedef boost::uint32_t wb_addr_type; + + /*! + * Write a register (32 bits) + * \param addr the address + * \param data the 32bit data + */ + virtual void poke32(wb_addr_type addr, boost::uint32_t data) = 0; + + /*! + * Read a register (32 bits) + * \param addr the address + * \return the 32bit data + */ + virtual boost::uint32_t peek32(wb_addr_type addr) = 0; + + /*! + * Write a register (16 bits) + * \param addr the address + * \param data the 16bit data + */ + virtual void poke16(wb_addr_type addr, boost::uint16_t data) = 0; + + /*! + * Read a register (16 bits) + * \param addr the address + * \return the 16bit data + */ + virtual boost::uint16_t peek16(wb_addr_type addr) = 0; + +}; + +#endif /* INCLUDED_LIBUHD_USRP_WB_IFACE_HPP */ diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index 566e24d97..ff93f1d89 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -15,7 +15,6 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/usrp/subdev_props.hpp> #include <uhd/types/dict.hpp> #include <uhd/types/ranges.hpp> #include <uhd/utils/assert_has.hpp> @@ -162,6 +161,10 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(1, ""); //vector of 1 empty string return; + case SUBDEV_PROP_SENSOR_NAMES: + val = prop_names_t(1, ""); //vector of 1 empty string + return; + case SUBDEV_PROP_CONNECTION: val = sd_name_to_conn[get_subdev_name()]; return; @@ -268,6 +271,10 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(1, ""); //vector of 1 empty string return; + case SUBDEV_PROP_SENSOR_NAMES: + val = prop_names_t(1, ""); //vector of 1 empty string + return; + case SUBDEV_PROP_CONNECTION: val = sd_name_to_conn[get_subdev_name()]; return; diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp index cfe06db29..c65c52590 100644 --- a/host/lib/usrp/dboard/db_dbsrx.cpp +++ b/host/lib/usrp/dboard/db_dbsrx.cpp @@ -28,7 +28,6 @@ #include <uhd/types/ranges.hpp> #include <uhd/types/sensors.hpp> #include <uhd/types/dict.hpp> -#include <uhd/usrp/subdev_props.hpp> #include <uhd/usrp/dboard_base.hpp> #include <uhd/usrp/dboard_manager.hpp> #include <boost/assign/list_of.hpp> diff --git a/host/lib/usrp/dboard/db_dbsrx2.cpp b/host/lib/usrp/dboard/db_dbsrx2.cpp index f646a238f..f19236907 100644 --- a/host/lib/usrp/dboard/db_dbsrx2.cpp +++ b/host/lib/usrp/dboard/db_dbsrx2.cpp @@ -25,7 +25,6 @@ #include <uhd/types/ranges.hpp> #include <uhd/types/sensors.hpp> #include <uhd/types/dict.hpp> -#include <uhd/usrp/subdev_props.hpp> #include <uhd/usrp/dboard_base.hpp> #include <uhd/usrp/dboard_manager.hpp> #include <boost/assign/list_of.hpp> diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index 61f9130d4..14129ef72 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -34,7 +34,6 @@ #include "adf4360_regs.hpp" #include <uhd/types/dict.hpp> -#include <uhd/usrp/subdev_props.hpp> #include <uhd/types/ranges.hpp> #include <uhd/types/sensors.hpp> #include <uhd/utils/assert_has.hpp> diff --git a/host/lib/usrp/dboard/db_sbx.cpp b/host/lib/usrp/dboard/db_sbx.cpp index 6ca89b81a..aa9556e77 100644 --- a/host/lib/usrp/dboard/db_sbx.cpp +++ b/host/lib/usrp/dboard/db_sbx.cpp @@ -74,7 +74,6 @@ #include "adf4350_regs.hpp" #include <uhd/types/dict.hpp> -#include <uhd/usrp/subdev_props.hpp> #include <uhd/types/ranges.hpp> #include <uhd/types/sensors.hpp> #include <uhd/utils/assert_has.hpp> diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 1ff0fb785..3b8b276e0 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -35,7 +35,6 @@ #include <uhd/types/ranges.hpp> #include <uhd/types/sensors.hpp> #include <uhd/types/dict.hpp> -#include <uhd/usrp/subdev_props.hpp> #include <uhd/usrp/dboard_base.hpp> #include <uhd/usrp/dboard_manager.hpp> #include <boost/assign/list_of.hpp> diff --git a/host/lib/usrp/dboard/db_tvrx2.cpp b/host/lib/usrp/dboard/db_tvrx2.cpp index 39ff90d79..23f203b8c 100644 --- a/host/lib/usrp/dboard/db_tvrx2.cpp +++ b/host/lib/usrp/dboard/db_tvrx2.cpp @@ -59,7 +59,6 @@ #include <uhd/types/ranges.hpp> #include <uhd/types/sensors.hpp> #include <uhd/types/dict.hpp> -#include <uhd/usrp/subdev_props.hpp> #include <uhd/usrp/dboard_base.hpp> #include <uhd/usrp/dboard_manager.hpp> #include <boost/assign/list_of.hpp> diff --git a/host/lib/usrp/dboard/db_unknown.cpp b/host/lib/usrp/dboard/db_unknown.cpp index 6cacab231..0587d015c 100644 --- a/host/lib/usrp/dboard/db_unknown.cpp +++ b/host/lib/usrp/dboard/db_unknown.cpp @@ -15,7 +15,6 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/usrp/subdev_props.hpp> #include <uhd/types/ranges.hpp> #include <uhd/utils/assert_has.hpp> #include <uhd/utils/static.hpp> @@ -142,6 +141,10 @@ void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(1, ""); //vector of 1 empty string return; + case SUBDEV_PROP_SENSOR_NAMES: + val = prop_names_t(1, ""); //vector of 1 empty string + return; + case SUBDEV_PROP_CONNECTION: val = SUBDEV_CONN_COMPLEX_IQ; return; @@ -238,6 +241,10 @@ void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(1, ""); //vector of 1 empty string return; + case SUBDEV_PROP_SENSOR_NAMES: + val = prop_names_t(1, ""); //vector of 1 empty string + return; + case SUBDEV_PROP_CONNECTION: val = SUBDEV_CONN_COMPLEX_IQ; return; diff --git a/host/lib/usrp/dboard/db_wbx_common.cpp b/host/lib/usrp/dboard/db_wbx_common.cpp index c21ba80dc..1089dc7c2 100644 --- a/host/lib/usrp/dboard/db_wbx_common.cpp +++ b/host/lib/usrp/dboard/db_wbx_common.cpp @@ -61,7 +61,6 @@ #include "adf4350_regs.hpp" #include <uhd/utils/log.hpp> #include <uhd/types/dict.hpp> -#include <uhd/usrp/subdev_props.hpp> #include <uhd/types/ranges.hpp> #include <uhd/types/sensors.hpp> #include <uhd/utils/assert_has.hpp> diff --git a/host/lib/usrp/dboard/db_wbx_simple.cpp b/host/lib/usrp/dboard/db_wbx_simple.cpp index aa4937b19..990bacbc8 100644 --- a/host/lib/usrp/dboard/db_wbx_simple.cpp +++ b/host/lib/usrp/dboard/db_wbx_simple.cpp @@ -26,7 +26,6 @@ #include <uhd/utils/static.hpp> #include <uhd/utils/assert_has.hpp> #include <uhd/usrp/dboard_manager.hpp> -#include <uhd/usrp/subdev_props.hpp> #include <boost/assign/list_of.hpp> using namespace uhd; diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index fcd05ea04..b88eb2a95 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -56,7 +56,6 @@ #include <uhd/types/ranges.hpp> #include <uhd/types/sensors.hpp> #include <uhd/types/dict.hpp> -#include <uhd/usrp/subdev_props.hpp> #include <uhd/usrp/dboard_base.hpp> #include <uhd/usrp/dboard_manager.hpp> #include <boost/assign/list_of.hpp> diff --git a/host/lib/usrp/dboard_eeprom.cpp b/host/lib/usrp/dboard_eeprom.cpp index 0dc3471f7..b3cb54c1c 100644 --- a/host/lib/usrp/dboard_eeprom.cpp +++ b/host/lib/usrp/dboard_eeprom.cpp @@ -133,7 +133,7 @@ void dboard_eeprom_t::load(i2c_iface &iface, boost::uint8_t addr){ } } -void dboard_eeprom_t::store(i2c_iface &iface, boost::uint8_t addr){ +void dboard_eeprom_t::store(i2c_iface &iface, boost::uint8_t addr) const{ byte_vector_t bytes(DB_EEPROM_CLEN, 0); //defaults to all zeros bytes[DB_EEPROM_MAGIC] = DB_EEPROM_MAGIC_VALUE; diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 3cc2ca3c0..3f4b5a511 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -17,7 +17,6 @@ #include "dboard_ctor_args.hpp" #include <uhd/usrp/dboard_manager.hpp> -#include <uhd/usrp/subdev_props.hpp> #include <uhd/utils/msg.hpp> #include <uhd/utils/log.hpp> #include <uhd/utils/safe_call.hpp> @@ -404,3 +403,125 @@ void dboard_manager_impl::set_nice_dboard_if(void){ this->get_tx_subdev(sd_name)[SUBDEV_PROP_ENABLED] = false; } } + +/*********************************************************************** + * Populate a properties tree from a subdev waxy object + **********************************************************************/ +#include <uhd/types/ranges.hpp> +#include <uhd/types/sensors.hpp> + +static sensor_value_t get_sensor(wax::obj subdev, const std::string &name){ + return subdev[named_prop_t(SUBDEV_PROP_SENSOR, name)].as<sensor_value_t>(); +} + +static void set_gain(wax::obj subdev, const std::string &name, const double gain){ + subdev[named_prop_t(SUBDEV_PROP_GAIN, name)] = gain; +} + +static double get_gain(wax::obj subdev, const std::string &name){ + return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<double>(); +} + +static meta_range_t get_gain_range(wax::obj subdev, const std::string &name){ + return subdev[named_prop_t(SUBDEV_PROP_GAIN_RANGE, name)].as<meta_range_t>(); +} + +static void set_freq(wax::obj subdev, const double freq){ + subdev[SUBDEV_PROP_FREQ] = freq; +} + +static double get_freq(wax::obj subdev){ + return subdev[SUBDEV_PROP_FREQ].as<double>(); +} + +static meta_range_t get_freq_range(wax::obj subdev){ + return subdev[SUBDEV_PROP_FREQ_RANGE].as<meta_range_t>(); +} + +static void set_ant(wax::obj subdev, const std::string &ant){ + subdev[SUBDEV_PROP_ANTENNA] = ant; +} + +static std::string get_ant(wax::obj subdev){ + return subdev[SUBDEV_PROP_ANTENNA].as<std::string>(); +} + +static std::vector<std::string> get_ants(wax::obj subdev){ + return subdev[SUBDEV_PROP_ANTENNA_NAMES].as<std::vector<std::string> >(); +} + +static std::string get_conn(wax::obj subdev){ + switch(subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){ + case SUBDEV_CONN_COMPLEX_IQ: return "IQ"; + case SUBDEV_CONN_COMPLEX_QI: return "QI"; + case SUBDEV_CONN_REAL_I: return "I"; + case SUBDEV_CONN_REAL_Q: return "Q"; + } + UHD_THROW_INVALID_CODE_PATH(); +} + +static bool get_use_lo_off(wax::obj subdev){ + return subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>(); +} + +static bool get_set_enb(wax::obj subdev, const bool enb){ + subdev[SUBDEV_PROP_ENABLED] = enb; + return subdev[SUBDEV_PROP_ENABLED].as<bool>(); +} + +static void set_bw(wax::obj subdev, const double freq){ + subdev[SUBDEV_PROP_BANDWIDTH] = freq; +} + +static double get_bw(wax::obj subdev){ + return subdev[SUBDEV_PROP_BANDWIDTH].as<double>(); +} + +void dboard_manager::populate_prop_tree_from_subdev( + property_tree::sptr subtree, wax::obj subdev +){ + subtree->create<std::string>("name").set(subdev[SUBDEV_PROP_NAME].as<std::string>()); + + const prop_names_t sensor_names = subdev[SUBDEV_PROP_SENSOR_NAMES].as<prop_names_t>(); + BOOST_FOREACH(const std::string &name, sensor_names){ + subtree->create<sensor_value_t>("sensors/" + name) + .publish(boost::bind(&get_sensor, subdev, name)); + } + + const prop_names_t gain_names = subdev[SUBDEV_PROP_GAIN_NAMES].as<prop_names_t>(); + subtree->create<int>("gains"); //phony property so this dir exists + BOOST_FOREACH(const std::string &name, gain_names){ + subtree->create<double>("gains/" + name + "/value") + .publish(boost::bind(&get_gain, subdev, name)) + .subscribe(boost::bind(&set_gain, subdev, name, _1)); + subtree->create<meta_range_t>("gains/" + name + "/range") + .publish(boost::bind(&get_gain_range, subdev, name)); + } + + subtree->create<double>("freq/value") + .publish(boost::bind(&get_freq, subdev)) + .subscribe(boost::bind(&set_freq, subdev, _1)); + + subtree->create<meta_range_t>("freq/range") + .publish(boost::bind(&get_freq_range, subdev)); + + subtree->create<std::string>("antenna/value") + .publish(boost::bind(&get_ant, subdev)) + .subscribe(boost::bind(&set_ant, subdev, _1)); + + subtree->create<std::vector<std::string> >("antenna/options") + .publish(boost::bind(&get_ants, subdev)); + + subtree->create<std::string>("connection") + .publish(boost::bind(&get_conn, subdev)); + + subtree->create<bool>("enabled") + .coerce(boost::bind(&get_set_enb, subdev, _1)); + + subtree->create<bool>("use_lo_offset") + .publish(boost::bind(&get_use_lo_off, subdev)); + + subtree->create<double>("bandwidth/value") + .publish(boost::bind(&get_bw, subdev)) + .subscribe(boost::bind(&set_bw, subdev, _1)); +} diff --git a/host/lib/usrp/dsp_utils.cpp b/host/lib/usrp/dsp_utils.cpp deleted file mode 100644 index 2686e895b..000000000 --- a/host/lib/usrp/dsp_utils.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/types/dict.hpp> -#include <uhd/exception.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/tuple/tuple.hpp> -#include <boost/math/special_functions/round.hpp> -#include <boost/math/special_functions/sign.hpp> -#include <algorithm> -#include <cmath> - -using namespace uhd; -using namespace uhd::usrp; - -template <class T> T ceil_log2(T num){ - return std::ceil(std::log(num)/std::log(T(2))); -} - -/*! - * 3 2 1 0 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------------------------------+-------+-------+-------+-------+ - * | | DDC0Q | DDC0I | - * +-------------------------------+-------+-------+-------+-------+ - */ -boost::uint32_t dsp_type1::calc_rx_mux_word(subdev_conn_t subdev_conn){ - switch(subdev_conn){ - case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 4) | (0x0 << 0); //DDC0Q=ADC0Q, DDC0I=ADC0I - case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 4) | (0x1 << 0); //DDC0Q=ADC0I, DDC0I=ADC0Q - case SUBDEV_CONN_REAL_I: return (0xf << 4) | (0x0 << 0); //DDC0Q=ZERO, DDC0I=ADC0I - case SUBDEV_CONN_REAL_Q: return (0xf << 4) | (0x1 << 0); //DDC0Q=ZERO, DDC0I=ADC0Q - default: UHD_THROW_INVALID_CODE_PATH(); - } -} - -/*! - * 3 2 1 0 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------------------------------+-------+-------+-------+-------+ - * | | DAC0Q | DAC0I | - * +-------------------------------+-------+-------+-------+-------+ - */ -boost::uint32_t dsp_type1::calc_tx_mux_word(subdev_conn_t subdev_conn){ - switch(subdev_conn){ - case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 4) | (0x0 << 0); //DAC0Q=DUC0Q, DAC0I=DUC0I - case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 4) | (0x1 << 0); //DAC0Q=DUC0I, DAC0I=DUC0Q - case SUBDEV_CONN_REAL_I: return (0xf << 4) | (0x0 << 0); //DAC0Q=ZERO, DAC0I=DUC0I - case SUBDEV_CONN_REAL_Q: return (0x0 << 4) | (0xf << 0); //DAC0Q=DUC0I, DAC0I=ZERO - default: UHD_THROW_INVALID_CODE_PATH(); - } -} - -boost::uint32_t dsp_type1::calc_cordic_word_and_update( - double &freq, double codec_rate -){ - //correct for outside of rate (wrap around) - freq = std::fmod(freq, codec_rate); - if (std::abs(freq) > codec_rate/2.0) - freq -= boost::math::sign(freq)*codec_rate; - - //calculate the freq register word (signed) - UHD_ASSERT_THROW(std::abs(freq) <= codec_rate/2.0); - static const double scale_factor = std::pow(2.0, 32); - boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / codec_rate) * scale_factor)); - - //update the actual frequency - freq = (double(freq_word) / scale_factor) * codec_rate; - - return boost::uint32_t(freq_word); -} - -boost::uint32_t dsp_type1::calc_cic_filter_word(unsigned rate){ - int hb0 = 0, hb1 = 0; - if (not (rate & 0x1)){ - hb0 = 1; - rate /= 2; - } - if (not (rate & 0x1)){ - hb1 = 1; - rate /= 2; - } - return (hb1 << 9) | (hb0 << 8) | (rate & 0xff); -} - -boost::uint32_t dsp_type1::calc_iq_scale_word( - boost::int16_t i, boost::int16_t q -){ - return (boost::uint32_t(i) << 16) | (boost::uint32_t(q) << 0); -} - -boost::uint32_t dsp_type1::calc_iq_scale_word(unsigned rate){ - // Calculate CIC interpolation (i.e., without halfband interpolators) - unsigned tmp_rate = calc_cic_filter_word(rate) & 0xff; - - // Calculate closest multiplier constant to reverse gain absent scale multipliers - double rate_cubed = std::pow(double(tmp_rate), 3); - boost::int16_t scale = boost::math::iround((4096*std::pow(2, ceil_log2(rate_cubed)))/(1.65*rate_cubed)); - return calc_iq_scale_word(scale, scale); -} - -boost::uint32_t dsp_type1::calc_stream_cmd_word(const stream_cmd_t &stream_cmd){ - UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x3fffffff); - - //setup the mode to instruction flags - typedef boost::tuple<bool, bool, bool> inst_t; - static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of - //reload, chain, samps - (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false)) - (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false)) - (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true)) - (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true)) - ; - - //setup the instruction flag values - bool inst_reload, inst_chain, inst_samps; - boost::tie(inst_reload, inst_chain, inst_samps) = mode_to_inst[stream_cmd.stream_mode]; - - //calculate the word from flags and length - boost::uint32_t word = 0; - word |= boost::uint32_t((stream_cmd.stream_now)? 1 : 0) << 31; - word |= boost::uint32_t((inst_chain)? 1 : 0) << 30; - word |= boost::uint32_t((inst_reload)? 1 : 0) << 29; - word |= (inst_samps)? stream_cmd.num_samps : ((inst_chain)? 1 : 0); - return word; -} diff --git a/host/lib/usrp/usrp_e100/CMakeLists.txt b/host/lib/usrp/e100/CMakeLists.txt index d0e20a3d8..ac9d8c655 100644 --- a/host/lib/usrp/usrp_e100/CMakeLists.txt +++ b/host/lib/usrp/e100/CMakeLists.txt @@ -22,28 +22,19 @@ ######################################################################## # Conditionally configure the USRP-E100 support ######################################################################## -LIBUHD_REGISTER_COMPONENT("USRP-E100" ENABLE_USRP_E100 OFF "ENABLE_LIBUHD;LINUX" OFF) +LIBUHD_REGISTER_COMPONENT("E100" ENABLE_E100 OFF "ENABLE_LIBUHD;LINUX" OFF) -IF(ENABLE_USRP_E100) +IF(ENABLE_E100) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/e100_ctrl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/e100_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/e100_mmap_zero_copy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/fpga_downloader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_impl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_iface.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_mmap_zero_copy.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_regs.hpp ) -ENDIF(ENABLE_USRP_E100) +ENDIF(ENABLE_E100) diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.cpp b/host/lib/usrp/e100/clock_ctrl.cpp index f1b29840a..6acb13528 100644 --- a/host/lib/usrp/usrp_e100/clock_ctrl.cpp +++ b/host/lib/usrp/e100/clock_ctrl.cpp @@ -21,7 +21,7 @@ #include <uhd/utils/log.hpp> #include <uhd/utils/assert_has.hpp> #include <boost/cstdint.hpp> -#include "usrp_e100_regs.hpp" //spi slave constants +#include "e100_regs.hpp" //spi slave constants #include <boost/assign/list_of.hpp> #include <boost/foreach.hpp> #include <boost/format.hpp> @@ -165,13 +165,19 @@ static clock_settings_type get_clock_settings(double rate){ /*********************************************************************** * Clock Control Implementation **********************************************************************/ -class usrp_e100_clock_ctrl_impl : public usrp_e100_clock_ctrl{ +class e100_clock_ctrl_impl : public e100_clock_ctrl{ public: - usrp_e100_clock_ctrl_impl(usrp_e100_iface::sptr iface, double master_clock_rate){ + e100_clock_ctrl_impl(spi_iface::sptr iface, double master_clock_rate){ _iface = iface; _chan_rate = 0.0; _out_rate = 0.0; + //perform soft-reset + _ad9522_regs.soft_reset = 1; + this->send_reg(0x000); + this->latch_regs(); + _ad9522_regs.soft_reset = 0; + //init the clock gen registers //Note: out0 should already be clocking the FPGA or this isnt going to work _ad9522_regs.sdo_active = ad9522_regs_t::SDO_ACTIVE_SDO_SDIO; @@ -192,7 +198,7 @@ public: this->enable_tx_dboard_clock(false); } - ~usrp_e100_clock_ctrl_impl(void){ + ~e100_clock_ctrl_impl(void){ this->enable_test_clock(ENABLE_THE_TEST_OUT); this->enable_rx_dboard_clock(false); this->enable_tx_dboard_clock(false); @@ -288,10 +294,8 @@ public: if (_out_rate == rate) return; if (rate == 61.44e6) set_clock_settings_with_external_vcxo(rate); else set_clock_settings_with_internal_vco(rate); - //clock rate changed! update dboard clocks and FPGA ticks per second set_rx_dboard_clock_rate(rate); set_tx_dboard_clock_rate(rate); - _iface->poke32(UE_REG_TIME64_TPS, boost::uint32_t(get_fpga_clock_rate())); } double get_fpga_clock_rate(void){ @@ -415,7 +419,7 @@ public: } private: - usrp_e100_iface::sptr _iface; + spi_iface::sptr _iface; ad9522_regs_t _ad9522_regs; double _out_rate; //rate at the fpga and codec double _chan_rate; //rate before final dividers @@ -437,8 +441,6 @@ private: } void calibrate_now(void){ - set_ignore_sync_fpga_plus_codec(false); //want vco cal to sync - //vco calibration routine: _ad9522_regs.vco_calibration_now = 0; this->send_reg(0x18); @@ -467,20 +469,9 @@ private: _ad9522_regs.get_read_reg(addr), 24 ); _ad9522_regs.set_reg(addr, reg); - if (_ad9522_regs.digital_lock_detect) goto finalize; + if (_ad9522_regs.digital_lock_detect) return; } UHD_MSG(error) << "USRP-E100 clock control: lock detection timeout" << std::endl; - finalize: - - set_ignore_sync_fpga_plus_codec(true); //never loose sync between these two - } - - void set_ignore_sync_fpga_plus_codec(bool enb){ - _ad9522_regs.divider0_ignore_sync = (enb)?1:0; // master FPGA clock ignores sync (always on, cannot be disabled by sync pulse) - _ad9522_regs.divider1_ignore_sync = (enb)?1:0; // codec clock ignores sync (always on, cannot be disabled by sync pulse) - this->send_reg(0x191); - this->send_reg(0x194); - this->latch_regs(); } void soft_sync(void){ @@ -514,6 +505,6 @@ private: /*********************************************************************** * Clock Control Make **********************************************************************/ -usrp_e100_clock_ctrl::sptr usrp_e100_clock_ctrl::make(usrp_e100_iface::sptr iface, double master_clock_rate){ - return sptr(new usrp_e100_clock_ctrl_impl(iface, master_clock_rate)); +e100_clock_ctrl::sptr e100_clock_ctrl::make(spi_iface::sptr iface, double master_clock_rate){ + return sptr(new e100_clock_ctrl_impl(iface, master_clock_rate)); } diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.hpp b/host/lib/usrp/e100/clock_ctrl.hpp index 6f16bc6ed..7c16649d3 100644 --- a/host/lib/usrp/usrp_e100/clock_ctrl.hpp +++ b/host/lib/usrp/e100/clock_ctrl.hpp @@ -18,7 +18,7 @@ #ifndef INCLUDED_USRP_E100_CLOCK_CTRL_HPP #define INCLUDED_USRP_E100_CLOCK_CTRL_HPP -#include "usrp_e100_iface.hpp" +#include <uhd/types/serial.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> #include <vector> @@ -28,17 +28,17 @@ * - Setup system clocks. * - Disable/enable clock lines. */ -class usrp_e100_clock_ctrl : boost::noncopyable{ +class e100_clock_ctrl : boost::noncopyable{ public: - typedef boost::shared_ptr<usrp_e100_clock_ctrl> sptr; + typedef boost::shared_ptr<e100_clock_ctrl> sptr; /*! * Make a new clock control object. - * \param iface the usrp_e100 iface object + * \param iface the spi iface object * \param master clock rate the FPGA rate * \return the clock control object */ - static sptr make(usrp_e100_iface::sptr iface, double master_clock_rate); + static sptr make(uhd::spi_iface::sptr iface, double master_clock_rate); /*! * Set the rate of the fpga clock line. diff --git a/host/lib/usrp/usrp_e100/codec_ctrl.cpp b/host/lib/usrp/e100/codec_ctrl.cpp index 43ad94a88..6efeb10e8 100644 --- a/host/lib/usrp/usrp_e100/codec_ctrl.cpp +++ b/host/lib/usrp/e100/codec_ctrl.cpp @@ -24,22 +24,22 @@ #include <boost/cstdint.hpp> #include <boost/tuple/tuple.hpp> #include <boost/math/special_functions/round.hpp> -#include "usrp_e100_regs.hpp" //spi slave constants +#include "e100_regs.hpp" //spi slave constants #include <boost/assign/list_of.hpp> using namespace uhd; -const gain_range_t usrp_e100_codec_ctrl::tx_pga_gain_range(-20, 0, double(0.1)); -const gain_range_t usrp_e100_codec_ctrl::rx_pga_gain_range(0, 20, 1); +const gain_range_t e100_codec_ctrl::tx_pga_gain_range(-20, 0, double(0.1)); +const gain_range_t e100_codec_ctrl::rx_pga_gain_range(0, 20, 1); /*********************************************************************** * Codec Control Implementation **********************************************************************/ -class usrp_e100_codec_ctrl_impl : public usrp_e100_codec_ctrl{ +class e100_codec_ctrl_impl : public e100_codec_ctrl{ public: //structors - usrp_e100_codec_ctrl_impl(usrp_e100_iface::sptr iface); - ~usrp_e100_codec_ctrl_impl(void); + e100_codec_ctrl_impl(spi_iface::sptr iface); + ~e100_codec_ctrl_impl(void); //aux adc and dac control double read_aux_adc(aux_adc_t which); @@ -52,7 +52,7 @@ public: double get_rx_pga_gain(char); private: - usrp_e100_iface::sptr _iface; + spi_iface::sptr _iface; ad9862_regs_t _ad9862_regs; void send_reg(boost::uint8_t addr); void recv_reg(boost::uint8_t addr); @@ -61,7 +61,7 @@ private: /*********************************************************************** * Codec Control Structors **********************************************************************/ -usrp_e100_codec_ctrl_impl::usrp_e100_codec_ctrl_impl(usrp_e100_iface::sptr iface){ +e100_codec_ctrl_impl::e100_codec_ctrl_impl(spi_iface::sptr iface){ _iface = iface; //soft reset @@ -116,7 +116,7 @@ usrp_e100_codec_ctrl_impl::usrp_e100_codec_ctrl_impl(usrp_e100_iface::sptr iface this->send_reg(34); } -usrp_e100_codec_ctrl_impl::~usrp_e100_codec_ctrl_impl(void){ +e100_codec_ctrl_impl::~e100_codec_ctrl_impl(void){ //set aux dacs to zero this->write_aux_dac(AUX_DAC_A, 0); this->write_aux_dac(AUX_DAC_B, 0); @@ -136,19 +136,19 @@ usrp_e100_codec_ctrl_impl::~usrp_e100_codec_ctrl_impl(void){ **********************************************************************/ static const int mtpgw = 255; //maximum tx pga gain word -void usrp_e100_codec_ctrl_impl::set_tx_pga_gain(double gain){ +void e100_codec_ctrl_impl::set_tx_pga_gain(double gain){ int gain_word = int(mtpgw*(gain - tx_pga_gain_range.start())/(tx_pga_gain_range.stop() - tx_pga_gain_range.start())); _ad9862_regs.tx_pga_gain = uhd::clip(gain_word, 0, mtpgw); this->send_reg(16); } -double usrp_e100_codec_ctrl_impl::get_tx_pga_gain(void){ +double e100_codec_ctrl_impl::get_tx_pga_gain(void){ return (_ad9862_regs.tx_pga_gain*(tx_pga_gain_range.stop() - tx_pga_gain_range.start())/mtpgw) + tx_pga_gain_range.start(); } static const int mrpgw = 0x14; //maximum rx pga gain word -void usrp_e100_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){ +void e100_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){ int gain_word = int(mrpgw*(gain - rx_pga_gain_range.start())/(rx_pga_gain_range.stop() - rx_pga_gain_range.start())); gain_word = uhd::clip(gain_word, 0, mrpgw); switch(which){ @@ -164,7 +164,7 @@ void usrp_e100_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){ } } -double usrp_e100_codec_ctrl_impl::get_rx_pga_gain(char which){ +double e100_codec_ctrl_impl::get_rx_pga_gain(char which){ int gain_word; switch(which){ case 'A': gain_word = _ad9862_regs.rx_pga_a; break; @@ -181,7 +181,7 @@ static double aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low){ return double((boost::uint16_t(high) << 2) | low)*3.3/0x3ff; } -double usrp_e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){ +double e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){ switch(which){ case AUX_ADC_A1: _ad9862_regs.select_a = ad9862_regs_t::SELECT_A_AUX_ADC1; @@ -217,7 +217,7 @@ double usrp_e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){ /*********************************************************************** * Codec Control AUX DAC Methods **********************************************************************/ -void usrp_e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts){ +void e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts){ //special case for aux dac d (aka sigma delta word) if (which == AUX_DAC_D){ boost::uint16_t dac_word = uhd::clip(boost::math::iround(volts*0xfff/3.3), 0, 0xfff); @@ -250,7 +250,7 @@ void usrp_e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts){ /*********************************************************************** * Codec Control SPI Methods **********************************************************************/ -void usrp_e100_codec_ctrl_impl::send_reg(boost::uint8_t addr){ +void e100_codec_ctrl_impl::send_reg(boost::uint8_t addr){ boost::uint32_t reg = _ad9862_regs.get_write_reg(addr); UHD_LOGV(often) << "codec control write reg: " << std::hex << reg << std::endl; _iface->write_spi( @@ -260,7 +260,7 @@ void usrp_e100_codec_ctrl_impl::send_reg(boost::uint8_t addr){ ); } -void usrp_e100_codec_ctrl_impl::recv_reg(boost::uint8_t addr){ +void e100_codec_ctrl_impl::recv_reg(boost::uint8_t addr){ boost::uint32_t reg = _ad9862_regs.get_read_reg(addr); UHD_LOGV(often) << "codec control read reg: " << std::hex << reg << std::endl; boost::uint32_t ret = _iface->read_spi( @@ -275,6 +275,6 @@ void usrp_e100_codec_ctrl_impl::recv_reg(boost::uint8_t addr){ /*********************************************************************** * Codec Control Make **********************************************************************/ -usrp_e100_codec_ctrl::sptr usrp_e100_codec_ctrl::make(usrp_e100_iface::sptr iface){ - return sptr(new usrp_e100_codec_ctrl_impl(iface)); +e100_codec_ctrl::sptr e100_codec_ctrl::make(spi_iface::sptr iface){ + return sptr(new e100_codec_ctrl_impl(iface)); } diff --git a/host/lib/usrp/usrp_e100/codec_ctrl.hpp b/host/lib/usrp/e100/codec_ctrl.hpp index 05d7aab38..707f6f521 100644 --- a/host/lib/usrp/usrp_e100/codec_ctrl.hpp +++ b/host/lib/usrp/e100/codec_ctrl.hpp @@ -18,7 +18,7 @@ #ifndef INCLUDED_USRP_E100_CODEC_CTRL_HPP #define INCLUDED_USRP_E100_CODEC_CTRL_HPP -#include "usrp_e100_iface.hpp" +#include <uhd/types/serial.hpp> #include <uhd/types/ranges.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> @@ -28,19 +28,19 @@ * - Init/power down codec. * - Read aux adc, write aux dac. */ -class usrp_e100_codec_ctrl : boost::noncopyable{ +class e100_codec_ctrl : boost::noncopyable{ public: - typedef boost::shared_ptr<usrp_e100_codec_ctrl> sptr; + typedef boost::shared_ptr<e100_codec_ctrl> sptr; static const uhd::gain_range_t tx_pga_gain_range; static const uhd::gain_range_t rx_pga_gain_range; /*! * Make a new codec control object. - * \param iface the usrp_e100 iface object + * \param iface the spi iface object * \return the codec control object */ - static sptr make(usrp_e100_iface::sptr iface); + static sptr make(uhd::spi_iface::sptr iface); //! aux adc identifier constants enum aux_adc_t{ diff --git a/host/lib/usrp/usrp_e100/dboard_iface.cpp b/host/lib/usrp/e100/dboard_iface.cpp index 61b5a1c92..d45577bd9 100644 --- a/host/lib/usrp/usrp_e100/dboard_iface.cpp +++ b/host/lib/usrp/e100/dboard_iface.cpp @@ -15,8 +15,9 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include "usrp_e100_iface.hpp" -#include "usrp_e100_regs.hpp" +#include "wb_iface.hpp" +#include <uhd/types/serial.hpp> +#include "e100_regs.hpp" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" #include <uhd/usrp/dboard_iface.hpp> @@ -29,15 +30,19 @@ using namespace uhd; using namespace uhd::usrp; using namespace boost::assign; -class usrp_e100_dboard_iface : public dboard_iface{ +class e100_dboard_iface : public dboard_iface{ public: - usrp_e100_dboard_iface( - usrp_e100_iface::sptr iface, - usrp_e100_clock_ctrl::sptr clock, - usrp_e100_codec_ctrl::sptr codec + e100_dboard_iface( + wb_iface::sptr wb_iface, + i2c_iface::sptr i2c_iface, + spi_iface::sptr spi_iface, + e100_clock_ctrl::sptr clock, + e100_codec_ctrl::sptr codec ){ - _iface = iface; + _wb_iface = wb_iface; + _i2c_iface = i2c_iface; + _spi_iface = spi_iface; _clock = clock; _codec = codec; @@ -45,11 +50,11 @@ public: this->set_clock_rate(UNIT_RX, _clock->get_fpga_clock_rate()); this->set_clock_rate(UNIT_TX, _clock->get_fpga_clock_rate()); - _iface->poke16(UE_REG_GPIO_RX_DBG, 0); - _iface->poke16(UE_REG_GPIO_TX_DBG, 0); + _wb_iface->poke16(E100_REG_GPIO_RX_DBG, 0); + _wb_iface->poke16(E100_REG_GPIO_TX_DBG, 0); } - ~usrp_e100_dboard_iface(void){ + ~e100_dboard_iface(void){ /* NOP */ } @@ -94,33 +99,37 @@ public: double get_codec_rate(unit_t); private: - usrp_e100_iface::sptr _iface; - usrp_e100_clock_ctrl::sptr _clock; - usrp_e100_codec_ctrl::sptr _codec; + wb_iface::sptr _wb_iface; + i2c_iface::sptr _i2c_iface; + spi_iface::sptr _spi_iface; + e100_clock_ctrl::sptr _clock; + e100_codec_ctrl::sptr _codec; }; /*********************************************************************** * Make Function **********************************************************************/ -dboard_iface::sptr make_usrp_e100_dboard_iface( - usrp_e100_iface::sptr iface, - usrp_e100_clock_ctrl::sptr clock, - usrp_e100_codec_ctrl::sptr codec +dboard_iface::sptr make_e100_dboard_iface( + wb_iface::sptr wb_iface, + i2c_iface::sptr i2c_iface, + spi_iface::sptr spi_iface, + e100_clock_ctrl::sptr clock, + e100_codec_ctrl::sptr codec ){ - return dboard_iface::sptr(new usrp_e100_dboard_iface(iface, clock, codec)); + return dboard_iface::sptr(new e100_dboard_iface(wb_iface, i2c_iface, spi_iface, clock, codec)); } /*********************************************************************** * Clock Rates **********************************************************************/ -void usrp_e100_dboard_iface::set_clock_rate(unit_t unit, double rate){ +void e100_dboard_iface::set_clock_rate(unit_t unit, double rate){ switch(unit){ case UNIT_RX: return _clock->set_rx_dboard_clock_rate(rate); case UNIT_TX: return _clock->set_tx_dboard_clock_rate(rate); } } -std::vector<double> usrp_e100_dboard_iface::get_clock_rates(unit_t unit){ +std::vector<double> e100_dboard_iface::get_clock_rates(unit_t unit){ switch(unit){ case UNIT_RX: return _clock->get_rx_dboard_clock_rates(); case UNIT_TX: return _clock->get_tx_dboard_clock_rates(); @@ -128,7 +137,7 @@ std::vector<double> usrp_e100_dboard_iface::get_clock_rates(unit_t unit){ } } -double usrp_e100_dboard_iface::get_clock_rate(unit_t unit){ +double e100_dboard_iface::get_clock_rate(unit_t unit){ switch(unit){ case UNIT_RX: return _clock->get_rx_clock_rate(); case UNIT_TX: return _clock->get_tx_clock_rate(); @@ -136,72 +145,72 @@ double usrp_e100_dboard_iface::get_clock_rate(unit_t unit){ UHD_THROW_INVALID_CODE_PATH(); } -void usrp_e100_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ +void e100_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ switch(unit){ case UNIT_RX: return _clock->enable_rx_dboard_clock(enb); case UNIT_TX: return _clock->enable_tx_dboard_clock(enb); } } -double usrp_e100_dboard_iface::get_codec_rate(unit_t){ +double e100_dboard_iface::get_codec_rate(unit_t){ return _clock->get_fpga_clock_rate(); } /*********************************************************************** * GPIO **********************************************************************/ -void usrp_e100_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){ +void e100_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){ UHD_ASSERT_THROW(GPIO_SEL_ATR == 1); //make this assumption switch(unit){ - case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_SEL, value); return; - case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_SEL, value); return; + case UNIT_RX: _wb_iface->poke16(E100_REG_GPIO_RX_SEL, value); return; + case UNIT_TX: _wb_iface->poke16(E100_REG_GPIO_TX_SEL, value); return; } } -void usrp_e100_dboard_iface::_set_gpio_ddr(unit_t unit, boost::uint16_t value){ +void e100_dboard_iface::_set_gpio_ddr(unit_t unit, boost::uint16_t value){ switch(unit){ - case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_DDR, value); return; - case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_DDR, value); return; + case UNIT_RX: _wb_iface->poke16(E100_REG_GPIO_RX_DDR, value); return; + case UNIT_TX: _wb_iface->poke16(E100_REG_GPIO_TX_DDR, value); return; } } -void usrp_e100_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){ +void e100_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){ switch(unit){ - case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_IO, value); return; - case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_IO, value); return; + case UNIT_RX: _wb_iface->poke16(E100_REG_GPIO_RX_IO, value); return; + case UNIT_TX: _wb_iface->poke16(E100_REG_GPIO_TX_IO, value); return; } } -boost::uint16_t usrp_e100_dboard_iface::read_gpio(unit_t unit){ +boost::uint16_t e100_dboard_iface::read_gpio(unit_t unit){ switch(unit){ - case UNIT_RX: return _iface->peek16(UE_REG_GPIO_RX_IO); - case UNIT_TX: return _iface->peek16(UE_REG_GPIO_TX_IO); + case UNIT_RX: return _wb_iface->peek16(E100_REG_GPIO_RX_IO); + case UNIT_TX: return _wb_iface->peek16(E100_REG_GPIO_TX_IO); default: UHD_THROW_INVALID_CODE_PATH(); } } -void usrp_e100_dboard_iface::_set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){ +void e100_dboard_iface::_set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){ //define mapping of unit to atr regs to register address static const uhd::dict< unit_t, uhd::dict<atr_reg_t, boost::uint32_t> > unit_to_atr_to_addr = map_list_of (UNIT_RX, map_list_of - (ATR_REG_IDLE, UE_REG_ATR_IDLE_RXSIDE) - (ATR_REG_TX_ONLY, UE_REG_ATR_INTX_RXSIDE) - (ATR_REG_RX_ONLY, UE_REG_ATR_INRX_RXSIDE) - (ATR_REG_FULL_DUPLEX, UE_REG_ATR_FULL_RXSIDE) + (ATR_REG_IDLE, E100_REG_ATR_IDLE_RXSIDE) + (ATR_REG_TX_ONLY, E100_REG_ATR_INTX_RXSIDE) + (ATR_REG_RX_ONLY, E100_REG_ATR_INRX_RXSIDE) + (ATR_REG_FULL_DUPLEX, E100_REG_ATR_FULL_RXSIDE) ) (UNIT_TX, map_list_of - (ATR_REG_IDLE, UE_REG_ATR_IDLE_TXSIDE) - (ATR_REG_TX_ONLY, UE_REG_ATR_INTX_TXSIDE) - (ATR_REG_RX_ONLY, UE_REG_ATR_INRX_TXSIDE) - (ATR_REG_FULL_DUPLEX, UE_REG_ATR_FULL_TXSIDE) + (ATR_REG_IDLE, E100_REG_ATR_IDLE_TXSIDE) + (ATR_REG_TX_ONLY, E100_REG_ATR_INTX_TXSIDE) + (ATR_REG_RX_ONLY, E100_REG_ATR_INRX_TXSIDE) + (ATR_REG_FULL_DUPLEX, E100_REG_ATR_FULL_TXSIDE) ) ; - _iface->poke16(unit_to_atr_to_addr[unit][atr], value); + _wb_iface->poke16(unit_to_atr_to_addr[unit][atr], value); } -void usrp_e100_dboard_iface::set_gpio_debug(unit_t unit, int which){ +void e100_dboard_iface::set_gpio_debug(unit_t unit, int which){ //set this unit to all outputs this->set_gpio_ddr(unit, 0xffff); @@ -213,13 +222,13 @@ void usrp_e100_dboard_iface::set_gpio_debug(unit_t unit, int which){ //set the debug on and which debug selection switch(unit){ case UNIT_RX: - _iface->poke16(UE_REG_GPIO_RX_DBG, 0xffff); - _iface->poke16(UE_REG_GPIO_RX_SEL, dbg_sels); + _wb_iface->poke16(E100_REG_GPIO_RX_DBG, 0xffff); + _wb_iface->poke16(E100_REG_GPIO_RX_SEL, dbg_sels); return; case UNIT_TX: - _iface->poke16(UE_REG_GPIO_TX_DBG, 0xffff); - _iface->poke16(UE_REG_GPIO_TX_SEL, dbg_sels); + _wb_iface->poke16(E100_REG_GPIO_TX_DBG, 0xffff); + _wb_iface->poke16(E100_REG_GPIO_TX_SEL, dbg_sels); return; } } @@ -240,60 +249,60 @@ static boost::uint32_t unit_to_otw_spi_dev(dboard_iface::unit_t unit){ UHD_THROW_INVALID_CODE_PATH(); } -void usrp_e100_dboard_iface::write_spi( +void e100_dboard_iface::write_spi( unit_t unit, const spi_config_t &config, boost::uint32_t data, size_t num_bits ){ - _iface->write_spi(unit_to_otw_spi_dev(unit), config, data, num_bits); + _spi_iface->write_spi(unit_to_otw_spi_dev(unit), config, data, num_bits); } -boost::uint32_t usrp_e100_dboard_iface::read_write_spi( +boost::uint32_t e100_dboard_iface::read_write_spi( unit_t unit, const spi_config_t &config, boost::uint32_t data, size_t num_bits ){ - return _iface->read_spi(unit_to_otw_spi_dev(unit), config, data, num_bits); + return _spi_iface->read_spi(unit_to_otw_spi_dev(unit), config, data, num_bits); } /*********************************************************************** * I2C **********************************************************************/ -void usrp_e100_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ - return _iface->write_i2c(addr, bytes); +void e100_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ + return _i2c_iface->write_i2c(addr, bytes); } -byte_vector_t usrp_e100_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ - return _iface->read_i2c(addr, num_bytes); +byte_vector_t e100_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ + return _i2c_iface->read_i2c(addr, num_bytes); } /*********************************************************************** * Aux DAX/ADC **********************************************************************/ -void usrp_e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which, double value){ +void e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which, double value){ //same aux dacs for each unit - static const uhd::dict<aux_dac_t, usrp_e100_codec_ctrl::aux_dac_t> which_to_aux_dac = map_list_of - (AUX_DAC_A, usrp_e100_codec_ctrl::AUX_DAC_A) - (AUX_DAC_B, usrp_e100_codec_ctrl::AUX_DAC_B) - (AUX_DAC_C, usrp_e100_codec_ctrl::AUX_DAC_C) - (AUX_DAC_D, usrp_e100_codec_ctrl::AUX_DAC_D) + static const uhd::dict<aux_dac_t, e100_codec_ctrl::aux_dac_t> which_to_aux_dac = map_list_of + (AUX_DAC_A, e100_codec_ctrl::AUX_DAC_A) + (AUX_DAC_B, e100_codec_ctrl::AUX_DAC_B) + (AUX_DAC_C, e100_codec_ctrl::AUX_DAC_C) + (AUX_DAC_D, e100_codec_ctrl::AUX_DAC_D) ; _codec->write_aux_dac(which_to_aux_dac[which], value); } -double usrp_e100_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, aux_adc_t which){ +double e100_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, aux_adc_t which){ static const uhd::dict< - unit_t, uhd::dict<aux_adc_t, usrp_e100_codec_ctrl::aux_adc_t> + unit_t, uhd::dict<aux_adc_t, e100_codec_ctrl::aux_adc_t> > unit_to_which_to_aux_adc = map_list_of (UNIT_RX, map_list_of - (AUX_ADC_A, usrp_e100_codec_ctrl::AUX_ADC_A1) - (AUX_ADC_B, usrp_e100_codec_ctrl::AUX_ADC_B1) + (AUX_ADC_A, e100_codec_ctrl::AUX_ADC_A1) + (AUX_ADC_B, e100_codec_ctrl::AUX_ADC_B1) ) (UNIT_TX, map_list_of - (AUX_ADC_A, usrp_e100_codec_ctrl::AUX_ADC_A2) - (AUX_ADC_B, usrp_e100_codec_ctrl::AUX_ADC_B2) + (AUX_ADC_A, e100_codec_ctrl::AUX_ADC_A2) + (AUX_ADC_B, e100_codec_ctrl::AUX_ADC_B2) ) ; return _codec->read_aux_adc(unit_to_which_to_aux_adc[unit][which]); diff --git a/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp b/host/lib/usrp/e100/e100_ctrl.cpp index 55446da63..87f7855d3 100644 --- a/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp +++ b/host/lib/usrp/e100/e100_ctrl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2011 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -15,24 +15,106 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include "usrp_e100_iface.hpp" -#include "usrp_e100_regs.hpp" +#include "e100_ctrl.hpp" +#include "e100_regs.hpp" #include <uhd/exception.hpp> +#include <uhd/utils/msg.hpp> #include <sys/ioctl.h> //ioctl #include <fcntl.h> //open, close #include <linux/usrp_e.h> //ioctl structures and constants -#include <boost/format.hpp> +#include <boost/thread/thread.hpp> //sleep #include <boost/thread/mutex.hpp> -#include <linux/i2c-dev.h> -#include <linux/i2c.h> -#include <stdexcept> +#include <boost/format.hpp> +#include <fstream> using namespace uhd; -using namespace uhd::usrp; + +/*********************************************************************** + * Sysfs GPIO wrapper class + **********************************************************************/ +class gpio{ +public: + gpio(const int num, const std::string &dir) : _num(num){ + this->set_xport("export"); + this->set_dir(dir); + _value_file.open(str(boost::format("/sys/class/gpio/gpio%d/value") % num).c_str(), std::ios_base::in | std::ios_base::out); + } + ~gpio(void){ + _value_file.close(); + this->set_dir("in"); + this->set_xport("unexport"); + } + void operator()(const int val){ + _value_file << val << std::endl << std::flush; + } + int operator()(void){ + std::string val; + std::getline(_value_file, val); + _value_file.seekg(0); + return int(val.at(0) - '0') & 0x1; + } +private: + void set_xport(const std::string &xport){ + std::ofstream export_file(("/sys/class/gpio/" + xport).c_str()); + export_file << _num << std::endl << std::flush; + export_file.close(); + } + void set_dir(const std::string &dir){ + std::ofstream dir_file(str(boost::format("/sys/class/gpio/gpio%d/direction") % _num).c_str()); + dir_file << dir << std::endl << std::flush; + dir_file.close(); + } + const int _num; + std::fstream _value_file; +}; + +/*********************************************************************** + * Aux spi implementation + **********************************************************************/ +class aux_spi_iface_impl : public spi_iface{ +public: + aux_spi_iface_impl(void): + spi_sclk_gpio(65, "out"), + spi_sen_gpio(186, "out"), + spi_mosi_gpio(145, "out"), + spi_miso_gpio(147, "in"){} + + boost::uint32_t transact_spi( + int, const spi_config_t &, //not used params + boost::uint32_t bits, + size_t num_bits, + bool readback + ){ + boost::uint32_t rb_bits = 0; + this->spi_sen_gpio(0); + + for (size_t i = 0; i < num_bits; i++){ + this->spi_sclk_gpio(0); + this->spi_mosi_gpio((bits >> (num_bits-i-1)) & 0x1); + boost::this_thread::sleep(boost::posix_time::microseconds(10)); + if (readback) rb_bits = (rb_bits << 1) | this->spi_miso_gpio(); + this->spi_sclk_gpio(1); + boost::this_thread::sleep(boost::posix_time::microseconds(10)); + } + + this->spi_sen_gpio(1); + boost::this_thread::sleep(boost::posix_time::microseconds(100)); + return rb_bits; + } + +private: + gpio spi_sclk_gpio, spi_sen_gpio, spi_mosi_gpio, spi_miso_gpio; +}; + +uhd::spi_iface::sptr e100_ctrl::make_aux_spi_iface(void){ + return uhd::spi_iface::sptr(new aux_spi_iface_impl()); +} /*********************************************************************** * I2C device node implementation wrapper **********************************************************************/ +#include <linux/i2c-dev.h> +#include <linux/i2c.h> class i2c_dev_iface : public i2c_iface{ public: i2c_dev_iface(const std::string &node){ @@ -88,10 +170,14 @@ public: private: int _node_fd; }; +uhd::i2c_iface::sptr e100_ctrl::make_dev_i2c_iface(const std::string &node){ + return uhd::i2c_iface::sptr(new i2c_dev_iface(node)); +} + /*********************************************************************** - * USRP-E100 interface implementation + * USRP-E100 control implementation **********************************************************************/ -class usrp_e100_iface_impl : public usrp_e100_iface{ +class e100_ctrl_impl : public e100_ctrl{ public: int get_file_descriptor(void){ @@ -101,9 +187,9 @@ public: /******************************************************************* * Structors ******************************************************************/ - usrp_e100_iface_impl(const std::string &node): - _i2c_dev_iface(i2c_dev_iface("/dev/i2c-3")) - { + e100_ctrl_impl(const std::string &node){ + UHD_MSG(status) << "Opening device node " << node << "..." << std::endl; + //open the device node and check file descriptor if ((_node_fd = ::open(node.c_str(), O_RDWR)) < 0){ throw uhd::io_error("Failed to open " + node); @@ -112,17 +198,17 @@ public: //check the module compatibility number int module_compat_num = ::ioctl(_node_fd, USRP_E_GET_COMPAT_NUMBER, NULL); if (module_compat_num != USRP_E_COMPAT_NUMBER){ - throw uhd::runtime_error(str(boost::format( - "Expected module compatibility number 0x%x, but got 0x%x:\n" - "The module build is not compatible with the host code build." - ) % USRP_E_COMPAT_NUMBER % module_compat_num)); - } + throw uhd::runtime_error(str(boost::format( + "Expected module compatibility number 0x%x, but got 0x%x:\n" + "The module build is not compatible with the host code build." + ) % USRP_E_COMPAT_NUMBER % module_compat_num)); + } - mb_eeprom = mboard_eeprom_t(get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100); + //perform a global reset after opening + this->poke32(E100_REG_GLOBAL_RESET, 0); } - ~usrp_e100_iface_impl(void){ - //close the device node file descriptor + ~e100_ctrl_impl(void){ ::close(_node_fd); } @@ -130,7 +216,7 @@ public: * IOCTL: provides the communication base for all other calls ******************************************************************/ void ioctl(int request, void *mem){ - boost::mutex::scoped_lock lock(_ctrl_mutex); + boost::mutex::scoped_lock lock(_ioctl_mutex); if (::ioctl(_node_fd, request, mem) < 0){ throw uhd::os_error(str( @@ -138,18 +224,10 @@ public: )); } } - - /******************************************************************* - * I2C device node interface - ******************************************************************/ - i2c_iface &get_i2c_dev_iface(void){ - return _i2c_dev_iface; - } - /******************************************************************* * Peek and Poke ******************************************************************/ - void poke32(boost::uint32_t addr, boost::uint32_t value){ + void poke32(wb_addr_type addr, boost::uint32_t value){ //load the data struct usrp_e_ctl32 data; data.offset = addr; @@ -160,7 +238,7 @@ public: this->ioctl(USRP_E_WRITE_CTL32, &data); } - void poke16(boost::uint32_t addr, boost::uint16_t value){ + void poke16(wb_addr_type addr, boost::uint16_t value){ //load the data struct usrp_e_ctl16 data; data.offset = addr; @@ -171,7 +249,7 @@ public: this->ioctl(USRP_E_WRITE_CTL16, &data); } - boost::uint32_t peek32(boost::uint32_t addr){ + boost::uint32_t peek32(wb_addr_type addr){ //load the data struct usrp_e_ctl32 data; data.offset = addr; @@ -183,7 +261,7 @@ public: return data.buf[0]; } - boost::uint16_t peek16(boost::uint32_t addr){ + boost::uint16_t peek16(wb_addr_type addr){ //load the data struct usrp_e_ctl16 data; data.offset = addr; @@ -195,92 +273,14 @@ public: return data.buf[0]; } - /******************************************************************* - * I2C - ******************************************************************/ - static const size_t max_i2c_data_bytes = 10; - - void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ - //allocate some memory for this transaction - UHD_ASSERT_THROW(bytes.size() <= max_i2c_data_bytes); - boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; - - //load the data struct - usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem); - data->addr = addr; - data->len = bytes.size(); - std::copy(bytes.begin(), bytes.end(), data->data); - - //call the spi ioctl - this->ioctl(USRP_E_I2C_WRITE, data); - } - - byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ - //allocate some memory for this transaction - UHD_ASSERT_THROW(num_bytes <= max_i2c_data_bytes); - boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; - - //load the data struct - usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem); - data->addr = addr; - data->len = num_bytes; - - //call the spi ioctl - this->ioctl(USRP_E_I2C_READ, data); - - //unload the data - byte_vector_t bytes(data->len); - UHD_ASSERT_THROW(bytes.size() == num_bytes); - std::copy(data->data, data->data+bytes.size(), bytes.begin()); - return bytes; - } - - /******************************************************************* - * SPI - ******************************************************************/ - boost::uint32_t transact_spi( - int which_slave, - const spi_config_t &config, - boost::uint32_t bits, - size_t num_bits, - bool readback - ){ - //load data struct - usrp_e_spi data; - data.readback = (readback)? UE_SPI_TXRX : UE_SPI_TXONLY; - data.slave = which_slave; - data.length = num_bits; - data.data = bits; - - //load the flags - data.flags = 0; - data.flags |= (config.miso_edge == spi_config_t::EDGE_RISE)? UE_SPI_LATCH_RISE : UE_SPI_LATCH_FALL; - data.flags |= (config.mosi_edge == spi_config_t::EDGE_RISE)? UE_SPI_PUSH_FALL : UE_SPI_PUSH_RISE; - - //call the spi ioctl - this->ioctl(USRP_E_SPI, &data); - - //unload the data - return data.data; - } - - void write_uart(boost::uint8_t, const std::string &) { - throw uhd::not_implemented_error("Unhandled command write_uart()"); - } - - std::string read_uart(boost::uint8_t) { - throw uhd::not_implemented_error("Unhandled command read_uart()"); - } - private: int _node_fd; - i2c_dev_iface _i2c_dev_iface; - boost::mutex _ctrl_mutex; + boost::mutex _ioctl_mutex; }; /*********************************************************************** * Public Make Function **********************************************************************/ -usrp_e100_iface::sptr usrp_e100_iface::make(const std::string &node){ - return sptr(new usrp_e100_iface_impl(node)); +e100_ctrl::sptr e100_ctrl::make(const std::string &node){ + return sptr(new e100_ctrl_impl(node)); } diff --git a/host/lib/usrp/e100/e100_ctrl.hpp b/host/lib/usrp/e100/e100_ctrl.hpp new file mode 100644 index 000000000..8520ea595 --- /dev/null +++ b/host/lib/usrp/e100/e100_ctrl.hpp @@ -0,0 +1,45 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_B100_CTRL_HPP +#define INCLUDED_B100_CTRL_HPP + +#include "wb_iface.hpp" +#include <uhd/types/serial.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> + +class e100_ctrl : boost::noncopyable, public wb_iface{ +public: + typedef boost::shared_ptr<e100_ctrl> sptr; + + //! Make a new controller for E100 + static sptr make(const std::string &node); + + //! Make an i2c iface for the i2c device node + static uhd::i2c_iface::sptr make_dev_i2c_iface(const std::string &node); + + //! Make an i2c iface for the i2c device node + static uhd::spi_iface::sptr make_aux_spi_iface(void); + + virtual void ioctl(int request, void *mem) = 0; + + virtual int get_file_descriptor(void) = 0; + +}; + +#endif /* INCLUDED_B100_CTRL_HPP */ diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp new file mode 100644 index 000000000..cca4ee9b3 --- /dev/null +++ b/host/lib/usrp/e100/e100_impl.cpp @@ -0,0 +1,390 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "e100_impl.hpp" +#include "e100_regs.hpp" +#include <uhd/utils/msg.hpp> +#include <uhd/exception.hpp> +#include <uhd/utils/static.hpp> +#include <uhd/utils/images.hpp> +#include <boost/bind.hpp> +#include <boost/format.hpp> +#include <boost/filesystem.hpp> +#include <boost/functional/hash.hpp> +#include <boost/assign/list_of.hpp> +#include <fstream> + +using namespace uhd; +using namespace uhd::usrp; +namespace fs = boost::filesystem; + +//////////////////////////////////////////////////////////////////////// +// I2C addresses +//////////////////////////////////////////////////////////////////////// +#define I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx +#define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0) +#define I2C_ADDR_TX_DB (I2C_DEV_EEPROM | 0x4) +#define I2C_ADDR_RX_DB (I2C_DEV_EEPROM | 0x5) + +/*********************************************************************** + * Discovery + **********************************************************************/ +static device_addrs_t e100_find(const device_addr_t &hint){ + device_addrs_t e100_addrs; + + //return an empty list of addresses when type is set to non-usrp-e + if (hint.has_key("type") and hint["type"] != "e100") return e100_addrs; + + //device node not provided, assume its 0 + if (not hint.has_key("node")){ + device_addr_t new_addr = hint; + new_addr["node"] = "/dev/usrp_e0"; + return e100_find(new_addr); + } + + //use the given device node name + if (fs::exists(hint["node"])){ + device_addr_t new_addr; + new_addr["type"] = "e100"; + new_addr["node"] = fs::system_complete(fs::path(hint["node"])).string(); + try{ + i2c_iface::sptr i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE); + const mboard_eeprom_t mb_eeprom(*i2c_iface, mboard_eeprom_t::MAP_E100); + new_addr["name"] = mb_eeprom["name"]; + new_addr["serial"] = mb_eeprom["serial"]; + } + catch(const std::exception &e){ + new_addr["name"] = ""; + new_addr["serial"] = ""; + } + if ( + (not hint.has_key("name") or hint["name"] == new_addr["name"]) and + (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]) + ){ + e100_addrs.push_back(new_addr); + } + } + + return e100_addrs; +} + +/*********************************************************************** + * Make + **********************************************************************/ +static size_t hash_fpga_file(const std::string &file_path){ + size_t hash = 0; + std::ifstream file(file_path.c_str()); + if (not file.good()) throw uhd::io_error("cannot open fpga file for read: " + file_path); + while (file.good()) boost::hash_combine(hash, file.get()); + file.close(); + return hash; +} + +static device::sptr e100_make(const device_addr_t &device_addr){ + return device::sptr(new e100_impl(device_addr)); +} + +UHD_STATIC_BLOCK(register_e100_device){ + device::register_device(&e100_find, &e100_make); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ + + //setup the main interface into fpga + const std::string node = device_addr["node"]; + _fpga_ctrl = e100_ctrl::make(node); + + //extract the fpga path and compute hash + const std::string e100_fpga_image = find_image_path(device_addr.get("fpga", E100_FPGA_FILE_NAME)); + const boost::uint32_t file_hash = boost::uint32_t(hash_fpga_file(e100_fpga_image)); + + //When the hash does not match: + // - close the device node + // - load the fpga bin file + // - re-open the device node + if (_fpga_ctrl->peek32(E100_REG_RB_MISC_TEST32) != file_hash){ + _fpga_ctrl.reset(); + e100_load_fpga(e100_fpga_image); + _fpga_ctrl = e100_ctrl::make(node); + } + + //setup clock control here to ensure that the FPGA has a good clock before we continue + const double master_clock_rate = device_addr.cast<double>("master_clock_rate", E100_DEFAULT_CLOCK_RATE); + _aux_spi_iface = e100_ctrl::make_aux_spi_iface(); + _clock_ctrl = e100_clock_ctrl::make(_aux_spi_iface, master_clock_rate); + + //Perform wishbone readback tests, these tests also write the hash + bool test_fail = false; + UHD_MSG(status) << "Performing wishbone readback test... " << std::flush; + for (size_t i = 0; i < 100; i++){ + _fpga_ctrl->poke32(E100_REG_SR_MISC_TEST32, file_hash); + test_fail = _fpga_ctrl->peek32(E100_REG_RB_MISC_TEST32) != file_hash; + if (test_fail) break; //exit loop on any failure + } + UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl; + + if (test_fail) UHD_MSG(error) << boost::format( + "The FPGA is either clocked improperly\n" + "or the FPGA build is not compatible.\n" + "Subsequent errors may follow...\n" + ); + + //check that the compatibility is correct + const boost::uint16_t fpga_compat_num = _fpga_ctrl->peek16(E100_REG_MISC_COMPAT); + if (fpga_compat_num != E100_FPGA_COMPAT_NUM){ + throw uhd::runtime_error(str(boost::format( + "\nPlease update the FPGA image for your device.\n" + "See the application notes for USRP E-Series for instructions.\n" + "Expected FPGA compatibility number 0x%x, but got 0x%x:\n" + "The FPGA build is not compatible with the host code build." + ) % E100_FPGA_COMPAT_NUM % fpga_compat_num)); + } + + //////////////////////////////////////////////////////////////////// + // Create controller objects + //////////////////////////////////////////////////////////////////// + _fpga_i2c_ctrl = i2c_core_100::make(_fpga_ctrl, E100_REG_SLAVE(3)); + _fpga_spi_ctrl = spi_core_100::make(_fpga_ctrl, E100_REG_SLAVE(2)); + _dev_i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE); + _data_transport = e100_make_mmap_zero_copy(_fpga_ctrl); + + //////////////////////////////////////////////////////////////////// + // Initialize the properties tree + //////////////////////////////////////////////////////////////////// + _tree = property_tree::make(); + _tree->create<std::string>("/name").set("E-Series Device"); + const property_tree::path_type mb_path = "/mboards/0"; + _tree->create<std::string>(mb_path / "name").set("E100 (euewanee)"); + + //////////////////////////////////////////////////////////////////// + // setup the mboard eeprom + //////////////////////////////////////////////////////////////////// + const mboard_eeprom_t mb_eeprom(*_dev_i2c_iface, mboard_eeprom_t::MAP_E100); + _tree->create<mboard_eeprom_t>(mb_path / "eeprom") + .set(mb_eeprom) + .subscribe(boost::bind(&e100_impl::set_mb_eeprom, this, _1)); + + //////////////////////////////////////////////////////////////////// + // create clock control objects + //////////////////////////////////////////////////////////////////// + //^^^ clock created up top, just reg props here... ^^^ + _tree->create<double>(mb_path / "tick_rate") + .publish(boost::bind(&e100_clock_ctrl::get_fpga_clock_rate, _clock_ctrl)) + .subscribe(boost::bind(&e100_impl::update_tick_rate, this, _1)); + + //////////////////////////////////////////////////////////////////// + // create codec control objects + //////////////////////////////////////////////////////////////////// + _codec_ctrl = e100_codec_ctrl::make(_fpga_spi_ctrl); + const property_tree::path_type rx_codec_path = mb_path / "rx_codecs/A"; + const property_tree::path_type tx_codec_path = mb_path / "tx_codecs/A"; + _tree->create<std::string>(rx_codec_path / "name").set("ad9522"); + _tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(e100_codec_ctrl::rx_pga_gain_range); + _tree->create<double>(rx_codec_path / "gains/pga/value") + .coerce(boost::bind(&e100_impl::update_rx_codec_gain, this, _1)); + _tree->create<std::string>(tx_codec_path / "name").set("ad9522"); + _tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(e100_codec_ctrl::tx_pga_gain_range); + _tree->create<double>(tx_codec_path / "gains/pga/value") + .subscribe(boost::bind(&e100_codec_ctrl::set_tx_pga_gain, _codec_ctrl, _1)) + .publish(boost::bind(&e100_codec_ctrl::get_tx_pga_gain, _codec_ctrl)); + + //////////////////////////////////////////////////////////////////// + // and do the misc mboard sensors + //////////////////////////////////////////////////////////////////// + //none for now... + _tree->create<int>(mb_path / "sensors"); //phony property so this dir exists + + //////////////////////////////////////////////////////////////////// + // create frontend control objects + //////////////////////////////////////////////////////////////////// + _rx_fe = rx_frontend_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_FRONT)); + _tx_fe = tx_frontend_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TX_FRONT)); + //TODO lots of properties to expose here for frontends + _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec") + .subscribe(boost::bind(&e100_impl::update_rx_subdev_spec, this, _1)); + _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec") + .subscribe(boost::bind(&e100_impl::update_tx_subdev_spec, this, _1)); + + //////////////////////////////////////////////////////////////////// + // create rx dsp control objects + //////////////////////////////////////////////////////////////////// + _rx_dsps.push_back(rx_dsp_core_200::make( + _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_DSP0), E100_REG_SR_ADDR(UE_SR_RX_CTRL0), E100_RX_SID_BASE + 0 + )); + _rx_dsps.push_back(rx_dsp_core_200::make( + _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_DSP1), E100_REG_SR_ADDR(UE_SR_RX_CTRL1), E100_RX_SID_BASE + 1 + )); + for (size_t dspno = 0; dspno < _rx_dsps.size(); dspno++){ + _rx_dsps[dspno]->set_link_rate(E100_LINK_RATE_BPS); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _rx_dsps[dspno], _1)); + property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno); + _tree->create<double>(rx_dsp_path / "rate/value") + .coerce(boost::bind(&rx_dsp_core_200::set_host_rate, _rx_dsps[dspno], _1)) + .subscribe(boost::bind(&e100_impl::update_rx_samp_rate, this, _1)); + _tree->create<double>(rx_dsp_path / "freq/value") + .coerce(boost::bind(&rx_dsp_core_200::set_freq, _rx_dsps[dspno], _1)); + _tree->create<meta_range_t>(rx_dsp_path / "freq/range") + .publish(boost::bind(&rx_dsp_core_200::get_freq_range, _rx_dsps[dspno])); + _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd") + .subscribe(boost::bind(&rx_dsp_core_200::issue_stream_command, _rx_dsps[dspno], _1)); + } + + //////////////////////////////////////////////////////////////////// + // create tx dsp control objects + //////////////////////////////////////////////////////////////////// + _tx_dsp = tx_dsp_core_200::make( + _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TX_DSP), E100_REG_SR_ADDR(UE_SR_TX_CTRL), E100_TX_ASYNC_SID + ); + _tx_dsp->set_link_rate(E100_LINK_RATE_BPS); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _tx_dsp, _1)); + _tree->create<double>(mb_path / "tx_dsps/0/rate/value") + .coerce(boost::bind(&tx_dsp_core_200::set_host_rate, _tx_dsp, _1)) + .subscribe(boost::bind(&e100_impl::update_tx_samp_rate, this, _1)); + _tree->create<double>(mb_path / "tx_dsps/0/freq/value") + .coerce(boost::bind(&tx_dsp_core_200::set_freq, _tx_dsp, _1)); + _tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range") + .publish(boost::bind(&tx_dsp_core_200::get_freq_range, _tx_dsp)); + + //////////////////////////////////////////////////////////////////// + // create time control objects + //////////////////////////////////////////////////////////////////// + time64_core_200::readback_bases_type time64_rb_bases; + time64_rb_bases.rb_secs_now = E100_REG_RB_TIME_NOW_SECS; + time64_rb_bases.rb_ticks_now = E100_REG_RB_TIME_NOW_TICKS; + time64_rb_bases.rb_secs_pps = E100_REG_RB_TIME_PPS_SECS; + time64_rb_bases.rb_ticks_pps = E100_REG_RB_TIME_PPS_TICKS; + _time64 = time64_core_200::make( + _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TIME64), time64_rb_bases + ); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&time64_core_200::set_tick_rate, _time64, _1)); + _tree->create<time_spec_t>(mb_path / "time/now") + .publish(boost::bind(&time64_core_200::get_time_now, _time64)) + .subscribe(boost::bind(&time64_core_200::set_time_now, _time64, _1)); + _tree->create<time_spec_t>(mb_path / "time/pps") + .publish(boost::bind(&time64_core_200::get_time_last_pps, _time64)) + .subscribe(boost::bind(&time64_core_200::set_time_next_pps, _time64, _1)); + //setup time source props + _tree->create<std::string>(mb_path / "time_source/value") + .subscribe(boost::bind(&time64_core_200::set_time_source, _time64, _1)); + _tree->create<std::vector<std::string> >(mb_path / "time_source/options") + .publish(boost::bind(&time64_core_200::get_time_sources, _time64)); + //setup reference source props + _tree->create<std::string>(mb_path / "clock_source/value") + .subscribe(boost::bind(&e100_impl::update_clock_source, this, _1)); + static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("auto"); + _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources); + + //////////////////////////////////////////////////////////////////// + // create dboard control objects + //////////////////////////////////////////////////////////////////// + + //read the dboard eeprom to extract the dboard ids + dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom; + rx_db_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_RX_DB); + tx_db_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_DB); + gdb_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_DB ^ 5); + + //create the properties and register subscribers + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/rx_eeprom") + .set(rx_db_eeprom) + .subscribe(boost::bind(&e100_impl::set_db_eeprom, this, "rx", _1)); + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/tx_eeprom") + .set(tx_db_eeprom) + .subscribe(boost::bind(&e100_impl::set_db_eeprom, this, "tx", _1)); + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/gdb_eeprom") + .set(gdb_eeprom) + .subscribe(boost::bind(&e100_impl::set_db_eeprom, this, "gdb", _1)); + + //create a new dboard interface and manager + _dboard_iface = make_e100_dboard_iface(_fpga_ctrl, _fpga_i2c_ctrl, _fpga_spi_ctrl, _clock_ctrl, _codec_ctrl); + _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_dboard_iface); + _dboard_manager = dboard_manager::make( + rx_db_eeprom.id, + ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id, + _dboard_iface + ); + BOOST_FOREACH(const std::string &name, _dboard_manager->get_rx_subdev_names()){ + dboard_manager::populate_prop_tree_from_subdev( + _tree->subtree(mb_path / "dboards/A/rx_frontends" / name), + _dboard_manager->get_rx_subdev(name) + ); + } + BOOST_FOREACH(const std::string &name, _dboard_manager->get_tx_subdev_names()){ + dboard_manager::populate_prop_tree_from_subdev( + _tree->subtree(mb_path / "dboards/A/tx_frontends" / name), + _dboard_manager->get_tx_subdev(name) + ); + } + + //initialize io handling + this->io_init(); + + //////////////////////////////////////////////////////////////////// + // do some post-init tasks + //////////////////////////////////////////////////////////////////// + _tree->access<double>(mb_path / "tick_rate").update() //update and then subscribe the clock callback + .subscribe(boost::bind(&e100_clock_ctrl::set_fpga_clock_rate, _clock_ctrl, _1)); + + //and now that the tick rate is set, init the host rates to something + BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "rx_dsps")){ + _tree->access<double>(mb_path / "rx_dsps" / name / "rate" / "value").set(1e6); + } + BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "tx_dsps")){ + _tree->access<double>(mb_path / "tx_dsps" / name / "rate" / "value").set(1e6); + } + + _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_rx_subdev_names()[0])); + _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_tx_subdev_names()[0])); + _tree->access<std::string>(mb_path / "clock_source/value").set("internal"); + _tree->access<std::string>(mb_path / "time_source/value").set("none"); + +} + +e100_impl::~e100_impl(void){ + /* NOP */ +} + +double e100_impl::update_rx_codec_gain(const double gain){ + //set gain on both I and Q, readback on one + //TODO in the future, gains should have individual control + _codec_ctrl->set_rx_pga_gain(gain, 'A'); + _codec_ctrl->set_rx_pga_gain(gain, 'B'); + return _codec_ctrl->get_rx_pga_gain('A'); +} + +void e100_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){ + mb_eeprom.commit(*_dev_i2c_iface, mboard_eeprom_t::MAP_E100); +} + +void e100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){ + if (type == "rx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_RX_DB); + if (type == "tx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_DB); + if (type == "gdb") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_DB ^ 5); +} + +void e100_impl::update_clock_source(const std::string &source){ + if (source == "auto") _clock_ctrl->use_auto_ref(); + else if (source == "internal") _clock_ctrl->use_internal_ref(); + else if (source == "external") _clock_ctrl->use_external_ref(); + else throw uhd::runtime_error("unhandled clock configuration reference source: " + source); +} diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp new file mode 100644 index 000000000..e24360223 --- /dev/null +++ b/host/lib/usrp/e100/e100_impl.hpp @@ -0,0 +1,129 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "e100_ctrl.hpp" +#include "clock_ctrl.hpp" +#include "codec_ctrl.hpp" +#include "spi_core_100.hpp" +#include "i2c_core_100.hpp" +#include "rx_frontend_core_200.hpp" +#include "tx_frontend_core_200.hpp" +#include "rx_dsp_core_200.hpp" +#include "tx_dsp_core_200.hpp" +#include "time64_core_200.hpp" +#include <uhd/device.hpp> +#include <uhd/property_tree.hpp> +#include <uhd/utils/pimpl.hpp> +#include <uhd/usrp/subdev_spec.hpp> +#include <uhd/usrp/dboard_eeprom.hpp> +#include <uhd/usrp/mboard_eeprom.hpp> +#include <uhd/types/otw_type.hpp> +#include <uhd/types/clock_config.hpp> +#include <uhd/types/stream_cmd.hpp> +#include <uhd/usrp/dboard_manager.hpp> +#include <uhd/transport/zero_copy.hpp> + +#ifndef INCLUDED_E100_IMPL_HPP +#define INCLUDED_E100_IMPL_HPP + +uhd::transport::zero_copy_if::sptr e100_make_mmap_zero_copy(e100_ctrl::sptr iface); + +static const double E100_LINK_RATE_BPS = 256e6/8; +static const std::string E100_I2C_DEV_NODE = "/dev/i2c-3"; +static const std::string E100_FPGA_FILE_NAME = "usrp_e100_fpga_v2.bin"; +static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x05; +static const boost::uint32_t E100_RX_SID_BASE = 2; +static const boost::uint32_t E100_TX_ASYNC_SID = 1; +static const double E100_DEFAULT_CLOCK_RATE = 64e6; + +//! load an fpga image from a bin file into the usrp-e fpga +extern void e100_load_fpga(const std::string &bin_file); + +//! Make an e100 dboard interface +uhd::usrp::dboard_iface::sptr make_e100_dboard_iface( + wb_iface::sptr wb_iface, + uhd::i2c_iface::sptr i2c_iface, + uhd::spi_iface::sptr spi_iface, + e100_clock_ctrl::sptr clock, + e100_codec_ctrl::sptr codec +); + +/*! + * USRP-E100 implementation guts: + * The implementation details are encapsulated here. + * Handles properties on the mboard, dboard, dsps... + */ +class e100_impl : public uhd::device{ +public: + //structors + e100_impl(const uhd::device_addr_t &); + ~e100_impl(void); + + //the io interface + size_t send(const send_buffs_type &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double); + size_t recv(const recv_buffs_type &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double); + bool recv_async_msg(uhd::async_metadata_t &, double); + size_t get_max_send_samps_per_packet(void) const; + size_t get_max_recv_samps_per_packet(void) const; + +private: + uhd::property_tree::sptr _tree; + + //controllers + spi_core_100::sptr _fpga_spi_ctrl; + i2c_core_100::sptr _fpga_i2c_ctrl; + rx_frontend_core_200::sptr _rx_fe; + tx_frontend_core_200::sptr _tx_fe; + std::vector<rx_dsp_core_200::sptr> _rx_dsps; + tx_dsp_core_200::sptr _tx_dsp; + time64_core_200::sptr _time64; + e100_clock_ctrl::sptr _clock_ctrl; + e100_codec_ctrl::sptr _codec_ctrl; + e100_ctrl::sptr _fpga_ctrl; + uhd::i2c_iface::sptr _dev_i2c_iface; + uhd::spi_iface::sptr _aux_spi_iface; + + //transports + uhd::transport::zero_copy_if::sptr _data_transport; + + //dboard stuff + uhd::usrp::dboard_manager::sptr _dboard_manager; + uhd::usrp::dboard_iface::sptr _dboard_iface; + + //handle io stuff + uhd::otw_type_t _rx_otw_type, _tx_otw_type; + UHD_PIMPL_DECL(io_impl) _io_impl; + void io_init(void); + + //device properties interface + void get(const wax::obj &, wax::obj &val){ + val = _tree; //entry point into property tree + } + + double update_rx_codec_gain(const double); //sets A and B at once + void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &); + void set_db_eeprom(const std::string &, const uhd::usrp::dboard_eeprom_t &); + void update_tick_rate(const double rate); + void update_rx_samp_rate(const double rate); + void update_tx_samp_rate(const double rate); + void update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &); + void update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &); + void update_clock_source(const std::string &); + +}; + +#endif /* INCLUDED_E100_IMPL_HPP */ diff --git a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp b/host/lib/usrp/e100/e100_mmap_zero_copy.cpp index bb421507a..cdb7094f4 100644 --- a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp +++ b/host/lib/usrp/e100/e100_mmap_zero_copy.cpp @@ -15,7 +15,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // -#include "usrp_e100_iface.hpp" +#include "e100_ctrl.hpp" #include <uhd/transport/zero_copy.hpp> #include <uhd/utils/log.hpp> #include <uhd/exception.hpp> @@ -35,9 +35,9 @@ static const size_t poll_breakout = 10; //how many poll timeouts constitute a fu * Reusable managed receiver buffer: * - The buffer knows how to claim and release a frame. **********************************************************************/ -class usrp_e100_mmap_zero_copy_mrb : public managed_recv_buffer{ +class e100_mmap_zero_copy_mrb : public managed_recv_buffer{ public: - usrp_e100_mmap_zero_copy_mrb(void *mem, ring_buffer_info *info): + e100_mmap_zero_copy_mrb(void *mem, ring_buffer_info *info): _mem(mem), _info(info) { /* NOP */ } void release(void){ @@ -66,9 +66,9 @@ private: * Reusable managed send buffer: * - The buffer knows how to claim and release a frame. **********************************************************************/ -class usrp_e100_mmap_zero_copy_msb : public managed_send_buffer{ +class e100_mmap_zero_copy_msb : public managed_send_buffer{ public: - usrp_e100_mmap_zero_copy_msb(void *mem, ring_buffer_info *info, size_t len, int fd): + e100_mmap_zero_copy_msb(void *mem, ring_buffer_info *info, size_t len, int fd): _mem(mem), _info(info), _len(len), _fd(fd) { /* NOP */ } void commit(size_t len){ @@ -102,9 +102,9 @@ private: /*********************************************************************** * The zero copy interface implementation **********************************************************************/ -class usrp_e100_mmap_zero_copy_impl : public zero_copy_if{ +class e100_mmap_zero_copy_impl : public zero_copy_if{ public: - usrp_e100_mmap_zero_copy_impl(usrp_e100_iface::sptr iface): + e100_mmap_zero_copy_impl(e100_ctrl::sptr iface): _fd(iface->get_file_descriptor()), _recv_index(0), _send_index(0) { //get system sizes @@ -162,28 +162,28 @@ public: //initialize the managed receive buffers for (size_t i = 0; i < get_num_recv_frames(); i++){ - _mrb_pool.push_back(usrp_e100_mmap_zero_copy_mrb( + _mrb_pool.push_back(e100_mmap_zero_copy_mrb( recv_buff + get_recv_frame_size()*i, (*recv_info) + i )); } //initialize the managed send buffers for (size_t i = 0; i < get_num_recv_frames(); i++){ - _msb_pool.push_back(usrp_e100_mmap_zero_copy_msb( + _msb_pool.push_back(e100_mmap_zero_copy_msb( send_buff + get_send_frame_size()*i, (*send_info) + i, get_send_frame_size(), _fd )); } } - ~usrp_e100_mmap_zero_copy_impl(void){ + ~e100_mmap_zero_copy_impl(void){ UHD_LOG << "cleanup: munmap" << std::endl; ::munmap(_mapped_mem, _map_size); } managed_recv_buffer::sptr get_recv_buff(double timeout){ if (fp_verbose) UHD_LOGV(always) << "get_recv_buff: " << _recv_index << std::endl; - usrp_e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index]; + e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index]; //poll/wait for a ready frame if (not mrb.ready()){ @@ -215,7 +215,7 @@ public: managed_send_buffer::sptr get_send_buff(double timeout){ if (fp_verbose) UHD_LOGV(always) << "get_send_buff: " << _send_index << std::endl; - usrp_e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index]; + e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index]; //poll/wait for a ready frame if (not msb.ready()){ @@ -254,8 +254,8 @@ private: size_t _frame_size, _map_size; //re-usable managed buffers - std::vector<usrp_e100_mmap_zero_copy_mrb> _mrb_pool; - std::vector<usrp_e100_mmap_zero_copy_msb> _msb_pool; + std::vector<e100_mmap_zero_copy_mrb> _mrb_pool; + std::vector<e100_mmap_zero_copy_msb> _msb_pool; //indexes into sub-sections of mapped memory size_t _recv_index, _send_index; @@ -264,6 +264,6 @@ private: /*********************************************************************** * The zero copy interface make function **********************************************************************/ -zero_copy_if::sptr usrp_e100_make_mmap_zero_copy(usrp_e100_iface::sptr iface){ - return zero_copy_if::sptr(new usrp_e100_mmap_zero_copy_impl(iface)); +zero_copy_if::sptr e100_make_mmap_zero_copy(e100_ctrl::sptr iface){ + return zero_copy_if::sptr(new e100_mmap_zero_copy_impl(iface)); } diff --git a/host/lib/usrp/e100/e100_regs.hpp b/host/lib/usrp/e100/e100_regs.hpp new file mode 100644 index 000000000..28ef707dc --- /dev/null +++ b/host/lib/usrp/e100/e100_regs.hpp @@ -0,0 +1,157 @@ + + +//////////////////////////////////////////////////////////////// +// +// Memory map for embedded wishbone bus +// +//////////////////////////////////////////////////////////////// + +// All addresses are byte addresses. All accesses are word (16-bit) accesses. +// This means that address bit 0 is usually 0. +// There are 11 bits of address for the control. + +#ifndef INCLUDED_E100_REGS_HPP +#define INCLUDED_E100_REGS_HPP + +///////////////////////////////////////////////////// +// Slave pointers + +#define E100_REG_SLAVE(n) ((n)<<7) + +///////////////////////////////////////////////////// +// Slave 0 -- Misc Regs + +#define E100_REG_MISC_BASE E100_REG_SLAVE(0) + +#define E100_REG_MISC_LED E100_REG_MISC_BASE + 0 +#define E100_REG_MISC_SW E100_REG_MISC_BASE + 2 +#define E100_REG_MISC_CGEN_CTRL E100_REG_MISC_BASE + 4 +#define E100_REG_MISC_CGEN_ST E100_REG_MISC_BASE + 6 +#define E100_REG_MISC_TEST E100_REG_MISC_BASE + 8 +#define E100_REG_MISC_RX_LEN E100_REG_MISC_BASE + 10 +#define E100_REG_MISC_TX_LEN E100_REG_MISC_BASE + 12 +#define E100_REG_MISC_XFER_RATE E100_REG_MISC_BASE + 14 +#define E100_REG_MISC_COMPAT E100_REG_MISC_BASE + 16 + +///////////////////////////////////////////////////// +// Slave 1 -- UART +// CLKDIV is 16 bits, others are only 8 + +#define E100_REG_UART_BASE E100_REG_SLAVE(1) + +#define E100_REG_UART_CLKDIV E100_REG_UART_BASE + 0 +#define E100_REG_UART_TXLEVEL E100_REG_UART_BASE + 2 +#define E100_REG_UART_RXLEVEL E100_REG_UART_BASE + 4 +#define E100_REG_UART_TXCHAR E100_REG_UART_BASE + 6 +#define E100_REG_UART_RXCHAR E100_REG_UART_BASE + 8 + +///////////////////////////////////////////////////// +// Slave 2 -- SPI Core +//these are 32-bit registers mapped onto the 16-bit Wishbone bus. +//Using peek32/poke32 should allow transparent use of these registers. +#define E100_REG_SPI_BASE E100_REG_SLAVE(2) + +//spi slave constants +#define UE_SPI_SS_AD9522 (1 << 3) +#define UE_SPI_SS_AD9862 (1 << 2) +#define UE_SPI_SS_TX_DB (1 << 1) +#define UE_SPI_SS_RX_DB (1 << 0) + +//////////////////////////////////////////////// +// Slave 3 -- I2C Core + +#define E100_REG_I2C_BASE E100_REG_SLAVE(3) + +//////////////////////////////////////////////// +// Slave 5 -- Error messages buffer + +#define E100_REG_ERR_BUFF E100_REG_SLAVE(5) + +//////////////////////////////////////////////// +// Slave 4 -- GPIO + +#define E100_REG_GPIO_BASE E100_REG_SLAVE(4) + +#define E100_REG_GPIO_RX_IO E100_REG_GPIO_BASE + 0 +#define E100_REG_GPIO_TX_IO E100_REG_GPIO_BASE + 2 +#define E100_REG_GPIO_RX_DDR E100_REG_GPIO_BASE + 4 +#define E100_REG_GPIO_TX_DDR E100_REG_GPIO_BASE + 6 +#define E100_REG_GPIO_RX_SEL E100_REG_GPIO_BASE + 8 +#define E100_REG_GPIO_TX_SEL E100_REG_GPIO_BASE + 10 +#define E100_REG_GPIO_RX_DBG E100_REG_GPIO_BASE + 12 +#define E100_REG_GPIO_TX_DBG E100_REG_GPIO_BASE + 14 + +//possible bit values for sel when dbg is 0: +#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg +#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic + +//possible bit values for sel when dbg is 1: +#define GPIO_SEL_DEBUG_0 0 // if pin is an output, debug lines from FPGA fabric +#define GPIO_SEL_DEBUG_1 1 // if pin is an output, debug lines from FPGA fabric + +/////////////////////////////////////////////////// +// Slave 6 -- ATR Controller +// 16 regs + +#define E100_REG_ATR_BASE E100_REG_SLAVE(6) + +#define E100_REG_ATR_IDLE_RXSIDE E100_REG_ATR_BASE + 0 +#define E100_REG_ATR_IDLE_TXSIDE E100_REG_ATR_BASE + 2 +#define E100_REG_ATR_INTX_RXSIDE E100_REG_ATR_BASE + 4 +#define E100_REG_ATR_INTX_TXSIDE E100_REG_ATR_BASE + 6 +#define E100_REG_ATR_INRX_RXSIDE E100_REG_ATR_BASE + 8 +#define E100_REG_ATR_INRX_TXSIDE E100_REG_ATR_BASE + 10 +#define E100_REG_ATR_FULL_RXSIDE E100_REG_ATR_BASE + 12 +#define E100_REG_ATR_FULL_TXSIDE E100_REG_ATR_BASE + 14 + +/////////////////////////////////////////////////// +// Slave 7 -- Readback Mux 32 + +#define E100_REG_RB_MUX_32_BASE E100_REG_SLAVE(7) + +#define E100_REG_RB_TIME_NOW_SECS E100_REG_RB_MUX_32_BASE + 0 +#define E100_REG_RB_TIME_NOW_TICKS E100_REG_RB_MUX_32_BASE + 4 +#define E100_REG_RB_TIME_PPS_SECS E100_REG_RB_MUX_32_BASE + 8 +#define E100_REG_RB_TIME_PPS_TICKS E100_REG_RB_MUX_32_BASE + 12 +#define E100_REG_RB_MISC_TEST32 E100_REG_RB_MUX_32_BASE + 16 +#define E100_REG_RB_ERR_STATUS E100_REG_RB_MUX_32_BASE + 20 + +//////////////////////////////////////////////////// +// Slave 8 -- Settings Bus +// +// Output-only, no readback, 64 registers total +// Each register must be written 64 bits at a time +// First the address xxx_xx00 and then xxx_xx10 + +// 64 total regs in address space +#define UE_SR_RX_CTRL0 0 // 9 regs (+0 to +8) +#define UE_SR_RX_DSP0 10 // 4 regs (+0 to +3) +#define UE_SR_RX_CTRL1 16 // 9 regs (+0 to +8) +#define UE_SR_RX_DSP1 26 // 4 regs (+0 to +3) +#define UE_SR_ERR_CTRL 30 // 1 reg +#define UE_SR_TX_CTRL 32 // 4 regs (+0 to +3) +#define UE_SR_TX_DSP 38 // 3 regs (+0 to +2) + +#define UE_SR_TIME64 42 // 6 regs (+0 to +5) +#define UE_SR_RX_FRONT 48 // 5 regs (+0 to +4) +#define UE_SR_TX_FRONT 54 // 5 regs (+0 to +4) + +#define UE_SR_REG_TEST32 60 // 1 reg +#define UE_SR_CLEAR_RX_FIFO 61 // 1 reg +#define UE_SR_CLEAR_TX_FIFO 62 // 1 reg +#define UE_SR_GLOBAL_RESET 63 // 1 reg + +#define E100_REG_SR_ADDR(n) (E100_REG_SLAVE(8) + (4*(n))) + +#define E100_REG_SR_MISC_TEST32 E100_REG_SR_ADDR(UE_SR_REG_TEST32) +#define E100_REG_SR_ERR_CTRL E100_REG_SR_ADDR(UE_SR_ERR_CTRL) + +///////////////////////////////////////////////// +// Magic reset regs +//////////////////////////////////////////////// +#define E100_REG_CLEAR_RX E100_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO) +#define E100_REG_CLEAR_TX E100_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO) +#define E100_REG_GLOBAL_RESET E100_REG_SR_ADDR(UE_SR_GLOBAL_RESET) + +#endif + diff --git a/host/lib/usrp/usrp_e100/fpga_downloader.cpp b/host/lib/usrp/e100/fpga_downloader.cpp index a7449d3b1..7074c8299 100644 --- a/host/lib/usrp/usrp_e100/fpga_downloader.cpp +++ b/host/lib/usrp/e100/fpga_downloader.cpp @@ -245,7 +245,7 @@ static void send_file_to_fpga(const std::string &file_name, gpio &error, gpio &d }//namespace usrp_e_fpga_downloader_utility -void usrp_e100_load_fpga(const std::string &bin_file){ +void e100_load_fpga(const std::string &bin_file){ using namespace usrp_e_fpga_downloader_utility; gpio gpio_prog_b(PROG_B, OUT); @@ -254,9 +254,9 @@ void usrp_e100_load_fpga(const std::string &bin_file){ UHD_MSG(status) << "Loading FPGA image: " << bin_file << "... " << std::flush; - if(std::system("/sbin/rmmod usrp_e") != 0){ - UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not unload usrp_e module" << std::endl; - } +// if(std::system("/sbin/rmmod usrp_e") != 0){ +// UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not unload usrp_e module" << std::endl; +// } prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b); @@ -264,9 +264,9 @@ void usrp_e100_load_fpga(const std::string &bin_file){ send_file_to_fpga(bin_file, gpio_init_b, gpio_done); - if(std::system("/sbin/modprobe usrp_e") != 0){ - UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not load usrp_e module" << std::endl; - } +// if(std::system("/sbin/modprobe usrp_e") != 0){ +// UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not load usrp_e module" << std::endl; +// } } diff --git a/host/lib/usrp/usrp_e100/include/linux/usrp_e.h b/host/lib/usrp/e100/include/linux/usrp_e.h index 4c6a5dd89..2c4aa2ac1 100644 --- a/host/lib/usrp/usrp_e100/include/linux/usrp_e.h +++ b/host/lib/usrp/e100/include/linux/usrp_e.h @@ -28,46 +28,15 @@ struct usrp_e_ctl32 { __u32 buf[10]; }; -/* SPI interface */ - -#define UE_SPI_TXONLY 0 -#define UE_SPI_TXRX 1 - -/* Defines for spi ctrl register */ -#define UE_SPI_CTRL_TXNEG (1<<10) -#define UE_SPI_CTRL_RXNEG (1<<9) - -#define UE_SPI_PUSH_RISE 0 -#define UE_SPI_PUSH_FALL UE_SPI_CTRL_TXNEG -#define UE_SPI_LATCH_RISE 0 -#define UE_SPI_LATCH_FALL UE_SPI_CTRL_RXNEG - -struct usrp_e_spi { - __u8 readback; - __u32 slave; - __u32 data; - __u32 length; - __u32 flags; -}; - -struct usrp_e_i2c { - __u8 addr; - __u32 len; - __u8 data[]; -}; - #define USRP_E_IOC_MAGIC 'u' #define USRP_E_WRITE_CTL16 _IOW(USRP_E_IOC_MAGIC, 0x20, struct usrp_e_ctl16) #define USRP_E_READ_CTL16 _IOWR(USRP_E_IOC_MAGIC, 0x21, struct usrp_e_ctl16) #define USRP_E_WRITE_CTL32 _IOW(USRP_E_IOC_MAGIC, 0x22, struct usrp_e_ctl32) #define USRP_E_READ_CTL32 _IOWR(USRP_E_IOC_MAGIC, 0x23, struct usrp_e_ctl32) -#define USRP_E_SPI _IOWR(USRP_E_IOC_MAGIC, 0x24, struct usrp_e_spi) -#define USRP_E_I2C_READ _IOWR(USRP_E_IOC_MAGIC, 0x25, struct usrp_e_i2c) -#define USRP_E_I2C_WRITE _IOW(USRP_E_IOC_MAGIC, 0x26, struct usrp_e_i2c) #define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t) #define USRP_E_GET_COMPAT_NUMBER _IO(USRP_E_IOC_MAGIC, 0x28) -#define USRP_E_COMPAT_NUMBER 1 +#define USRP_E_COMPAT_NUMBER 2 /* Flag defines */ #define RB_USER (1<<0) diff --git a/host/lib/usrp/e100/io_impl.cpp b/host/lib/usrp/e100/io_impl.cpp new file mode 100644 index 000000000..a10b3ffb3 --- /dev/null +++ b/host/lib/usrp/e100/io_impl.cpp @@ -0,0 +1,327 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "recv_packet_demuxer.hpp" +#include "validate_subdev_spec.hpp" +#include "../../transport/super_recv_packet_handler.hpp" +#include "../../transport/super_send_packet_handler.hpp" +#include <linux/usrp_e.h> //ioctl structures and constants +#include "e100_impl.hpp" +#include "e100_regs.hpp" +#include <uhd/utils/msg.hpp> +#include <uhd/utils/log.hpp> +#include <uhd/utils/tasks.hpp> +#include <uhd/utils/thread_priority.hpp> +#include <uhd/transport/bounded_buffer.hpp> +#include <boost/bind.hpp> +#include <boost/format.hpp> +#include <boost/bind.hpp> +#include <boost/thread/thread.hpp> +#include <poll.h> //poll +#include <fcntl.h> //open, close +#include <sstream> +#include <fstream> + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::transport; + +/*********************************************************************** + * io impl details (internal to this file) + * - pirate crew of 1 + * - bounded buffer + * - thread loop + * - vrt packet handler states + **********************************************************************/ +struct e100_impl::io_impl{ + io_impl(void): + false_alarm(0), async_msg_fifo(100/*messages deep*/) + { /* NOP */ } + + double tick_rate; //set by update tick rate method + e100_ctrl::sptr iface; //so handle irq can peek and poke + void handle_irq(void); + size_t false_alarm; + //The data transport is listed first so that it is deconstructed last, + //which is after the states and booty which may hold managed buffers. + recv_packet_demuxer::sptr demuxer; + + //state management for the vrt packet handler code + sph::recv_packet_handler recv_handler; + sph::send_packet_handler send_handler; + + //a pirate's life is the life for me! + void recv_pirate_loop( + spi_iface::sptr //keep a sptr to iface which shares gpio147 + ){ + //open the GPIO and set it up for an IRQ + std::ofstream edge_file("/sys/class/gpio/gpio147/edge"); + edge_file << "rising" << std::endl << std::flush; + edge_file.close(); + int fd = ::open("/sys/class/gpio/gpio147/value", O_RDONLY); + if (fd < 0) UHD_MSG(error) << "Unable to open GPIO for IRQ\n"; + + while (not boost::this_thread::interruption_requested()){ + pollfd pfd; + pfd.fd = fd; + pfd.events = POLLPRI | POLLERR; + ssize_t ret = ::poll(&pfd, 1, 100/*ms*/); + if (ret > 0) this->handle_irq(); + } + + //cleanup before thread exit + ::close(fd); + } + bounded_buffer<async_metadata_t> async_msg_fifo; + task::sptr pirate_task; +}; + +void e100_impl::io_impl::handle_irq(void){ + //check the status of the async msg buffer + const boost::uint32_t status = iface->peek32(E100_REG_RB_ERR_STATUS); + if ((status & 0x3) == 0){ //not done or error + //This could be a false-alarm because spi readback is mixed in. + //So we just sleep for a bit rather than interrupt continuously. + if (false_alarm++ > 3) boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + return; + } + false_alarm = 0; //its a real message, reset the count... + //std::cout << boost::format("status: 0x%x") % status << std::endl; + + //load the data struct and call the ioctl + usrp_e_ctl32 data; + data.offset = E100_REG_ERR_BUFF; + data.count = status >> 16; + iface->ioctl(USRP_E_READ_CTL32, &data); + //for (size_t i = 0; i < data.count; i++){ + //data.buf[i] = iface->peek32(E100_REG_ERR_BUFF + i*sizeof(boost::uint32_t)); + //std::cout << boost::format(" buff[%u] = 0x%08x\n") % i % data.buf[i]; + //} + + //unpack the vrt header and process below... + vrt::if_packet_info_t if_packet_info; + if_packet_info.num_packet_words32 = data.count; + try{vrt::if_hdr_unpack_le(data.buf, if_packet_info);} + catch(const std::exception &e){ + UHD_MSG(error) << "Error unpacking vrt header:\n" << e.what() << std::endl; + goto prepare; + } + + //handle a tx async report message + if (if_packet_info.sid == E100_TX_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ + + //fill in the async metadata + async_metadata_t metadata; + metadata.channel = 0; + metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; + metadata.time_spec = time_spec_t( + time_t(if_packet_info.tsi), long(if_packet_info.tsf), tick_rate + ); + metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(data.buf, if_packet_info)); + + //push the message onto the queue + async_msg_fifo.push_with_pop_on_full(metadata); + + //print some fastpath messages + if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_UNDERFLOW + | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) + ) UHD_MSG(fastpath) << "U"; + else if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_SEQ_ERROR + | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) + ) UHD_MSG(fastpath) << "S"; + } + + //prepare for the next round + prepare: + iface->poke32(E100_REG_SR_ERR_CTRL, 1 << 0); //clear + while ((iface->peek32(E100_REG_RB_ERR_STATUS) & (1 << 2)) == 0){} //wait for idle + iface->poke32(E100_REG_SR_ERR_CTRL, 1 << 1); //start +} + +/*********************************************************************** + * Helper Functions + **********************************************************************/ +void e100_impl::io_init(void){ + + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN; + + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN; + + //create new io impl + _io_impl = UHD_PIMPL_MAKE(io_impl, ()); + _io_impl->demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), E100_RX_SID_BASE); + _io_impl->iface = _fpga_ctrl; + + //clear state machines + _fpga_ctrl->poke32(E100_REG_CLEAR_RX, 0); + _fpga_ctrl->poke32(E100_REG_CLEAR_TX, 0); + + //prepare the async msg buffer for incoming messages + _fpga_ctrl->poke32(E100_REG_SR_ERR_CTRL, 1 << 0); //clear + while ((_fpga_ctrl->peek32(E100_REG_RB_ERR_STATUS) & (1 << 2)) == 0){} //wait for idle + _fpga_ctrl->poke32(E100_REG_SR_ERR_CTRL, 1 << 1); //start + + //spawn a pirate, yarrr! + _io_impl->pirate_task = task::make(boost::bind( + &e100_impl::io_impl::recv_pirate_loop, _io_impl.get(), _aux_spi_iface + )); + + //init some handler stuff + _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le); + _io_impl->recv_handler.set_converter(_rx_otw_type); + _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le); + _io_impl->send_handler.set_converter(_tx_otw_type); + _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); +} + +void e100_impl::update_tick_rate(const double rate){ + _io_impl->tick_rate = rate; + boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); + _io_impl->recv_handler.set_tick_rate(rate); + boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); + _io_impl->send_handler.set_tick_rate(rate); +} + +void e100_impl::update_rx_samp_rate(const double rate){ + boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); + _io_impl->recv_handler.set_samp_rate(rate); + const double adj = _rx_dsps.front()->get_scaling_adjustment(); + _io_impl->recv_handler.set_scale_factor(adj/32767.); +} + +void e100_impl::update_tx_samp_rate(const double rate){ + boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); + _io_impl->send_handler.set_samp_rate(rate); +} + +void e100_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ + boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); + property_tree::path_type root = "/mboards/0/dboards"; + + //sanity checking + validate_subdev_spec(_tree, spec, "rx"); + + //setup mux for this spec + bool fe_swapped = false; + for (size_t i = 0; i < spec.size(); i++){ + const std::string conn = _tree->access<std::string>(root / spec[i].db_name / "rx_frontends" / spec[i].sd_name / "connection").get(); + if (i == 0 and (conn == "QI" or conn == "Q")) fe_swapped = true; + _rx_dsps[i]->set_mux(conn, fe_swapped); + } + _rx_fe->set_mux(fe_swapped); + + //resize for the new occupancy + _io_impl->recv_handler.resize(spec.size()); + + //bind new callbacks for the handler + for (size_t i = 0; i < _io_impl->recv_handler.size(); i++){ + _rx_dsps[i]->set_nsamps_per_packet(get_max_recv_samps_per_packet()); //seems to be a good place to set this + _io_impl->recv_handler.set_xport_chan_get_buff(i, boost::bind( + &recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, i, _1 + )); + _io_impl->recv_handler.set_overflow_handler(i, boost::bind(&rx_dsp_core_200::handle_overflow, _rx_dsps[i])); + } +} + +void e100_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ + boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); + property_tree::path_type root = "/mboards/0/dboards"; + + //sanity checking + validate_subdev_spec(_tree, spec, "tx"); + + //set the mux for this spec + const std::string conn = _tree->access<std::string>(root / spec[0].db_name / "tx_frontends" / spec[0].sd_name / "connection").get(); + _tx_fe->set_mux(conn); + + //resize for the new occupancy + _io_impl->send_handler.resize(spec.size()); + + //bind new callbacks for the handler + for (size_t i = 0; i < _io_impl->send_handler.size(); i++){ + _io_impl->send_handler.set_xport_chan_get_buff(i, boost::bind( + &zero_copy_if::get_send_buff, _data_transport, _1 + )); + } +} + +/*********************************************************************** + * Data Send + **********************************************************************/ +size_t e100_impl::get_max_send_samps_per_packet(void) const{ + static const size_t hdr_size = 0 + + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + ; + size_t bpp = _data_transport->get_send_frame_size() - hdr_size; + return bpp/_tx_otw_type.get_sample_size(); +} + +size_t e100_impl::send( + const send_buffs_type &buffs, size_t nsamps_per_buff, + const tx_metadata_t &metadata, const io_type_t &io_type, + send_mode_t send_mode, double timeout +){ + return _io_impl->send_handler.send( + buffs, nsamps_per_buff, + metadata, io_type, + send_mode, timeout + ); +} + +/*********************************************************************** + * Data Recv + **********************************************************************/ +size_t e100_impl::get_max_recv_samps_per_packet(void) const{ + static const size_t hdr_size = 0 + + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer + - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + ; + size_t bpp = _data_transport->get_recv_frame_size() - hdr_size; + return bpp/_rx_otw_type.get_sample_size(); +} + +size_t e100_impl::recv( + const recv_buffs_type &buffs, size_t nsamps_per_buff, + rx_metadata_t &metadata, const io_type_t &io_type, + recv_mode_t recv_mode, double timeout +){ + return _io_impl->recv_handler.recv( + buffs, nsamps_per_buff, + metadata, io_type, + recv_mode, timeout + ); +} + +/*********************************************************************** + * Async Recv + **********************************************************************/ +bool e100_impl::recv_async_msg( + async_metadata_t &async_metadata, double timeout +){ + boost::this_thread::disable_interruption di; //disable because the wait can throw + return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout); +} diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp index f65b0aac8..35fba547a 100644 --- a/host/lib/usrp/mboard_eeprom.cpp +++ b/host/lib/usrp/mboard_eeprom.cpp @@ -351,7 +351,7 @@ mboard_eeprom_t::mboard_eeprom_t(i2c_iface &iface, map_type map){ } } -void mboard_eeprom_t::commit(i2c_iface &iface, map_type map){ +void mboard_eeprom_t::commit(i2c_iface &iface, map_type map) const{ switch(map){ case MAP_N100: store_n100(*this, iface); break; case MAP_B000: store_b000(*this, iface); break; diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp deleted file mode 100644 index ddcad41cf..000000000 --- a/host/lib/usrp/misc_utils.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include <uhd/usrp/misc_utils.hpp> -#include <uhd/utils/assert_has.hpp> -#include <uhd/utils/algorithm.hpp> -#include <uhd/utils/gain_group.hpp> -#include <uhd/usrp/dboard_eeprom.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/usrp/codec_props.hpp> -#include <boost/bind.hpp> -#include <boost/foreach.hpp> -#include <boost/format.hpp> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * codec gain group helper functions: - * do this so we dont have to bind a templated function - **********************************************************************/ -static gain_range_t get_codec_gain_range(wax::obj codec, const std::string &name){ - return codec[named_prop_t(CODEC_PROP_GAIN_RANGE, name)].as<gain_range_t>(); -} - -static double get_codec_gain_i(wax::obj codec, const std::string &name){ - return codec[named_prop_t(CODEC_PROP_GAIN_I, name)].as<double>(); -} - -static double get_codec_gain_q(wax::obj codec, const std::string &name){ - return codec[named_prop_t(CODEC_PROP_GAIN_Q, name)].as<double>(); -} - -static void set_codec_gain_both(wax::obj codec, const std::string &name, double gain){ - codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain; - codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain; -} - -static void set_codec_gain_i(wax::obj codec, const std::string &name, double gain){ - codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain; -} - -static void set_codec_gain_q(wax::obj codec, const std::string &name, double gain){ - codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain; -} - -/*********************************************************************** - * subdev gain group helper functions: - * do this so we dont have to bind a templated function - **********************************************************************/ -static double get_subdev_gain(wax::obj subdev, const std::string &name){ - return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<double>(); -} - -static gain_range_t get_subdev_gain_range(wax::obj subdev, const std::string &name){ - return subdev[named_prop_t(SUBDEV_PROP_GAIN_RANGE, name)].as<gain_range_t>(); -} - -static void set_subdev_gain(wax::obj subdev, const std::string &name, double gain){ - subdev[named_prop_t(SUBDEV_PROP_GAIN, name)] = gain; -} - -/*********************************************************************** - * gain group factory function for usrp - **********************************************************************/ -gain_group::sptr usrp::make_gain_group( - const dboard_id_t &dboard_id, - wax::obj subdev, wax::obj codec, - gain_group_policy_t gain_group_policy -){ - const size_t subdev_gain_priority = 1; - const size_t codec_gain_priority = (gain_group_policy == GAIN_GROUP_POLICY_RX)? - (subdev_gain_priority - 1): //RX policy, codec gains fill last (lower priority) - (subdev_gain_priority + 1); //TX policy, codec gains fill first (higher priority) - const std::string subdev_prefix = dboard_id.to_cname() + "-"; - const std::string codec_prefix = (gain_group_policy == GAIN_GROUP_POLICY_RX)? "ADC-" : "DAC-"; - - gain_group::sptr gg = gain_group::make(); - gain_fcns_t fcns; - //add all the subdev gains first (antenna to dsp order) - BOOST_FOREACH(const std::string &name, subdev[SUBDEV_PROP_GAIN_NAMES].as<prop_names_t>()){ - fcns.get_range = boost::bind(&get_subdev_gain_range, subdev, name); - fcns.get_value = boost::bind(&get_subdev_gain, subdev, name); - fcns.set_value = boost::bind(&set_subdev_gain, subdev, name, _1); - gg->register_fcns(subdev_prefix+name, fcns, subdev_gain_priority); - } - //add all the codec gains last (antenna to dsp order) - BOOST_FOREACH(const std::string &name, codec[CODEC_PROP_GAIN_NAMES].as<prop_names_t>()){ - fcns.get_range = boost::bind(&get_codec_gain_range, codec, name); - - //register the value functions depending upon the connection type - switch(subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){ - case SUBDEV_CONN_COMPLEX_IQ: - case SUBDEV_CONN_COMPLEX_QI: - fcns.get_value = boost::bind(&get_codec_gain_i, codec, name); //same as Q - fcns.set_value = boost::bind(&set_codec_gain_both, codec, name, _1); //sets both - break; - - case SUBDEV_CONN_REAL_I: - fcns.get_value = boost::bind(&get_codec_gain_i, codec, name); - fcns.set_value = boost::bind(&set_codec_gain_i, codec, name, _1); - break; - - case SUBDEV_CONN_REAL_Q: - fcns.get_value = boost::bind(&get_codec_gain_q, codec, name); - fcns.set_value = boost::bind(&set_codec_gain_q, codec, name, _1); - break; - } - gg->register_fcns(codec_prefix+name, fcns, codec_gain_priority); - } - return gg; -} - -/*********************************************************************** - * verify subdev specs - **********************************************************************/ -static void verify_xx_subdev_spec( - mboard_prop_t dboard_names_prop, - mboard_prop_t dboard_prop, - subdev_spec_t &subdev_spec, - wax::obj mboard, - std::string xx_type -){ - try{ - prop_names_t dboard_names = mboard[dboard_names_prop].as<prop_names_t>(); - UHD_ASSERT_THROW(dboard_names.size() > 0); //well i hope there is a dboard - - //the subdevice specification is empty: handle automatic - if (subdev_spec.empty()){ - BOOST_FOREACH(const std::string &db_name, dboard_names){ - wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)]; - - //if the dboard slot is populated, take the first subdevice - if (dboard[DBOARD_PROP_DBOARD_EEPROM].as<dboard_eeprom_t>().id != dboard_id_t::none()){ - std::string sd_name = dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>().front(); - subdev_spec.push_back(subdev_spec_pair_t(db_name, sd_name)); - break; - } - } - - //didnt find any populated dboards: add the first subdevice - if (subdev_spec.empty()){ - std::string db_name = dboard_names.front(); - wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)]; - std::string sd_name = dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>().front(); - subdev_spec.push_back(subdev_spec_pair_t(db_name, sd_name)); - } - } - - //sanity check that the dboard/subdevice names exist for this mboard - BOOST_FOREACH(subdev_spec_pair_t &pair, subdev_spec){ - //empty db name means select dboard automatically - if (pair.db_name.empty()){ - if (dboard_names.size() != 1) throw uhd::value_error( - "A daughterboard name must be provided for multi-slot motherboards: " + subdev_spec.to_string() - ); - pair.db_name = dboard_names.front(); - } - uhd::assert_has(dboard_names, pair.db_name, xx_type + " dboard name"); - wax::obj dboard = mboard[named_prop_t(dboard_prop, pair.db_name)]; - prop_names_t subdev_names = dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>(); - - //empty sd name means select the subdev automatically - if (pair.sd_name.empty()){ - if (subdev_names.size() != 1) throw uhd::value_error( - "A subdevice name must be provided for multi-subdev daughterboards: " + subdev_spec.to_string() - ); - pair.sd_name = subdev_names.front(); - } - uhd::assert_has(subdev_names, pair.sd_name, xx_type + " subdev name"); - } - }catch(const std::exception &e){ - throw uhd::value_error(str(boost::format( - "Validate %s subdev spec failed: %s\n %s" - ) % xx_type % subdev_spec.to_string() % e.what())); - } - - //now use the subdev spec to enable the subdevices in use and vice-versa - BOOST_FOREACH(const std::string &db_name, mboard[dboard_names_prop].as<prop_names_t>()){ - wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)]; - BOOST_FOREACH(const std::string &sd_name, dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>()){ - try{ - bool enable = uhd::has(subdev_spec, subdev_spec_pair_t(db_name, sd_name)); - dboard[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)][SUBDEV_PROP_ENABLED] = enable; - } - catch(const std::exception &e){ - throw uhd::runtime_error(str(boost::format( - "Cannot set enabled property on subdevice %s:%s\n %s" - ) % db_name % sd_name % e.what())); - } - } - } -} - -void usrp::verify_rx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard){ - return verify_xx_subdev_spec( - MBOARD_PROP_RX_DBOARD_NAMES, - MBOARD_PROP_RX_DBOARD, - subdev_spec, mboard, "rx" - ); -} - -void usrp::verify_tx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard){ - return verify_xx_subdev_spec( - MBOARD_PROP_TX_DBOARD_NAMES, - MBOARD_PROP_TX_DBOARD, - subdev_spec, mboard, "tx" - ); -} diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 64f82e559..f9f5e675f 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -15,18 +15,13 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include <uhd/property_tree.hpp> #include <uhd/usrp/multi_usrp.hpp> -#include <uhd/usrp/tune_helper.hpp> #include <uhd/usrp/mboard_iface.hpp> #include <uhd/utils/msg.hpp> #include <uhd/exception.hpp> #include <uhd/utils/msg.hpp> #include <uhd/utils/gain_group.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/usrp/device_props.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/usrp/dsp_props.hpp> #include <boost/thread.hpp> #include <boost/foreach.hpp> #include <boost/format.hpp> @@ -40,15 +35,7 @@ const std::string multi_usrp::ALL_GAINS = ""; /*********************************************************************** * Helper methods **********************************************************************/ -static inline uhd::freq_range_t add_dsp_shift( - const uhd::freq_range_t &range, - wax::obj dsp -){ - double codec_rate = dsp[uhd::usrp::DSP_PROP_CODEC_RATE].as<double>(); - return uhd::freq_range_t(range.start() - codec_rate/2.0, range.stop() + codec_rate/2.0); -} - -static inline void do_samp_rate_warning_message( +static void do_samp_rate_warning_message( double target_rate, double actual_rate, const std::string &xx @@ -63,7 +50,7 @@ static inline void do_samp_rate_warning_message( } } -static inline void do_tune_freq_warning_message( +static void do_tune_freq_warning_message( double target_freq, double actual_freq, const std::string &xx @@ -79,12 +66,128 @@ static inline void do_tune_freq_warning_message( } /*********************************************************************** + * Gain helper functions + **********************************************************************/ +static double get_gain_value(property_tree::sptr subtree){ + return subtree->access<double>("value").get(); +} + +static void set_gain_value(property_tree::sptr subtree, const double gain){ + subtree->access<double>("value").set(gain); +} + +static meta_range_t get_gain_range(property_tree::sptr subtree){ + return subtree->access<meta_range_t>("range").get(); +} + +static gain_fcns_t make_gain_fcns_from_subtree(property_tree::sptr subtree){ + gain_fcns_t gain_fcns; + gain_fcns.get_range = boost::bind(&get_gain_range, subtree); + gain_fcns.get_value = boost::bind(&get_gain_value, subtree); + gain_fcns.set_value = boost::bind(&set_gain_value, subtree, _1); + return gain_fcns; +} + +/*********************************************************************** + * Tune Helper Functions + **********************************************************************/ +static const double RX_SIGN = +1.0; +static const double TX_SIGN = -1.0; + +static tune_result_t tune_xx_subdev_and_dsp( + const double xx_sign, + property_tree::sptr dsp_subtree, + property_tree::sptr rf_fe_subtree, + const tune_request_t &tune_request +){ + //------------------------------------------------------------------ + //-- calculate the LO offset, only used with automatic policy + //------------------------------------------------------------------ + double lo_offset = 0.0; + if (rf_fe_subtree->access<bool>("use_lo_offset").get()){ + //If the local oscillator will be in the passband, use an offset. + //But constrain the LO offset by the width of the filter bandwidth. + const double rate = dsp_subtree->access<double>("rate/value").get(); + const double bw = rf_fe_subtree->access<double>("bandwidth/value").get(); + if (bw > rate) lo_offset = std::min((bw - rate)/2, rate/2); + } + + //------------------------------------------------------------------ + //-- set the RF frequency depending upon the policy + //------------------------------------------------------------------ + double target_rf_freq = 0.0; + switch (tune_request.rf_freq_policy){ + case tune_request_t::POLICY_AUTO: + target_rf_freq = tune_request.target_freq + lo_offset; + rf_fe_subtree->access<double>("freq/value").set(target_rf_freq); + break; + + case tune_request_t::POLICY_MANUAL: + target_rf_freq = tune_request.rf_freq; + rf_fe_subtree->access<double>("freq/value").set(target_rf_freq); + break; + + case tune_request_t::POLICY_NONE: break; //does not set + } + const double actual_rf_freq = rf_fe_subtree->access<double>("freq/value").get(); + + //------------------------------------------------------------------ + //-- calculate the dsp freq, only used with automatic policy + //------------------------------------------------------------------ + double target_dsp_freq = actual_rf_freq - tune_request.target_freq; + + //invert the sign on the dsp freq for transmit + target_dsp_freq *= xx_sign; + + //------------------------------------------------------------------ + //-- set the dsp frequency depending upon the dsp frequency policy + //------------------------------------------------------------------ + switch (tune_request.dsp_freq_policy){ + case tune_request_t::POLICY_AUTO: + dsp_subtree->access<double>("freq/value").set(target_dsp_freq); + break; + + case tune_request_t::POLICY_MANUAL: + target_dsp_freq = tune_request.dsp_freq; + dsp_subtree->access<double>("freq/value").set(target_dsp_freq); + break; + + case tune_request_t::POLICY_NONE: break; //does not set + } + const double actual_dsp_freq = dsp_subtree->access<double>("freq/value").get(); + + //------------------------------------------------------------------ + //-- load and return the tune result + //------------------------------------------------------------------ + tune_result_t tune_result; + tune_result.target_rf_freq = target_rf_freq; + tune_result.actual_rf_freq = actual_rf_freq; + tune_result.target_dsp_freq = target_dsp_freq; + tune_result.actual_dsp_freq = actual_dsp_freq; + return tune_result; +} + +static double derive_freq_from_xx_subdev_and_dsp( + const double xx_sign, + property_tree::sptr dsp_subtree, + property_tree::sptr rf_fe_subtree +){ + //extract actual dsp and IF frequencies + const double actual_rf_freq = rf_fe_subtree->access<double>("freq/value").get(); + const double actual_dsp_freq = dsp_subtree->access<double>("freq/value").get(); + + //invert the sign on the dsp freq for transmit + return actual_rf_freq - actual_dsp_freq * xx_sign; +} + +/*********************************************************************** * Multi USRP Implementation **********************************************************************/ class multi_usrp_impl : public multi_usrp{ public: multi_usrp_impl(const device_addr_t &addr){ _dev = device::make(addr); + _tree = (*_dev)[0].as<property_tree::sptr>(); } device::sptr get_device(void){ @@ -96,7 +199,7 @@ public: ******************************************************************/ void set_master_clock_rate(double rate, size_t mboard){ if (mboard != ALL_MBOARDS){ - _mboard(mboard)[MBOARD_PROP_CLOCK_RATE] = rate; + _tree->access<double>(mb_root(mboard) / "tick_rate").set(rate); return; } for (size_t m = 0; m < get_num_mboards(); m++){ @@ -105,7 +208,7 @@ public: } double get_master_clock_rate(size_t mboard){ - return _mboard(mboard)[MBOARD_PROP_CLOCK_RATE].as<double>(); + return _tree->access<double>(mb_root(mboard) / "tick_rate").get(); } std::string get_pp_string(void){ @@ -114,13 +217,13 @@ public: " Device: %s\n" ) % ((get_num_mboards() > 1)? "Multi" : "Single") - % (*_dev)[DEVICE_PROP_NAME].as<std::string>() + % (_tree->access<std::string>("/name").get()) ); for (size_t m = 0; m < get_num_mboards(); m++){ buff += str(boost::format( " Mboard %d: %s\n" ) % m - % _mboard(m)[MBOARD_PROP_NAME].as<std::string>() + % (_tree->access<std::string>(mb_root(m) / "name").get()) ); } @@ -133,9 +236,9 @@ public: " RX Dboard: %s\n" " RX Subdev: %s\n" ) % chan - % _rx_dsp(chan)[DSP_PROP_NAME].as<std::string>() - % _rx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>() - % _rx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>() + % rx_dsp_root(chan).leaf() + % rx_rf_fe_root(chan).branch_path().branch_path().leaf() + % (_tree->access<std::string>(rx_rf_fe_root(chan) / "name").get()) ); } } @@ -149,9 +252,9 @@ public: " TX Dboard: %s\n" " TX Subdev: %s\n" ) % chan - % _tx_dsp(chan)[DSP_PROP_NAME].as<std::string>() - % _tx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>() - % _tx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>() + % tx_dsp_root(chan).leaf() + % tx_rf_fe_root(chan).branch_path().branch_path().leaf() + % (_tree->access<std::string>(tx_rf_fe_root(chan) / "name").get()) ); } } @@ -160,20 +263,20 @@ public: } std::string get_mboard_name(size_t mboard){ - return _mboard(mboard)[MBOARD_PROP_NAME].as<std::string>(); + return _tree->access<std::string>(mb_root(mboard) / "name").get(); } time_spec_t get_time_now(size_t mboard = 0){ - return _mboard(mboard)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); + return _tree->access<time_spec_t>(mb_root(mboard) / "time/now").get(); } time_spec_t get_time_last_pps(size_t mboard = 0){ - return _mboard(mboard)[MBOARD_PROP_TIME_PPS].as<time_spec_t>(); + return _tree->access<time_spec_t>(mb_root(mboard) / "time/pps").get(); } void set_time_now(const time_spec_t &time_spec, size_t mboard){ if (mboard != ALL_MBOARDS){ - _mboard(mboard)[MBOARD_PROP_TIME_NOW] = time_spec; + _tree->access<time_spec_t>(mb_root(mboard) / "time/now").set(time_spec); return; } for (size_t m = 0; m < get_num_mboards(); m++){ @@ -183,7 +286,7 @@ public: void set_time_next_pps(const time_spec_t &time_spec){ for (size_t m = 0; m < get_num_mboards(); m++){ - _mboard(m)[MBOARD_PROP_TIME_PPS] = time_spec; + _tree->access<time_spec_t>(mb_root(m) / "time/pps").set(time_spec); } } @@ -208,8 +311,8 @@ public: //verify that the time registers are read to be within a few RTT for (size_t m = 1; m < get_num_mboards(); m++){ - time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); - time_spec_t time_i = _mboard(m)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); + time_spec_t time_0 = this->get_time_now(0); + time_spec_t time_i = this->get_time_now(m); if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big UHD_MSG(warning) << boost::format( "Detected time deviation between board %d and board 0.\n" @@ -222,8 +325,8 @@ public: bool get_time_synchronized(void){ for (size_t m = 1; m < get_num_mboards(); m++){ - time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); - time_spec_t time_i = _mboard(m)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); + time_spec_t time_0 = this->get_time_now(0); + time_spec_t time_i = this->get_time_now(m); if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)) return false; } return true; @@ -231,7 +334,7 @@ public: void issue_stream_cmd(const stream_cmd_t &stream_cmd, size_t chan){ if (chan != ALL_CHANS){ - _rx_dsp(chan)[DSP_PROP_STREAM_CMD] = stream_cmd; + _tree->access<stream_cmd_t>(rx_dsp_root(chan) / "stream_cmd").set(stream_cmd); return; } for (size_t c = 0; c < get_rx_num_channels(); c++){ @@ -241,7 +344,26 @@ public: void set_clock_config(const clock_config_t &clock_config, size_t mboard){ if (mboard != ALL_MBOARDS){ - _mboard(mboard)[MBOARD_PROP_CLOCK_CONFIG] = clock_config; + //set the reference source... + std::string clock_source; + switch(clock_config.ref_source){ + case clock_config_t::REF_INT: clock_source = "internal"; break; + case clock_config_t::PPS_SMA: clock_source = "external"; break; + case clock_config_t::PPS_MIMO: clock_source = "mimo"; break; + default: clock_source = "unknown"; + } + if (clock_source == "external" and clock_config.pps_polarity == clock_config_t::PPS_NEG) clock_source = "_external_"; + _tree->access<std::string>(mb_root(mboard) / "clock_source" / "value").set(clock_source); + + //set the time source + std::string time_source; + switch(clock_config.pps_source){ + case clock_config_t::PPS_INT: time_source = "internal"; break; + case clock_config_t::PPS_SMA: time_source = "external"; break; + case clock_config_t::PPS_MIMO: time_source = "mimo"; break; + default: time_source = "unknown"; + } + _tree->access<std::string>(mb_root(mboard) / "time_source" / "value").set(time_source); return; } for (size_t m = 0; m < get_num_mboards(); m++){ @@ -250,19 +372,19 @@ public: } size_t get_num_mboards(void){ - return (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>().size(); + return _tree->list("/mboards").size(); } sensor_value_t get_mboard_sensor(const std::string &name, size_t mboard){ - return _mboard(mboard)[named_prop_t(MBOARD_PROP_SENSOR, name)].as<sensor_value_t>(); + return _tree->access<sensor_value_t>(mb_root(mboard) / "sensors" / name).get(); } std::vector<std::string> get_mboard_sensor_names(size_t mboard){ - return _mboard(mboard)[MBOARD_PROP_SENSOR_NAMES].as<prop_names_t>(); + return _tree->list(mb_root(mboard) / "sensors"); } - - mboard_iface::sptr get_mboard_iface(size_t mboard){ - return _mboard(mboard)[MBOARD_PROP_IFACE].as<mboard_iface::sptr>(); + + mboard_iface::sptr get_mboard_iface(size_t){ + return mboard_iface::sptr(); //not implemented } /******************************************************************* @@ -270,7 +392,7 @@ public: ******************************************************************/ void set_rx_subdev_spec(const subdev_spec_t &spec, size_t mboard){ if (mboard != ALL_MBOARDS){ - _mboard(mboard)[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; + _tree->access<subdev_spec_t>(mb_root(mboard) / "rx_subdev_spec").set(spec); return; } for (size_t m = 0; m < get_num_mboards(); m++){ @@ -279,7 +401,7 @@ public: } subdev_spec_t get_rx_subdev_spec(size_t mboard){ - return _mboard(mboard)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>(); + return _tree->access<subdev_spec_t>(mb_root(mboard) / "rx_subdev_spec").get(); } size_t get_rx_num_channels(void){ @@ -291,12 +413,12 @@ public: } std::string get_rx_subdev_name(size_t chan){ - return _rx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>(); + return _tree->access<std::string>(rx_rf_fe_root(chan) / "name").get(); } void set_rx_rate(double rate, size_t chan){ if (chan != ALL_CHANS){ - _rx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; + _tree->access<double>(rx_dsp_root(chan) / "rate" / "value").set(rate); do_samp_rate_warning_message(rate, get_rx_rate(chan), "RX"); return; } @@ -306,69 +428,71 @@ public: } double get_rx_rate(size_t chan){ - return _rx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>(); + return _tree->access<double>(rx_dsp_root(chan) / "rate" / "value").get(); } tune_result_t set_rx_freq(const tune_request_t &tune_request, size_t chan){ - tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), tune_request); + tune_result_t r = tune_xx_subdev_and_dsp(RX_SIGN, _tree->subtree(rx_dsp_root(chan)), _tree->subtree(rx_rf_fe_root(chan)), tune_request); do_tune_freq_warning_message(tune_request.target_freq, get_rx_freq(chan), "RX"); return r; } double get_rx_freq(size_t chan){ - return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan)); + return derive_freq_from_xx_subdev_and_dsp(RX_SIGN, _tree->subtree(rx_dsp_root(chan)), _tree->subtree(rx_rf_fe_root(chan))); } freq_range_t get_rx_freq_range(size_t chan){ - return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp(chan)); + meta_range_t range = _tree->access<meta_range_t>(rx_rf_fe_root(chan) / "freq" / "range").get(); + meta_range_t dsp_range = _tree->access<meta_range_t>(rx_dsp_root(chan) / "freq" / "range").get(); + return meta_range_t(range.start() + dsp_range.start(), range.stop() + dsp_range.stop(), dsp_range.step()); } void set_rx_gain(double gain, const std::string &name, size_t chan){ - return _rx_gain_group(chan)->set_value(gain, name); + return rx_gain_group(chan)->set_value(gain, name); } double get_rx_gain(const std::string &name, size_t chan){ - return _rx_gain_group(chan)->get_value(name); + return rx_gain_group(chan)->get_value(name); } gain_range_t get_rx_gain_range(const std::string &name, size_t chan){ - return _rx_gain_group(chan)->get_range(name); + return rx_gain_group(chan)->get_range(name); } std::vector<std::string> get_rx_gain_names(size_t chan){ - return _rx_gain_group(chan)->get_names(); + return rx_gain_group(chan)->get_names(); } void set_rx_antenna(const std::string &ant, size_t chan){ - _rx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; + _tree->access<std::string>(rx_rf_fe_root(chan) / "antenna" / "value").set(ant); } std::string get_rx_antenna(size_t chan){ - return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>(); + return _tree->access<std::string>(rx_rf_fe_root(chan) / "antenna" / "value").get(); } std::vector<std::string> get_rx_antennas(size_t chan){ - return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); + return _tree->access<std::vector<std::string> >(rx_rf_fe_root(chan) / "antenna" / "options").get(); } void set_rx_bandwidth(double bandwidth, size_t chan){ - _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; + _tree->access<double>(rx_rf_fe_root(chan) / "bandwidth" / "value").set(bandwidth); } double get_rx_bandwidth(size_t chan){ - return _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as<double>(); + return _tree->access<double>(rx_rf_fe_root(chan) / "bandwidth" / "value").get(); } dboard_iface::sptr get_rx_dboard_iface(size_t chan){ - return _rx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>(); + return _tree->access<dboard_iface::sptr>(rx_rf_fe_root(chan).branch_path().branch_path() / "iface").get(); } sensor_value_t get_rx_sensor(const std::string &name, size_t chan){ - return _rx_subdev(chan)[named_prop_t(SUBDEV_PROP_SENSOR, name)].as<sensor_value_t>(); + return _tree->access<sensor_value_t>(rx_rf_fe_root(chan) / "sensors" / name).get(); } std::vector<std::string> get_rx_sensor_names(size_t chan){ - return _rx_subdev(chan)[SUBDEV_PROP_SENSOR_NAMES].as<prop_names_t>(); + return _tree->list(rx_rf_fe_root(chan) / "sensors"); } /******************************************************************* @@ -376,7 +500,7 @@ public: ******************************************************************/ void set_tx_subdev_spec(const subdev_spec_t &spec, size_t mboard){ if (mboard != ALL_MBOARDS){ - _mboard(mboard)[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; + _tree->access<subdev_spec_t>(mb_root(mboard) / "tx_subdev_spec").set(spec); return; } for (size_t m = 0; m < get_num_mboards(); m++){ @@ -385,11 +509,11 @@ public: } subdev_spec_t get_tx_subdev_spec(size_t mboard){ - return _mboard(mboard)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>(); + return _tree->access<subdev_spec_t>(mb_root(mboard) / "tx_subdev_spec").get(); } std::string get_tx_subdev_name(size_t chan){ - return _tx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>(); + return _tree->access<std::string>(tx_rf_fe_root(chan) / "name").get(); } size_t get_tx_num_channels(void){ @@ -402,7 +526,7 @@ public: void set_tx_rate(double rate, size_t chan){ if (chan != ALL_CHANS){ - _tx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; + _tree->access<double>(tx_dsp_root(chan) / "rate" / "value").set(rate); do_samp_rate_warning_message(rate, get_tx_rate(chan), "TX"); return; } @@ -412,73 +536,76 @@ public: } double get_tx_rate(size_t chan){ - return _tx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>(); + return _tree->access<double>(tx_dsp_root(chan) / "rate" / "value").get(); } tune_result_t set_tx_freq(const tune_request_t &tune_request, size_t chan){ - tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), tune_request); + tune_result_t r = tune_xx_subdev_and_dsp(TX_SIGN, _tree->subtree(tx_dsp_root(chan)), _tree->subtree(tx_rf_fe_root(chan)), tune_request); do_tune_freq_warning_message(tune_request.target_freq, get_tx_freq(chan), "TX"); return r; } double get_tx_freq(size_t chan){ - return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan)); + return derive_freq_from_xx_subdev_and_dsp(TX_SIGN, _tree->subtree(tx_dsp_root(chan)), _tree->subtree(tx_rf_fe_root(chan))); } freq_range_t get_tx_freq_range(size_t chan){ - return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp(chan)); + meta_range_t range = _tree->access<meta_range_t>(tx_rf_fe_root(chan) / "freq" / "range").get(); + meta_range_t dsp_range = _tree->access<meta_range_t>(tx_dsp_root(chan) / "freq" / "range").get(); + return meta_range_t(range.start() + dsp_range.start(), range.stop() + dsp_range.stop(), dsp_range.step()); } void set_tx_gain(double gain, const std::string &name, size_t chan){ - return _tx_gain_group(chan)->set_value(gain, name); + return tx_gain_group(chan)->set_value(gain, name); } double get_tx_gain(const std::string &name, size_t chan){ - return _tx_gain_group(chan)->get_value(name); + return tx_gain_group(chan)->get_value(name); } gain_range_t get_tx_gain_range(const std::string &name, size_t chan){ - return _tx_gain_group(chan)->get_range(name); + return tx_gain_group(chan)->get_range(name); } std::vector<std::string> get_tx_gain_names(size_t chan){ - return _tx_gain_group(chan)->get_names(); + return tx_gain_group(chan)->get_names(); } void set_tx_antenna(const std::string &ant, size_t chan){ - _tx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; + _tree->access<std::string>(tx_rf_fe_root(chan) / "antenna" / "value").set(ant); } std::string get_tx_antenna(size_t chan){ - return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>(); + return _tree->access<std::string>(tx_rf_fe_root(chan) / "antenna" / "value").get(); } std::vector<std::string> get_tx_antennas(size_t chan){ - return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); + return _tree->access<std::vector<std::string> >(tx_rf_fe_root(chan) / "antenna" / "options").get(); } void set_tx_bandwidth(double bandwidth, size_t chan){ - _tx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; + _tree->access<double>(tx_rf_fe_root(chan) / "bandwidth" / "value").set(bandwidth); } double get_tx_bandwidth(size_t chan){ - return _tx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as<double>(); + return _tree->access<double>(tx_rf_fe_root(chan) / "bandwidth" / "value").get(); } dboard_iface::sptr get_tx_dboard_iface(size_t chan){ - return _tx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>(); + return _tree->access<dboard_iface::sptr>(tx_rf_fe_root(chan).branch_path().branch_path() / "iface").get(); } sensor_value_t get_tx_sensor(const std::string &name, size_t chan){ - return _tx_subdev(chan)[named_prop_t(SUBDEV_PROP_SENSOR, name)].as<sensor_value_t>(); + return _tree->access<sensor_value_t>(tx_rf_fe_root(chan) / "sensors" / name).get(); } std::vector<std::string> get_tx_sensor_names(size_t chan){ - return _tx_subdev(chan)[SUBDEV_PROP_SENSOR_NAMES].as<prop_names_t>(); + return _tree->list(tx_rf_fe_root(chan) / "sensors"); } private: device::sptr _dev; + property_tree::sptr _tree; struct mboard_chan_pair{ size_t mboard, chan; @@ -507,49 +634,59 @@ private: return mcp; } - wax::obj _mboard(size_t mboard){ - std::string mb_name = (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>().at(mboard); - return (*_dev)[named_prop_t(DEVICE_PROP_MBOARD, mb_name)]; + property_tree::path_type mb_root(const size_t mboard){ + const std::string name = _tree->list("/mboards").at(mboard); + return "/mboards/" + name; } - wax::obj _rx_dsp(size_t chan){ - mboard_chan_pair mcp = rx_chan_to_mcp(chan); - prop_names_t dsp_names = _mboard(mcp.mboard)[MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>(); - return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_RX_DSP, dsp_names.at(mcp.chan))]; - } - wax::obj _tx_dsp(size_t chan){ - mboard_chan_pair mcp = tx_chan_to_mcp(chan); - prop_names_t dsp_names = _mboard(mcp.mboard)[MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>(); - return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_TX_DSP, dsp_names.at(mcp.chan))]; - } - wax::obj _rx_dboard(size_t chan){ + + property_tree::path_type rx_dsp_root(const size_t chan){ mboard_chan_pair mcp = rx_chan_to_mcp(chan); - std::string db_name = get_rx_subdev_spec(mcp.mboard).at(mcp.chan).db_name; - return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; + const std::string name = _tree->list(mb_root(mcp.mboard) / "rx_dsps").at(mcp.chan); + return mb_root(mcp.mboard) / "rx_dsps" / name; } - wax::obj _tx_dboard(size_t chan){ + + property_tree::path_type tx_dsp_root(const size_t chan){ mboard_chan_pair mcp = tx_chan_to_mcp(chan); - std::string db_name = get_tx_subdev_spec(mcp.mboard).at(mcp.chan).db_name; - return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; + const std::string name = _tree->list(mb_root(mcp.mboard) / "tx_dsps").at(mcp.chan); + return mb_root(mcp.mboard) / "tx_dsps" / name; } - wax::obj _rx_subdev(size_t chan){ + + property_tree::path_type rx_rf_fe_root(const size_t chan){ mboard_chan_pair mcp = rx_chan_to_mcp(chan); - std::string sd_name = get_rx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name; - return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; + const subdev_spec_pair_t spec = get_rx_subdev_spec(mcp.mboard).at(mcp.chan); + return mb_root(mcp.mboard) / "dboards" / spec.db_name / "rx_frontends" / spec.sd_name; } - wax::obj _tx_subdev(size_t chan){ + + property_tree::path_type tx_rf_fe_root(const size_t chan){ mboard_chan_pair mcp = tx_chan_to_mcp(chan); - std::string sd_name = get_tx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name; - return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; + const subdev_spec_pair_t spec = get_tx_subdev_spec(mcp.mboard).at(mcp.chan); + return mb_root(mcp.mboard) / "dboards" / spec.db_name / "tx_frontends" / spec.sd_name; } - gain_group::sptr _rx_gain_group(size_t chan){ + + gain_group::sptr rx_gain_group(size_t chan){ mboard_chan_pair mcp = rx_chan_to_mcp(chan); - std::string sd_name = get_rx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name; - return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); + const subdev_spec_pair_t spec = get_rx_subdev_spec(mcp.mboard).at(mcp.chan); + gain_group::sptr gg = gain_group::make(); + BOOST_FOREACH(const std::string &name, _tree->list(mb_root(mcp.mboard) / "rx_codecs" / spec.db_name / "gains")){ + gg->register_fcns("ADC-"+name, make_gain_fcns_from_subtree(_tree->subtree(mb_root(mcp.mboard) / "rx_codecs" / spec.db_name / "gains" / name)), 0 /* low prio */); + } + BOOST_FOREACH(const std::string &name, _tree->list(rx_rf_fe_root(chan) / "gains")){ + gg->register_fcns(name, make_gain_fcns_from_subtree(_tree->subtree(rx_rf_fe_root(chan) / "gains" / name)), 1 /* high prio */); + } + return gg; } - gain_group::sptr _tx_gain_group(size_t chan){ + + gain_group::sptr tx_gain_group(size_t chan){ mboard_chan_pair mcp = tx_chan_to_mcp(chan); - std::string sd_name = get_tx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name; - return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); + const subdev_spec_pair_t spec = get_tx_subdev_spec(mcp.mboard).at(mcp.chan); + gain_group::sptr gg = gain_group::make(); + BOOST_FOREACH(const std::string &name, _tree->list(mb_root(mcp.mboard) / "tx_codecs" / spec.db_name / "gains")){ + gg->register_fcns("ADC-"+name, make_gain_fcns_from_subtree(_tree->subtree(mb_root(mcp.mboard) / "tx_codecs" / spec.db_name / "gains" / name)), 1 /* high prio */); + } + BOOST_FOREACH(const std::string &name, _tree->list(tx_rf_fe_root(chan) / "gains")){ + gg->register_fcns(name, make_gain_fcns_from_subtree(_tree->subtree(tx_rf_fe_root(chan) / "gains" / name)), 0 /* low prio */); + } + return gg; } }; diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp deleted file mode 100644 index 264e6c04b..000000000 --- a/host/lib/usrp/tune_helper.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include <uhd/usrp/tune_helper.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/usrp/dsp_props.hpp> -#include <uhd/usrp/dboard_iface.hpp> //unit_t -#include <uhd/utils/algorithm.hpp> -#include <cmath> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Tune Helper Functions - **********************************************************************/ -static tune_result_t tune_xx_subdev_and_dsp( - dboard_iface::unit_t unit, - wax::obj subdev, wax::obj dsp, - const tune_request_t &tune_request -){ - wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; - wax::obj dsp_freq_proxy = dsp[DSP_PROP_FREQ_SHIFT]; - - //------------------------------------------------------------------ - //-- calculate the LO offset, only used with automatic policy - //------------------------------------------------------------------ - double lo_offset = 0.0; - if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){ - //If the local oscillator will be in the passband, use an offset. - //But constrain the LO offset by the width of the filter bandwidth. - double rate = dsp[DSP_PROP_HOST_RATE].as<double>(); - double bw = subdev[SUBDEV_PROP_BANDWIDTH].as<double>(); - if (bw > rate) lo_offset = std::min((bw - rate)/2, rate/2); - } - - //------------------------------------------------------------------ - //-- set the RF frequency depending upon the policy - //------------------------------------------------------------------ - double target_rf_freq = 0.0; - switch (tune_request.rf_freq_policy){ - case tune_request_t::POLICY_AUTO: - target_rf_freq = tune_request.target_freq + lo_offset; - subdev_freq_proxy = target_rf_freq; - break; - - case tune_request_t::POLICY_MANUAL: - target_rf_freq = tune_request.rf_freq; - subdev_freq_proxy = target_rf_freq; - break; - - case tune_request_t::POLICY_NONE: break; //does not set - } - double actual_rf_freq = subdev_freq_proxy.as<double>(); - - //------------------------------------------------------------------ - //-- calculate the dsp freq, only used with automatic policy - //------------------------------------------------------------------ - double target_dsp_freq = actual_rf_freq - tune_request.target_freq; - - //invert the sign on the dsp freq given the following conditions - if (unit == dboard_iface::UNIT_TX) target_dsp_freq *= -1.0; - - //------------------------------------------------------------------ - //-- set the dsp frequency depending upon the dsp frequency policy - //------------------------------------------------------------------ - switch (tune_request.dsp_freq_policy){ - case tune_request_t::POLICY_AUTO: - dsp_freq_proxy = target_dsp_freq; - break; - - case tune_request_t::POLICY_MANUAL: - target_dsp_freq = tune_request.dsp_freq; - dsp_freq_proxy = target_dsp_freq; - break; - - case tune_request_t::POLICY_NONE: break; //does not set - } - double actual_dsp_freq = dsp_freq_proxy.as<double>(); - - //------------------------------------------------------------------ - //-- load and return the tune result - //------------------------------------------------------------------ - tune_result_t tune_result; - tune_result.target_rf_freq = target_rf_freq; - tune_result.actual_rf_freq = actual_rf_freq; - tune_result.target_dsp_freq = target_dsp_freq; - tune_result.actual_dsp_freq = actual_dsp_freq; - return tune_result; -} - -static double derive_freq_from_xx_subdev_and_dsp( - dboard_iface::unit_t unit, wax::obj subdev, wax::obj dsp -){ - //extract actual dsp and IF frequencies - double actual_rf_freq = subdev[SUBDEV_PROP_FREQ].as<double>(); - double actual_dsp_freq = dsp[DSP_PROP_FREQ_SHIFT].as<double>(); - - //invert the sign on the dsp freq given the following conditions - if (unit == dboard_iface::UNIT_TX) actual_dsp_freq *= -1.0; - - return actual_rf_freq - actual_dsp_freq; -} - -/*********************************************************************** - * RX Tune - **********************************************************************/ -tune_result_t usrp::tune_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc, const tune_request_t &tune_request -){ - return tune_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc, tune_request); -} - -double usrp::derive_freq_from_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc -){ - return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc); -} - -/*********************************************************************** - * TX Tune - **********************************************************************/ -tune_result_t usrp::tune_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc, const tune_request_t &tune_request -){ - return tune_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc, tune_request); -} - -double usrp::derive_freq_from_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc -){ - return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc); -} diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt index c208cfe8c..70bebe502 100644 --- a/host/lib/usrp/usrp1/CMakeLists.txt +++ b/host/lib/usrp/usrp1/CMakeLists.txt @@ -26,20 +26,11 @@ LIBUHD_REGISTER_COMPONENT("USRP1" ENABLE_USRP1 ON "ENABLE_LIBUHD;ENABLE_USB" OFF IF(ENABLE_USRP1) LIBUHD_APPEND_SOURCES( - ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/soft_time_ctrl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/usrp1_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp1_iface.hpp ${CMAKE_CURRENT_SOURCE_DIR}/usrp1_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp1_impl.hpp ) ENDIF(ENABLE_USRP1) diff --git a/host/lib/usrp/usrp1/clock_ctrl.cpp b/host/lib/usrp/usrp1/clock_ctrl.cpp deleted file mode 100644 index 9edc010dd..000000000 --- a/host/lib/usrp/usrp1/clock_ctrl.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "clock_ctrl.hpp" -#include <uhd/utils/msg.hpp> -#include <boost/lexical_cast.hpp> -#include <boost/format.hpp> - -using namespace uhd; - -/*********************************************************************** - * Constants - **********************************************************************/ -static const double default_master_clock_rate = 64e6; - -/*********************************************************************** - * Clock Control Implementation - **********************************************************************/ -class usrp1_clock_ctrl_impl : public usrp1_clock_ctrl { -public: - usrp1_clock_ctrl_impl(usrp1_iface::sptr iface): _iface(iface){ - this->set_master_clock_freq(default_master_clock_rate); - try{ - if (not _iface->mb_eeprom["mcr"].empty()){ - UHD_MSG(status) << "Read FPGA clock rate from EEPROM setting." << std::endl; - const double master_clock_rate = boost::lexical_cast<double>(_iface->mb_eeprom["mcr"]); - UHD_MSG(status) << boost::format("Initializing FPGA clock to %fMHz...") % (master_clock_rate/1e6) << std::endl; - this->set_master_clock_freq(master_clock_rate); - } - } - catch(const std::exception &e){ - UHD_MSG(error) << "Error setting FPGA clock rate from EEPROM: " << e.what() << std::endl; - } - } - - void set_master_clock_freq(double freq){ - _freq = freq; - } - - double get_master_clock_freq(void){ - return _freq; - } - -private: - usrp1_iface::sptr _iface; - double _freq; -}; - -/*********************************************************************** - * Clock Control Make - **********************************************************************/ -usrp1_clock_ctrl::sptr usrp1_clock_ctrl::make(usrp1_iface::sptr iface){ - return sptr(new usrp1_clock_ctrl_impl(iface)); -} diff --git a/host/lib/usrp/usrp1/clock_ctrl.hpp b/host/lib/usrp/usrp1/clock_ctrl.hpp deleted file mode 100644 index 339d547e6..000000000 --- a/host/lib/usrp/usrp1/clock_ctrl.hpp +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_USRP1_CLOCK_CTRL_HPP -#define INCLUDED_USRP1_CLOCK_CTRL_HPP - -#include "usrp1_iface.hpp" -#include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> -#include <vector> - -/*! - * The usrp1 clock control: - * - Setup system clocks. - * - Disable/enable clock lines. - */ -class usrp1_clock_ctrl : boost::noncopyable{ -public: - typedef boost::shared_ptr<usrp1_clock_ctrl> sptr; - - /*! - * Make a new clock control object. - * \param iface the usrp1 iface object - * \return the clock control object - */ - static sptr make(usrp1_iface::sptr iface); - - /*! - * Set the rate of the fpga clock line. - * Note: does not really set, its all software. - * \param freq the new clock rate in Hz - */ - virtual void set_master_clock_freq(double freq) = 0; - - /*! - * Get the rate of the fpga clock line. - * \return the fpga clock rate in Hz - */ - virtual double get_master_clock_freq(void) = 0; - -}; - -#endif /* INCLUDED_USRP1_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 448135185..c82569ea3 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -16,8 +16,6 @@ // #include "codec_ctrl.hpp" -#include "usrp_commands.h" -#include "clock_ctrl.hpp" #include "ad9862_regs.hpp" #include <uhd/utils/log.hpp> #include <uhd/utils/safe_call.hpp> @@ -43,9 +41,7 @@ const gain_range_t usrp1_codec_ctrl::rx_pga_gain_range(0, 20, 1); class usrp1_codec_ctrl_impl : public usrp1_codec_ctrl { public: //structors - usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, - usrp1_clock_ctrl::sptr clock, - int spi_slave); + usrp1_codec_ctrl_impl(spi_iface::sptr iface, int spi_slave); ~usrp1_codec_ctrl_impl(void); //aux adc and dac control @@ -53,7 +49,7 @@ public: void write_aux_dac(aux_dac_t which, double volts); //duc control - void set_duc_freq(double freq); + void set_duc_freq(double freq, double); void enable_tx_digital(bool enb); //pga gain control @@ -66,8 +62,7 @@ public: void bypass_adc_buffers(bool bypass); private: - usrp1_iface::sptr _iface; - usrp1_clock_ctrl::sptr _clock_ctrl; + spi_iface::sptr _iface; int _spi_slave; ad9862_regs_t _ad9862_regs; void send_reg(boost::uint8_t addr); @@ -80,12 +75,8 @@ private: /*********************************************************************** * Codec Control Structors **********************************************************************/ -usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, - usrp1_clock_ctrl::sptr clock, - int spi_slave) -{ +usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(spi_iface::sptr iface, int spi_slave){ _iface = iface; - _clock_ctrl = clock; _spi_slave = spi_slave; //soft reset @@ -381,9 +372,9 @@ double usrp1_codec_ctrl_impl::fine_tune(double codec_rate, double target_freq) return actual_freq; } -void usrp1_codec_ctrl_impl::set_duc_freq(double freq) +void usrp1_codec_ctrl_impl::set_duc_freq(double freq, double rate) { - double codec_rate = _clock_ctrl->get_master_clock_freq() * 2; + double codec_rate = rate * 2; double coarse_freq = coarse_tune(codec_rate, freq); double fine_freq = fine_tune(codec_rate / 4, freq - coarse_freq); @@ -421,9 +412,8 @@ void usrp1_codec_ctrl_impl::bypass_adc_buffers(bool bypass) { /*********************************************************************** * Codec Control Make **********************************************************************/ -usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(usrp1_iface::sptr iface, - usrp1_clock_ctrl::sptr clock, +usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(spi_iface::sptr iface, int spi_slave) { - return sptr(new usrp1_codec_ctrl_impl(iface, clock, spi_slave)); + return sptr(new usrp1_codec_ctrl_impl(iface, spi_slave)); } diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp index 20e4015c5..70f4e0b61 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.hpp +++ b/host/lib/usrp/usrp1/codec_ctrl.hpp @@ -18,8 +18,7 @@ #ifndef INCLUDED_USRP1_CODEC_CTRL_HPP #define INCLUDED_USRP1_CODEC_CTRL_HPP -#include "usrp1_iface.hpp" -#include "clock_ctrl.hpp" +#include <uhd/types/serial.hpp> #include <uhd/types/ranges.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> @@ -38,13 +37,10 @@ public: /*! * Make a new clock control object. - * \param iface the usrp1 iface object + * \param iface the spi iface object * \param spi_slave which spi device - * \return the clock control object */ - static sptr make(usrp1_iface::sptr iface, - usrp1_clock_ctrl::sptr clock, int spi_slave - ); + static sptr make(uhd::spi_iface::sptr iface, int spi_slave); //! aux adc identifier constants enum aux_adc_t{ @@ -91,7 +87,7 @@ public: virtual double get_rx_pga_gain(char which) = 0; //! Set the TX modulator frequency - virtual void set_duc_freq(double freq) = 0; + virtual void set_duc_freq(double freq, double rate) = 0; //! Enable or disable the digital part of the DAC virtual void enable_tx_digital(bool enb) = 0; diff --git a/host/lib/usrp/usrp1/codec_impl.cpp b/host/lib/usrp/usrp1/codec_impl.cpp deleted file mode 100644 index 7e4032131..000000000 --- a/host/lib/usrp/usrp1/codec_impl.cpp +++ /dev/null @@ -1,159 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp1_impl.hpp" -#include <uhd/exception.hpp> -#include <uhd/usrp/codec_props.hpp> -#include <boost/bind.hpp> -#include <boost/foreach.hpp> -#include <boost/format.hpp> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Helper Methods - **********************************************************************/ -void usrp1_impl::codec_init(void) -{ - //make proxies - BOOST_FOREACH(dboard_slot_t dboard_slot, _dboard_slots){ - _rx_codec_proxies[dboard_slot] = wax_obj_proxy::make( - boost::bind(&usrp1_impl::rx_codec_get, this, _1, _2, dboard_slot), - boost::bind(&usrp1_impl::rx_codec_set, this, _1, _2, dboard_slot)); - - _tx_codec_proxies[dboard_slot] = wax_obj_proxy::make( - boost::bind(&usrp1_impl::tx_codec_get, this, _1, _2, dboard_slot), - boost::bind(&usrp1_impl::tx_codec_set, this, _1, _2, dboard_slot)); - } -} - -/*********************************************************************** - * RX Codec Properties - **********************************************************************/ -static const std::string adc_pga_gain_name = "PGA"; - -void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot) -{ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<codec_prop_t>()) { - case CODEC_PROP_NAME: - val = str(boost::format("usrp1 adc - ad9862 - slot %c") % char(dboard_slot)); - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - val = prop_names_t(1, adc_pga_gain_name); - return; - - case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(key.name == adc_pga_gain_name); - val = usrp1_codec_ctrl::rx_pga_gain_range; - return; - - case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(key.name == adc_pga_gain_name); - val = _codec_ctrls[dboard_slot]->get_rx_pga_gain('A'); - return; - - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == adc_pga_gain_name); - val = _codec_ctrls[dboard_slot]->get_rx_pga_gain('B'); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp1_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val, dboard_slot_t dboard_slot) -{ - named_prop_t key = named_prop_t::extract(key_); - - //handle the set request conditioned on the key - switch(key.as<codec_prop_t>()) { - case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(key.name == adc_pga_gain_name); - _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<double>(), 'A'); - return; - - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == adc_pga_gain_name); - _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<double>(), 'B'); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX Codec Properties - **********************************************************************/ -static const std::string dac_pga_gain_name = "PGA"; - -void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot) -{ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<codec_prop_t>()) { - case CODEC_PROP_NAME: - val = str(boost::format("usrp1 dac - ad9862 - slot %c") % char(dboard_slot)); - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - val = prop_names_t(1, dac_pga_gain_name); - return; - - case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(key.name == dac_pga_gain_name); - val = usrp1_codec_ctrl::tx_pga_gain_range; - return; - - case CODEC_PROP_GAIN_I: //only one gain for I and Q - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == dac_pga_gain_name); - val = _codec_ctrls[dboard_slot]->get_tx_pga_gain(); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp1_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val, dboard_slot_t dboard_slot) -{ - named_prop_t key = named_prop_t::extract(key_); - - //handle the set request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_GAIN_I: //only one gain for I and Q - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == dac_pga_gain_name); - _codec_ctrls[dboard_slot]->set_tx_pga_gain(val.as<double>()); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 3f3a98b7a..449ec64fe 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -20,7 +20,6 @@ #include "fpga_regs_common.h" #include "usrp_spi_defs.h" #include "fpga_regs_standard.h" -#include "clock_ctrl.hpp" #include "codec_ctrl.hpp" #include <uhd/usrp/dboard_iface.hpp> #include <uhd/types/dict.hpp> @@ -38,16 +37,16 @@ class usrp1_dboard_iface : public dboard_iface { public: usrp1_dboard_iface(usrp1_iface::sptr iface, - usrp1_clock_ctrl::sptr clock, usrp1_codec_ctrl::sptr codec, usrp1_impl::dboard_slot_t dboard_slot, + const double master_clock_rate, const dboard_id_t &rx_dboard_id ): _dboard_slot(dboard_slot), + _master_clock_rate(master_clock_rate), _rx_dboard_id(rx_dboard_id) { _iface = iface; - _clock = clock; _codec = codec; //init the clock rate shadows @@ -103,24 +102,24 @@ public: private: usrp1_iface::sptr _iface; - usrp1_clock_ctrl::sptr _clock; usrp1_codec_ctrl::sptr _codec; uhd::dict<unit_t, double> _clock_rates; const usrp1_impl::dboard_slot_t _dboard_slot; - const dboard_id_t &_rx_dboard_id; + const double _master_clock_rate; + const dboard_id_t _rx_dboard_id; }; /*********************************************************************** * Make Function **********************************************************************/ dboard_iface::sptr usrp1_impl::make_dboard_iface(usrp1_iface::sptr iface, - usrp1_clock_ctrl::sptr clock, usrp1_codec_ctrl::sptr codec, - dboard_slot_t dboard_slot, + usrp1_impl::dboard_slot_t dboard_slot, + const double master_clock_rate, const dboard_id_t &rx_dboard_id ){ return dboard_iface::sptr(new usrp1_dboard_iface( - iface, clock, codec, dboard_slot, rx_dboard_id + iface, codec, dboard_slot, master_clock_rate, rx_dboard_id )); } @@ -141,7 +140,7 @@ void usrp1_dboard_iface::set_clock_rate(unit_t unit, double rate) _clock_rates[unit] = rate; if (unit == UNIT_RX && _rx_dboard_id == dbsrx_classic_id){ - size_t divider = size_t(_clock->get_master_clock_freq()/rate); + size_t divider = size_t(_master_clock_rate/rate); switch(_dboard_slot){ case usrp1_impl::DBOARD_SLOT_A: _iface->poke32(FR_RX_A_REFCLK, (divider & 0x7f) | 0x80); @@ -159,10 +158,10 @@ std::vector<double> usrp1_dboard_iface::get_clock_rates(unit_t unit) std::vector<double> rates; if (unit == UNIT_RX && _rx_dboard_id == dbsrx_classic_id){ for (size_t div = 1; div <= 127; div++) - rates.push_back(_clock->get_master_clock_freq() / div); + rates.push_back(_master_clock_rate / div); } else{ - rates.push_back(_clock->get_master_clock_freq()); + rates.push_back(_master_clock_rate); } return rates; } @@ -178,7 +177,7 @@ void usrp1_dboard_iface::set_clock_enabled(unit_t, bool) } double usrp1_dboard_iface::get_codec_rate(unit_t){ - return _clock->get_master_clock_freq(); + return _master_clock_rate; } /*********************************************************************** diff --git a/host/lib/usrp/usrp1/dboard_impl.cpp b/host/lib/usrp/usrp1/dboard_impl.cpp deleted file mode 100644 index df0bb6261..000000000 --- a/host/lib/usrp/usrp1/dboard_impl.cpp +++ /dev/null @@ -1,218 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp1_impl.hpp" -#include "usrp_i2c_addr.h" -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/misc_utils.hpp> -#include <uhd/exception.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <boost/bind.hpp> -#include <boost/foreach.hpp> -#include <boost/format.hpp> -#include <iostream> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Helper Functions - **********************************************************************/ -static boost::uint8_t get_rx_ee_addr(usrp1_impl::dboard_slot_t dboard_slot){ - switch(dboard_slot){ - case usrp1_impl::DBOARD_SLOT_A: return I2C_ADDR_RX_A; - case usrp1_impl::DBOARD_SLOT_B: return I2C_ADDR_RX_B; - default: UHD_THROW_INVALID_CODE_PATH(); - } -} - -static boost::uint8_t get_tx_ee_addr(usrp1_impl::dboard_slot_t dboard_slot){ - switch(dboard_slot){ - case usrp1_impl::DBOARD_SLOT_A: return I2C_ADDR_TX_A; - case usrp1_impl::DBOARD_SLOT_B: return I2C_ADDR_TX_B; - default: UHD_THROW_INVALID_CODE_PATH(); - } -} - -/*********************************************************************** - * Dboard Initialization - **********************************************************************/ -void usrp1_impl::dboard_init(void) -{ - BOOST_FOREACH(dboard_slot_t dboard_slot, _dboard_slots){ - - //read the tx and rx dboard eeproms - _rx_db_eeproms[dboard_slot].load(*_iface, get_rx_ee_addr(dboard_slot)); - _tx_db_eeproms[dboard_slot].load(*_iface, get_tx_ee_addr(dboard_slot)); - _gdb_eeproms[dboard_slot].load(*_iface, get_tx_ee_addr(dboard_slot) ^ 5); - - //create a new dboard interface and manager - _dboard_ifaces[dboard_slot] = make_dboard_iface( - _iface, _clock_ctrl, _codec_ctrls[dboard_slot], - dboard_slot, _rx_db_eeproms[dboard_slot].id - ); - - _dboard_managers[dboard_slot] = dboard_manager::make( - _rx_db_eeproms[dboard_slot].id, - ((_gdb_eeproms[dboard_slot].id == dboard_id_t::none())? _tx_db_eeproms[dboard_slot] : _gdb_eeproms[dboard_slot]).id, - _dboard_ifaces[dboard_slot] - ); - - //setup the dboard proxies - _rx_dboard_proxies[dboard_slot] = wax_obj_proxy::make( - boost::bind(&usrp1_impl::rx_dboard_get, this, _1, _2, dboard_slot), - boost::bind(&usrp1_impl::rx_dboard_set, this, _1, _2, dboard_slot)); - - _tx_dboard_proxies[dboard_slot] = wax_obj_proxy::make( - boost::bind(&usrp1_impl::tx_dboard_get, this, _1, _2, dboard_slot), - boost::bind(&usrp1_impl::tx_dboard_set, this, _1, _2, dboard_slot)); - } - -} - -/*********************************************************************** - * RX Dboard Get - **********************************************************************/ -void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot) -{ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_NAME: - val = str(boost::format("usrp1 dboard (rx unit) - %c") % char(dboard_slot)); - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_managers[dboard_slot]->get_rx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_managers[dboard_slot]->get_rx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _rx_db_eeproms[dboard_slot]; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_ifaces[dboard_slot]; - return; - - case DBOARD_PROP_CODEC: - val = _rx_codec_proxies[dboard_slot]->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _rx_db_eeproms[dboard_slot].id, - _dboard_managers[dboard_slot]->get_rx_subdev(key.name), - _rx_codec_proxies[dboard_slot]->get_link(), - GAIN_GROUP_POLICY_RX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * RX Dboard Set - **********************************************************************/ -void usrp1_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val, dboard_slot_t dboard_slot) -{ - switch(key.as<dboard_prop_t>()) { - case DBOARD_PROP_DBOARD_EEPROM: - _rx_db_eeproms[dboard_slot] = val.as<dboard_eeprom_t>(); - _rx_db_eeproms[dboard_slot].store(*_iface, get_rx_ee_addr(dboard_slot)); - return; - - default: - UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX Dboard Get - **********************************************************************/ -void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot) -{ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_NAME: - val = str(boost::format("usrp1 dboard (tx unit) - %c") % char(dboard_slot)); - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_managers[dboard_slot]->get_tx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_managers[dboard_slot]->get_tx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _tx_db_eeproms[dboard_slot]; - return; - - case DBOARD_PROP_GBOARD_EEPROM: - val = _gdb_eeproms[dboard_slot]; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_ifaces[dboard_slot]; - return; - - case DBOARD_PROP_CODEC: - val = _tx_codec_proxies[dboard_slot]->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _tx_db_eeproms[dboard_slot].id, - _dboard_managers[dboard_slot]->get_tx_subdev(key.name), - _tx_codec_proxies[dboard_slot]->get_link(), - GAIN_GROUP_POLICY_TX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * TX Dboard Set - **********************************************************************/ -void usrp1_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val, dboard_slot_t dboard_slot) -{ - switch(key.as<dboard_prop_t>()) { - case DBOARD_PROP_DBOARD_EEPROM: - _tx_db_eeproms[dboard_slot] = val.as<dboard_eeprom_t>(); - _tx_db_eeproms[dboard_slot].store(*_iface, get_tx_ee_addr(dboard_slot)); - return; - - case DBOARD_PROP_GBOARD_EEPROM: - _gdb_eeproms[dboard_slot] = val.as<dboard_eeprom_t>(); - _gdb_eeproms[dboard_slot].store(*_iface, get_tx_ee_addr(dboard_slot) ^ 5); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp deleted file mode 100644 index 0bddc49f0..000000000 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ /dev/null @@ -1,222 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp1_impl.hpp" -#include "fpga_regs_standard.h" -#include <uhd/utils/msg.hpp> -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/dsp_props.hpp> -#include <boost/bind.hpp> -#include <boost/format.hpp> -#include <boost/lexical_cast.hpp> -#include <boost/assign/list_of.hpp> -#include <cmath> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * RX DDC Initialization - **********************************************************************/ -void usrp1_impl::rx_dsp_init(void) -{ - for (size_t i = 0; i < this->get_num_ddcs(); i++){ - _rx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( - boost::bind(&usrp1_impl::rx_dsp_get, this, _1, _2, i), - boost::bind(&usrp1_impl::rx_dsp_set, this, _1, _2, i) - ); - rx_dsp_set(DSP_PROP_HOST_RATE, _clock_ctrl->get_master_clock_freq() / 16, i); - } -} - -/*********************************************************************** - * RX DDC Get - **********************************************************************/ -void usrp1_impl::rx_dsp_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_NAME: - val = str(boost::format("usrp1 ddc%d %s") - % which_dsp - % (this->has_rx_halfband()? "+ hb" : "") - ); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); - return; - - case DSP_PROP_FREQ_SHIFT: - val = _rx_dsp_freqs[which_dsp]; - return; - - case DSP_PROP_CODEC_RATE: - val = _clock_ctrl->get_master_clock_freq(); - return; - - case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_master_clock_freq()/_rx_dsp_decim; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } - -} - -/*********************************************************************** - * RX DDC Set - **********************************************************************/ -void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()) { - case DSP_PROP_FREQ_SHIFT: { - double new_freq = val.as<double>(); - boost::uint32_t reg_word = dsp_type1::calc_cordic_word_and_update( - new_freq, _clock_ctrl->get_master_clock_freq()); - - static const boost::uint32_t dsp_index_to_reg_val[4] = { - FR_RX_FREQ_0, FR_RX_FREQ_1, FR_RX_FREQ_2, FR_RX_FREQ_3 - }; - _iface->poke32(dsp_index_to_reg_val[which_dsp], ~reg_word + 1); - _rx_dsp_freqs[which_dsp] = new_freq; - return; - } - - case DSP_PROP_HOST_RATE: - if (which_dsp != 0) return; //only for dsp[0] as this is vectorized - { - size_t rate = size_t(_clock_ctrl->get_master_clock_freq() / val.as<double>()); - - //clip the rate to something in range: - rate = std::min<size_t>(std::max<size_t>(rate, 4), 256); - - _rx_dsp_decim = rate; - //TODO Poll every 100ms. Make it selectable? - _rx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() / rate); - - bool s = this->disable_rx(); - _iface->poke32(FR_DECIM_RATE, _rx_dsp_decim/2 - 1); - this->restore_rx(s); - } - this->update_xport_channel_mapping(); //rate changed -> update - return; - - case DSP_PROP_STREAM_CMD: - if (which_dsp != 0) return; //only for dsp[0] as this is vectorized - _soft_time_ctrl->issue_stream_cmd(val.as<stream_cmd_t>()); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } - -} - -/*********************************************************************** - * TX DUC Initialization - **********************************************************************/ -void usrp1_impl::tx_dsp_init(void) -{ - for (size_t i = 0; i < this->get_num_ducs(); i++){ - _tx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( - boost::bind(&usrp1_impl::tx_dsp_get, this, _1, _2, i), - boost::bind(&usrp1_impl::tx_dsp_set, this, _1, _2, i) - ); - tx_dsp_set(DSP_PROP_HOST_RATE, _clock_ctrl->get_master_clock_freq() / 16, i); - } -} - -/*********************************************************************** - * TX DUC Get - **********************************************************************/ -void usrp1_impl::tx_dsp_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()) { - case DSP_PROP_NAME: - val = str(boost::format("usrp1 duc%d %s") - % which_dsp - % (this->has_tx_halfband()? "+ hb" : "") - ); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); //empty - return; - - case DSP_PROP_FREQ_SHIFT: - val = _tx_dsp_freqs[which_dsp]; - return; - - case DSP_PROP_CODEC_RATE: - val = _clock_ctrl->get_master_clock_freq(); - return; - - case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_master_clock_freq() / _tx_dsp_interp; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } - -} - -/*********************************************************************** - * TX DUC Set - **********************************************************************/ -void usrp1_impl::tx_dsp_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()) { - - case DSP_PROP_FREQ_SHIFT: { - double new_freq = val.as<double>(); - - //map the freq shift key to a subdev spec to a particular codec chip - std::string db_name = _tx_subdev_spec.at(which_dsp).db_name; - if (db_name == "A") _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq); - if (db_name == "B") _codec_ctrls[DBOARD_SLOT_B]->set_duc_freq(new_freq); - - _tx_dsp_freqs[which_dsp] = new_freq; - return; - } - - case DSP_PROP_HOST_RATE: - if (which_dsp != 0) return; //only for dsp[0] as this is vectorized - { - size_t rate = size_t(_clock_ctrl->get_master_clock_freq() / val.as<double>()); - - //clip the rate to something in range: - rate = std::min<size_t>(std::max<size_t>(rate, 4), 256); - - _tx_dsp_interp = rate; - - //TODO Poll every 100ms. Make it selectable? - _tx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() / rate); - - bool s = this->disable_tx(); - _iface->poke32(FR_INTERP_RATE, _tx_dsp_interp/2 - 1); - this->restore_tx(s); - } - this->update_xport_channel_mapping(); //rate changed -> update - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } - -} diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 90ed17cd8..e81b00d1c 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -15,26 +15,27 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include "validate_subdev_spec.hpp" #define SRPH_DONT_CHECK_SEQUENCE #include "../../transport/super_recv_packet_handler.hpp" #include "../../transport/super_send_packet_handler.hpp" +#include "usrp1_calc_mux.hpp" +#include "fpga_regs_standard.h" #include "usrp_commands.h" #include "usrp1_impl.hpp" #include <uhd/utils/msg.hpp> +#include <uhd/utils/tasks.hpp> #include <uhd/utils/safe_call.hpp> -#include <uhd/utils/thread_priority.hpp> -#include <uhd/usrp/dsp_props.hpp> #include <uhd/transport/bounded_buffer.hpp> +#include <boost/math/special_functions/sign.hpp> +#include <boost/math/special_functions/round.hpp> +#include <boost/thread/thread.hpp> #include <boost/bind.hpp> #include <boost/format.hpp> -#include <boost/asio.hpp> -#include <boost/bind.hpp> -#include <boost/thread.hpp> using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; -namespace asio = boost::asio; static const size_t alignment_padding = 512; @@ -124,8 +125,6 @@ static void usrp1_bs_vrt_unpacker( struct usrp1_impl::io_impl{ io_impl(zero_copy_if::sptr data_transport): data_transport(data_transport), - underflow_poll_samp_count(0), - overflow_poll_samp_count(0), curr_buff(offset_send_buffer(data_transport->get_send_buff())), omsb(boost::bind(&usrp1_impl::io_impl::commit_send_buff, this, _1, _2, _3)) { @@ -142,10 +141,6 @@ struct usrp1_impl::io_impl{ sph::recv_packet_handler recv_handler; sph::send_packet_handler send_handler; - //state management for overflow and underflow - size_t underflow_poll_samp_count; - size_t overflow_poll_samp_count; - //wrapper around the actual send buffer interface //all of this to ensure only aligned lengths are committed //NOTE: you must commit before getting a new buffer @@ -162,6 +157,9 @@ struct usrp1_impl::io_impl{ //make a new managed buffer with the offset buffs return omsb.get_new(curr_buff, next_buff); } + + task::sptr vandal_task; + boost::system_time last_send_time; }; /*! @@ -230,51 +228,219 @@ void usrp1_impl::io_init(void){ _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); - _soft_time_ctrl = soft_time_ctrl::make( - boost::bind(&usrp1_impl::rx_stream_on_off, this, _1) - ); - - this->enable_tx(true); //always enabled - rx_stream_on_off(false); - _io_impl->flush_send_buff(); - - //update mapping here since it didnt b4 when io init not called first - update_xport_channel_mapping(); -} - -void usrp1_impl::update_xport_channel_mapping(void){ - if (_io_impl.get() == NULL) return; //not inited yet + //create a new vandal thread to poll xerflow conditions + _io_impl->vandal_task = task::make(boost::bind( + &usrp1_impl::vandal_conquest_loop, this + )); - //set all of the relevant properties on the handler - boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); + //init some handler stuff + _io_impl->recv_handler.set_tick_rate(_master_clock_rate); _io_impl->recv_handler.set_vrt_unpacker(&usrp1_bs_vrt_unpacker); - _io_impl->recv_handler.set_tick_rate(_clock_ctrl->get_master_clock_freq()); - _io_impl->recv_handler.set_samp_rate(_rx_dsp_proxies[_rx_dsp_proxies.keys().at(0)]->get_link()[DSP_PROP_HOST_RATE].as<double>()); _io_impl->recv_handler.set_xport_chan_get_buff(0, boost::bind( &uhd::transport::zero_copy_if::get_recv_buff, _io_impl->data_transport, _1 )); - _io_impl->recv_handler.set_converter(_rx_otw_type, _rx_subdev_spec.size()); - - //set all of the relevant properties on the handler - boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); + _io_impl->send_handler.set_tick_rate(_master_clock_rate); _io_impl->send_handler.set_vrt_packer(&usrp1_bs_vrt_packer); - _io_impl->send_handler.set_tick_rate(_clock_ctrl->get_master_clock_freq()); - _io_impl->send_handler.set_samp_rate(_tx_dsp_proxies[_tx_dsp_proxies.keys().at(0)]->get_link()[DSP_PROP_HOST_RATE].as<double>()); _io_impl->send_handler.set_xport_chan_get_buff(0, boost::bind( &usrp1_impl::io_impl::get_send_buff, _io_impl.get(), _1 )); - _io_impl->send_handler.set_converter(_tx_otw_type, _tx_subdev_spec.size()); - _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); + + //init as disabled, then call the real function (uses restore) + this->enable_rx(false); + this->enable_tx(false); + rx_stream_on_off(false); + tx_stream_on_off(false); + _io_impl->flush_send_buff(); } void usrp1_impl::rx_stream_on_off(bool enb){ - this->enable_rx(enb); + this->restore_rx(enb); //drain any junk in the receive transport after stop streaming command while(not enb and _data_transport->get_recv_buff().get() != NULL){ /* NOP */ } } +void usrp1_impl::tx_stream_on_off(bool enb){ + _io_impl->last_send_time = boost::get_system_time(); + if (_tx_enabled and not enb) _io_impl->flush_send_buff(); + this->restore_tx(enb); +} + +/*! + * Casually poll the overflow and underflow registers. + * On an underflow, push an async message into the queue and print. + * On an overflow, interleave an inline message into recv and print. + * This procedure creates "soft" inline and async user messages. + */ +void usrp1_impl::vandal_conquest_loop(void){ + + //initialize the async metadata + async_metadata_t async_metadata; + async_metadata.channel = 0; + async_metadata.has_time_spec = true; + async_metadata.event_code = async_metadata_t::EVENT_CODE_UNDERFLOW; + + //initialize the inline metadata + rx_metadata_t inline_metadata; + inline_metadata.has_time_spec = true; + inline_metadata.error_code = rx_metadata_t::ERROR_CODE_OVERFLOW; + + //start the polling loop... + try{ while (not boost::this_thread::interruption_requested()){ + boost::uint8_t underflow = 0, overflow = 0; + + //shutoff transmit if it has been too long since send() was called + if (_tx_enabled and (boost::get_system_time() - _io_impl->last_send_time) > boost::posix_time::milliseconds(100)){ + this->tx_stream_on_off(false); + } + + //always poll regardless of enabled so we can clear the conditions + _fx2_ctrl->usrp_control_read( + VRQ_GET_STATUS, 0, GS_TX_UNDERRUN, &underflow, sizeof(underflow) + ); + _fx2_ctrl->usrp_control_read( + VRQ_GET_STATUS, 0, GS_RX_OVERRUN, &overflow, sizeof(overflow) + ); + + //handle message generation for xerflow conditions + if (_tx_enabled and underflow){ + async_metadata.time_spec = _soft_time_ctrl->get_time(); + _soft_time_ctrl->get_async_queue().push_with_pop_on_full(async_metadata); + UHD_MSG(fastpath) << "U"; + } + if (_rx_enabled and overflow){ + inline_metadata.time_spec = _soft_time_ctrl->get_time(); + _soft_time_ctrl->get_inline_queue().push_with_pop_on_full(inline_metadata); + UHD_MSG(fastpath) << "O"; + } + + boost::this_thread::sleep(boost::posix_time::milliseconds(50)); + }} + catch(const boost::thread_interrupted &){} //normal exit condition + catch(const std::exception &e){ + UHD_MSG(error) << "The vandal caught an unexpected exception " << e.what() << std::endl; + } +} + +/*********************************************************************** + * Properties callback methods below + **********************************************************************/ +void usrp1_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ + boost::mutex::scoped_lock lock = _io_impl->recv_handler.get_scoped_lock(); + + //sanity checking + validate_subdev_spec(_tree, spec, "rx"); + + _rx_subdev_spec = spec; //shadow + _io_impl->recv_handler.resize(spec.size()); + _io_impl->recv_handler.set_converter(_rx_otw_type, spec.size()); + + //set the mux and set the number of rx channels + std::vector<mapping_pair_t> mapping; + BOOST_FOREACH(const subdev_spec_pair_t &pair, spec){ + const std::string conn = _tree->access<std::string>(str(boost::format( + "/mboards/0/dboards/%s/rx_frontends/%s/connection" + ) % pair.db_name % pair.sd_name)).get(); + mapping.push_back(std::make_pair(pair.db_name, conn)); + } + bool s = this->disable_rx(); + _iface->poke32(FR_RX_MUX, calc_rx_mux(mapping)); + this->restore_rx(s); +} + +void usrp1_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ + boost::mutex::scoped_lock lock = _io_impl->send_handler.get_scoped_lock(); + + //sanity checking + validate_subdev_spec(_tree, spec, "tx"); + + _tx_subdev_spec = spec; //shadow + _io_impl->send_handler.resize(spec.size()); + _io_impl->send_handler.set_converter(_tx_otw_type, spec.size()); + + //set the mux and set the number of tx channels + std::vector<mapping_pair_t> mapping; + BOOST_FOREACH(const subdev_spec_pair_t &pair, spec){ + const std::string conn = _tree->access<std::string>(str(boost::format( + "/mboards/0/dboards/%s/tx_frontends/%s/connection" + ) % pair.db_name % pair.sd_name)).get(); + mapping.push_back(std::make_pair(pair.db_name, conn)); + } + bool s = this->disable_tx(); + _iface->poke32(FR_TX_MUX, calc_tx_mux(mapping)); + this->restore_tx(s); + + //if the spec changes size, so does the max samples per packet... + _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); +} + +double usrp1_impl::update_rx_samp_rate(const double samp_rate){ + boost::mutex::scoped_lock lock = _io_impl->recv_handler.get_scoped_lock(); + + const size_t rate = uhd::clip<size_t>( + boost::math::iround(_master_clock_rate / samp_rate), size_t(std::ceil(_master_clock_rate / 8e6)), 256 + ); + + bool s = this->disable_rx(); + _iface->poke32(FR_DECIM_RATE, rate/2 - 1); + this->restore_rx(s); + + _io_impl->recv_handler.set_samp_rate(_master_clock_rate / rate); + return _master_clock_rate / rate; +} + +double usrp1_impl::update_tx_samp_rate(const double samp_rate){ + boost::mutex::scoped_lock lock = _io_impl->send_handler.get_scoped_lock(); + + const size_t rate = uhd::clip<size_t>( + boost::math::iround(_master_clock_rate / samp_rate), size_t(std::ceil(_master_clock_rate / 8e6)), 256 + ); + + bool s = this->disable_tx(); + _iface->poke32(FR_INTERP_RATE, rate/2 - 1); + this->restore_tx(s); + + _io_impl->send_handler.set_samp_rate(_master_clock_rate / rate); + return _master_clock_rate / rate; +} + +double usrp1_impl::update_rx_dsp_freq(const size_t dspno, const double freq_){ + + //correct for outside of rate (wrap around) + double freq = std::fmod(freq_, _master_clock_rate); + if (std::abs(freq) > _master_clock_rate/2.0) + freq -= boost::math::sign(freq)*_master_clock_rate; + + //calculate the freq register word (signed) + UHD_ASSERT_THROW(std::abs(freq) <= _master_clock_rate/2.0); + static const double scale_factor = std::pow(2.0, 32); + const boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / _master_clock_rate) * scale_factor)); + + static const boost::uint32_t dsp_index_to_reg_val[4] = { + FR_RX_FREQ_0, FR_RX_FREQ_1, FR_RX_FREQ_2, FR_RX_FREQ_3 + }; + _iface->poke32(dsp_index_to_reg_val[dspno], ~freq_word + 1); + + return (double(freq_word) / scale_factor) * _master_clock_rate; +} + +double usrp1_impl::update_tx_dsp_freq(const size_t dspno, const double freq){ + //map the freq shift key to a subdev spec to a particular codec chip + _dbc[_tx_subdev_spec.at(dspno).db_name].codec->set_duc_freq(freq, _master_clock_rate); + return freq; //assume infinite precision +} + +/*********************************************************************** + * Async Data + **********************************************************************/ +bool usrp1_impl::recv_async_msg( + async_metadata_t &async_metadata, double timeout +){ + boost::this_thread::disable_interruption di; //disable because the wait can throw + return _soft_time_ctrl->get_async_queue().pop_with_timed_wait(async_metadata, timeout); +} + /*********************************************************************** * Data send + helper functions **********************************************************************/ @@ -292,29 +458,23 @@ size_t usrp1_impl::send( ){ if (_soft_time_ctrl->send_pre(metadata, timeout)) return 0; + this->tx_stream_on_off(true); //always enable (it will do the right thing) size_t num_samps_sent = _io_impl->send_handler.send( buffs, nsamps_per_buff, metadata, io_type, send_mode, timeout ); - //handle eob flag (commit the buffer, disable the DACs) + //handle eob flag (commit the buffer, /*disable the DACs*/) //check num samps sent to avoid flush on incomplete/timeout if (metadata.end_of_burst and num_samps_sent == nsamps_per_buff){ - _io_impl->flush_send_buff(); - } - - //handle the polling for underflow conditions - _io_impl->underflow_poll_samp_count += num_samps_sent; - if (_io_impl->underflow_poll_samp_count >= _tx_samps_per_poll_interval){ - _io_impl->underflow_poll_samp_count = 0; //reset count - boost::uint8_t underflow = 0; - ssize_t ret = _ctrl_transport->usrp_control_read( - VRQ_GET_STATUS, 0, GS_TX_UNDERRUN, - &underflow, sizeof(underflow) - ); - if (ret < 0) UHD_MSG(error) << "USRP: underflow check failed" << std::endl; - else if (underflow) UHD_MSG(fastpath) << "U"; + async_metadata_t metadata; + metadata.channel = 0; + metadata.has_time_spec = true; + metadata.time_spec = _soft_time_ctrl->get_time(); + metadata.event_code = async_metadata_t::EVENT_CODE_BURST_ACK; + _soft_time_ctrl->get_async_queue().push_with_pop_on_full(metadata); + this->tx_stream_on_off(false); } return num_samps_sent; @@ -335,26 +495,14 @@ size_t usrp1_impl::recv( rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode, double timeout ){ + //interleave a "soft" inline message into the receive stream: + if (_soft_time_ctrl->get_inline_queue().pop_with_haste(metadata)) return 0; + size_t num_samps_recvd = _io_impl->recv_handler.recv( buffs, nsamps_per_buff, metadata, io_type, recv_mode, timeout ); - _soft_time_ctrl->recv_post(metadata, num_samps_recvd); - - //handle the polling for overflow conditions - _io_impl->overflow_poll_samp_count += num_samps_recvd; - if (_io_impl->overflow_poll_samp_count >= _rx_samps_per_poll_interval){ - _io_impl->overflow_poll_samp_count = 0; //reset count - boost::uint8_t overflow = 0; - ssize_t ret = _ctrl_transport->usrp_control_read( - VRQ_GET_STATUS, 0, GS_RX_OVERRUN, - &overflow, sizeof(overflow) - ); - if (ret < 0) UHD_MSG(error) << "USRP: overflow check failed" << std::endl; - else if (overflow) UHD_MSG(fastpath) << "O"; - } - - return num_samps_recvd; + return _soft_time_ctrl->recv_post(metadata, num_samps_recvd); } diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp deleted file mode 100644 index a265a5089..000000000 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ /dev/null @@ -1,407 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp1_impl.hpp" -#include "usrp_commands.h" -#include "fpga_regs_standard.h" -#include "fpga_regs_common.h" -#include "usrp_i2c_addr.h" -#include <uhd/utils/msg.hpp> -#include <uhd/utils/log.hpp> -#include <uhd/usrp/misc_utils.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/utils/msg.hpp> -#include <uhd/utils/assert_has.hpp> -#include <uhd/utils/images.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/foreach.hpp> -#include <boost/bind.hpp> -#include <boost/thread/thread.hpp> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Calculate the RX mux value: - * The I and Q mux values are intentionally reversed to flip I and Q - * to account for the reversal in the type conversion routines. - **********************************************************************/ -static int calc_rx_mux_pair(int adc_for_i, int adc_for_q){ - return (adc_for_i << 2) | (adc_for_q << 0); //shift reversal here -} - -/*! - * 3 2 1 0 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-----------------------+-------+-------+-------+-------+-+-----+ - * | must be zero | Q3| I3| Q2| I2| Q1| I1| Q0| I0|Z| NCH | - * +-----------------------+-------+-------+-------+-------+-+-----+ - */ -static boost::uint32_t calc_rx_mux( - const subdev_spec_t &subdev_spec, wax::obj mboard -){ - //create look-up-table for mapping dboard name and connection type to ADC flags - static const int ADC0 = 0, ADC1 = 1, ADC2 = 2, ADC3 = 3; - static const uhd::dict<std::string, uhd::dict<subdev_conn_t, int> > name_to_conn_to_flag = boost::assign::map_list_of - ("A", boost::assign::map_list_of - (SUBDEV_CONN_COMPLEX_IQ, calc_rx_mux_pair(ADC0, ADC1)) //I and Q - (SUBDEV_CONN_COMPLEX_QI, calc_rx_mux_pair(ADC1, ADC0)) //I and Q - (SUBDEV_CONN_REAL_I, calc_rx_mux_pair(ADC0, ADC0)) //I and Q (Q identical but ignored Z=1) - (SUBDEV_CONN_REAL_Q, calc_rx_mux_pair(ADC1, ADC1)) //I and Q (Q identical but ignored Z=1) - ) - ("B", boost::assign::map_list_of - (SUBDEV_CONN_COMPLEX_IQ, calc_rx_mux_pair(ADC2, ADC3)) //I and Q - (SUBDEV_CONN_COMPLEX_QI, calc_rx_mux_pair(ADC3, ADC2)) //I and Q - (SUBDEV_CONN_REAL_I, calc_rx_mux_pair(ADC2, ADC2)) //I and Q (Q identical but ignored Z=1) - (SUBDEV_CONN_REAL_Q, calc_rx_mux_pair(ADC3, ADC3)) //I and Q (Q identical but ignored Z=1) - ) - ; - - //extract the number of channels - size_t nchan = subdev_spec.size(); - - //calculate the channel flags - int channel_flags = 0; - size_t num_reals = 0, num_quads = 0; - BOOST_FOREACH(const subdev_spec_pair_t &pair, uhd::reversed(subdev_spec)){ - wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_RX_DBOARD, pair.db_name)]; - wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)]; - subdev_conn_t conn = subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>(); - switch(conn){ - case SUBDEV_CONN_COMPLEX_IQ: - case SUBDEV_CONN_COMPLEX_QI: num_quads++; break; - case SUBDEV_CONN_REAL_I: - case SUBDEV_CONN_REAL_Q: num_reals++; break; - } - channel_flags = (channel_flags << 4) | name_to_conn_to_flag[pair.db_name][conn]; - } - - //calculate Z: - // for all real sources: Z = 1 - // for all quadrature sources: Z = 0 - // for mixed sources: warning + Z = 0 - int Z = (num_quads > 0)? 0 : 1; - if (num_quads != 0 and num_reals != 0) UHD_MSG(warning) << boost::format( - "Mixing real and quadrature rx subdevices is not supported.\n" - "The Q input to the real source(s) will be non-zero.\n" - ); - - //calculate the rx mux value - return ((channel_flags & 0xffff) << 4) | ((Z & 0x1) << 3) | ((nchan & 0x7) << 0); -} - -/*********************************************************************** - * Calculate the TX mux value: - * The I and Q mux values are intentionally reversed to flip I and Q - * to account for the reversal in the type conversion routines. - **********************************************************************/ -static int calc_tx_mux_pair(int chn_for_i, int chn_for_q){ - return (chn_for_i << 4) | (chn_for_q << 0); //shift reversal here -} - -/*! - * 3 2 1 0 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-----------------------+-------+-------+-------+-------+-+-----+ - * | | DAC1Q | DAC1I | DAC0Q | DAC0I |0| NCH | - * +-----------------------------------------------+-------+-+-----+ - */ -static boost::uint32_t calc_tx_mux( - const subdev_spec_t &subdev_spec, wax::obj mboard -){ - //create look-up-table for mapping channel number and connection type to flags - static const int ENB = 1 << 3, CHAN_I0 = 0, CHAN_Q0 = 1, CHAN_I1 = 2, CHAN_Q1 = 3; - static const uhd::dict<size_t, uhd::dict<subdev_conn_t, int> > chan_to_conn_to_flag = boost::assign::map_list_of - (0, boost::assign::map_list_of - (SUBDEV_CONN_COMPLEX_IQ, calc_tx_mux_pair(CHAN_I0 | ENB, CHAN_Q0 | ENB)) - (SUBDEV_CONN_COMPLEX_QI, calc_tx_mux_pair(CHAN_Q0 | ENB, CHAN_I0 | ENB)) - (SUBDEV_CONN_REAL_I, calc_tx_mux_pair(CHAN_I0 | ENB, 0 )) - (SUBDEV_CONN_REAL_Q, calc_tx_mux_pair(0, CHAN_I0 | ENB)) - ) - (1, boost::assign::map_list_of - (SUBDEV_CONN_COMPLEX_IQ, calc_tx_mux_pair(CHAN_I1 | ENB, CHAN_Q1 | ENB)) - (SUBDEV_CONN_COMPLEX_QI, calc_tx_mux_pair(CHAN_Q1 | ENB, CHAN_I1 | ENB)) - (SUBDEV_CONN_REAL_I, calc_tx_mux_pair(CHAN_I1 | ENB, 0 )) - (SUBDEV_CONN_REAL_Q, calc_tx_mux_pair(0, CHAN_I1 | ENB)) - ) - ; - - //extract the number of channels - size_t nchan = subdev_spec.size(); - - //calculate the channel flags - int channel_flags = 0, chan = 0; - uhd::dict<std::string, int> slot_to_chan_count = boost::assign::map_list_of("A", 0)("B", 0); - BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){ - wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_TX_DBOARD, pair.db_name)]; - wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)]; - subdev_conn_t conn = subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>(); - - //combine the channel flags: shift for slot A vs B - if (pair.db_name == "A") channel_flags |= chan_to_conn_to_flag[chan][conn] << 0; - if (pair.db_name == "B") channel_flags |= chan_to_conn_to_flag[chan][conn] << 8; - - //sanity check, only 1 channel per slot - slot_to_chan_count[pair.db_name]++; - if (slot_to_chan_count[pair.db_name] > 1){ - throw uhd::value_error(str(boost::format( - "dboard slot %s assigned to multiple channels in subdev spec %s" - ) % pair.db_name % subdev_spec.to_string())); - } - - //increment for the next channel - chan++; - } - - //calculate the tx mux value - return ((channel_flags & 0xffff) << 4) | ((nchan & 0x7) << 0); -} - -/*! - * Capabilities Register - * - * 3 2 1 0 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-----------------------------------------------+-+-----+-+-----+ - * | Reserved |T|DUCs |R|DDCs | - * +-----------------------------------------------+-+-----+-+-----+ - */ -size_t usrp1_impl::get_num_ddcs(void){ - boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); - return (regval >> 0) & 0x0007; -} - -size_t usrp1_impl::get_num_ducs(void){ - boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); - return (regval >> 4) & 0x0007; -} - -bool usrp1_impl::has_rx_halfband(void){ - boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); - return (regval >> 3) & 0x0001; -} - -bool usrp1_impl::has_tx_halfband(void){ - boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); - return (regval >> 7) & 0x0001; -} - -/*********************************************************************** - * Mboard Initialization - **********************************************************************/ -void usrp1_impl::mboard_init(void) -{ - _mboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp1_impl::mboard_get, this, _1, _2), - boost::bind(&usrp1_impl::mboard_set, this, _1, _2)); - - // Normal mode with no loopback or Rx counting - _iface->poke32(FR_MODE, 0x00000000); - _iface->poke32(FR_DEBUG_EN, 0x00000000); - _iface->poke32(FR_RX_SAMPLE_RATE_DIV, 0x00000001); //divide by 2 - _iface->poke32(FR_TX_SAMPLE_RATE_DIV, 0x00000001); //divide by 2 - _iface->poke32(FR_DC_OFFSET_CL_EN, 0x0000000f); - - // Reset offset correction registers - _iface->poke32(FR_ADC_OFFSET_0, 0x00000000); - _iface->poke32(FR_ADC_OFFSET_1, 0x00000000); - _iface->poke32(FR_ADC_OFFSET_2, 0x00000000); - _iface->poke32(FR_ADC_OFFSET_3, 0x00000000); - - // Set default for RX format to 16-bit I&Q and no half-band filter bypass - _iface->poke32(FR_RX_FORMAT, 0x00000300); - - // Set default for TX format to 16-bit I&Q - _iface->poke32(FR_TX_FORMAT, 0x00000000); - - UHD_LOG - << "USRP1 Capabilities" << std::endl - << " number of duc's: " << get_num_ddcs() << std::endl - << " number of ddc's: " << get_num_ducs() << std::endl - << " rx halfband: " << has_rx_halfband() << std::endl - << " tx halfband: " << has_tx_halfband() << std::endl - ; -} - -/*********************************************************************** - * Mboard Get - **********************************************************************/ -static prop_names_t dboard_names = boost::assign::list_of("A")("B"); - -void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) -{ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<mboard_prop_t>()){ - case MBOARD_PROP_NAME: - val = std::string("usrp1 mboard - " + _iface->mb_eeprom["serial"]); - return; - - case MBOARD_PROP_OTHERS: - val = prop_names_t(); - return; - - case MBOARD_PROP_RX_DBOARD: - uhd::assert_has(dboard_names, key.name, "dboard name"); - if (key.name == "A") val = _rx_dboard_proxies[DBOARD_SLOT_A]->get_link(); - if (key.name == "B") val = _rx_dboard_proxies[DBOARD_SLOT_B]->get_link(); - return; - - case MBOARD_PROP_RX_DBOARD_NAMES: - val = dboard_names; - return; - - case MBOARD_PROP_TX_DBOARD: - uhd::assert_has(dboard_names, key.name, "dboard name"); - if (key.name == "A") val = _tx_dboard_proxies[DBOARD_SLOT_A]->get_link(); - if (key.name == "B") val = _tx_dboard_proxies[DBOARD_SLOT_B]->get_link(); - return; - - case MBOARD_PROP_TX_DBOARD_NAMES: - val = dboard_names; - return; - - case MBOARD_PROP_RX_DSP: - val = _rx_dsp_proxies.get(key.name)->get_link(); - return; - - case MBOARD_PROP_RX_DSP_NAMES: - val = _rx_dsp_proxies.keys(); - return; - - case MBOARD_PROP_TX_DSP: - val = _tx_dsp_proxies.get(key.name)->get_link(); - return; - - case MBOARD_PROP_TX_DSP_NAMES: - val = _tx_dsp_proxies.keys(); - return; - - case MBOARD_PROP_CLOCK_CONFIG: - val = clock_config_t::internal(); - return; - - case MBOARD_PROP_RX_SUBDEV_SPEC: - val = _rx_subdev_spec; - return; - - case MBOARD_PROP_TX_SUBDEV_SPEC: - val = _tx_subdev_spec; - return; - - case MBOARD_PROP_EEPROM_MAP: - val = _iface->mb_eeprom; - return; - - case MBOARD_PROP_TIME_NOW: - val = _soft_time_ctrl->get_time(); - return; - - case MBOARD_PROP_CLOCK_RATE: - val = _clock_ctrl->get_master_clock_freq(); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * Mboard Set - **********************************************************************/ -void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) -{ - if(key.type() == typeid(std::string)) { - if(key.as<std::string>() == "load_eeprom") { - std::string usrp1_eeprom_image = val.as<std::string>(); - UHD_MSG(status) << "USRP1 EEPROM image: " << usrp1_eeprom_image << std::endl; - _ctrl_transport->usrp_load_eeprom(val.as<std::string>()); - } - return; - } - - //handle the get request conditioned on the key - switch(key.as<mboard_prop_t>()){ - - case MBOARD_PROP_RX_SUBDEV_SPEC:{ - _rx_subdev_spec = val.as<subdev_spec_t>(); - if (_rx_subdev_spec.size() > this->get_num_ddcs()){ - throw uhd::value_error(str(boost::format( - "USRP1 suports up to %u RX channels.\n" - "However, this RX subdev spec requires %u channels\n" - ) % this->get_num_ddcs() % _rx_subdev_spec.size())); - } - verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link()); - //set the mux and set the number of rx channels - bool s = this->disable_rx(); - _iface->poke32(FR_RX_MUX, calc_rx_mux(_rx_subdev_spec, _mboard_proxy->get_link())); - this->restore_rx(s); - this->update_xport_channel_mapping(); - }return; - - case MBOARD_PROP_TX_SUBDEV_SPEC:{ - _tx_subdev_spec = val.as<subdev_spec_t>(); - if (_tx_subdev_spec.size() > this->get_num_ducs()){ - throw uhd::value_error(str(boost::format( - "USRP1 suports up to %u TX channels.\n" - "However, this TX subdev spec requires %u channels\n" - ) % this->get_num_ducs() % _tx_subdev_spec.size())); - } - verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link()); - //set the mux and set the number of tx channels - bool s = this->disable_tx(); - _iface->poke32(FR_TX_MUX, calc_tx_mux(_tx_subdev_spec, _mboard_proxy->get_link())); - this->restore_tx(s); - this->update_xport_channel_mapping(); - }return; - - case MBOARD_PROP_EEPROM_MAP: - // Step1: commit the map, writing only those values set. - // Step2: readback the entire eeprom map into the iface. - val.as<mboard_eeprom_t>().commit(*_iface, mboard_eeprom_t::MAP_B000); - _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_B000); - return; - - case MBOARD_PROP_TIME_NOW: - _soft_time_ctrl->set_time(val.as<time_spec_t>()); - return; - - case MBOARD_PROP_CLOCK_RATE: - UHD_MSG(warning) - << "I see that you are setting the master clock rate from the API.\n" - << "You may find it more convenient to burn this setting into the EEPROM.\n" - << "See the application notes for USRP1 for further instructions.\n" - ; - _clock_ctrl->set_master_clock_freq(val.as<double>()); - this->update_xport_channel_mapping(); - return; - - case MBOARD_PROP_CLOCK_CONFIG:{ - clock_config_t clock_config = val.as<clock_config_t>(); - if (clock_config.ref_source != clock_config_t::REF_INT){ - throw uhd::value_error("USRP1 clock config: reference source must be set to internal"); - } - if (clock_config.pps_source != clock_config_t::PPS_INT){ - throw uhd::value_error("USRP1 clock config: PPS source must be set to internal"); - } - }return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.cpp b/host/lib/usrp/usrp1/soft_time_ctrl.cpp index 1bab34e7b..78481c3ff 100644 --- a/host/lib/usrp/usrp1/soft_time_ctrl.cpp +++ b/host/lib/usrp/usrp1/soft_time_ctrl.cpp @@ -16,10 +16,8 @@ // #include "soft_time_ctrl.hpp" -#include <uhd/transport/bounded_buffer.hpp> -#include <boost/any.hpp> -#include <boost/thread/thread.hpp> -#include <boost/thread/barrier.hpp> +#include <uhd/utils/tasks.hpp> +#include <boost/make_shared.hpp> #include <boost/thread/condition_variable.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <iostream> @@ -41,24 +39,17 @@ public: _nsamps_remaining(0), _stream_mode(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS), _cmd_queue(2), + _async_msg_queue(100), + _inline_msg_queue(100), _stream_on_off(stream_on_off) { //synchronously spawn a new thread - boost::barrier spawn_barrier(2); - _thread_group.create_thread(boost::bind( - &soft_time_ctrl_impl::recv_cmd_dispatcher, this, boost::ref(spawn_barrier)) - ); - spawn_barrier.wait(); + _recv_cmd_task = task::make(boost::bind(&soft_time_ctrl_impl::recv_cmd_task, this)); //initialize the time to something this->set_time(time_spec_t(0.0)); } - ~soft_time_ctrl_impl(void){ - _thread_group.interrupt_all(); - _thread_group.join_all(); - } - /******************************************************************* * Time control ******************************************************************/ @@ -89,32 +80,47 @@ public: /******************************************************************* * Receive control ******************************************************************/ - void recv_post(rx_metadata_t &md, size_t &nsamps){ + size_t recv_post(rx_metadata_t &md, const size_t nsamps){ boost::mutex::scoped_lock lock(_update_mutex); + //Since it timed out on the receive, check for inline messages... + //Must do a post check because recv() will not wake up for a message. + if (md.error_code == rx_metadata_t::ERROR_CODE_TIMEOUT){ + if (_inline_msg_queue.pop_with_haste(md)) return 0; + } + //load the metadata with the expected time md.has_time_spec = true; md.time_spec = time_now(); //none of the stuff below matters in continuous streaming mode - if (_stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) return; + if (_stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) return nsamps; //When to stop streaming: //The samples have been received and the stream mode is non-continuous. //Rewrite the sample count to clip to the requested number of samples. - if (_nsamps_remaining <= nsamps){ - nsamps = _nsamps_remaining; //set nsamps, then stop + if (_nsamps_remaining <= nsamps) switch(_stream_mode){ + case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE:{ + rx_metadata_t metadata; + metadata.has_time_spec = true; + metadata.time_spec = this->time_now(); + metadata.error_code = rx_metadata_t::ERROR_CODE_BROKEN_CHAIN; + _inline_msg_queue.push_with_pop_on_full(metadata); + } //continue to next case... + case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE: md.end_of_burst = true; - stream_on_off(false); - return; + this->issue_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); + return _nsamps_remaining; + default: break; } //update the consumed samples _nsamps_remaining -= nsamps; + return nsamps; } void issue_stream_cmd(const stream_cmd_t &cmd){ - _cmd_queue.push_with_wait(cmd); + _cmd_queue.push_with_wait(boost::make_shared<stream_cmd_t>(cmd)); } void stream_on_off(bool enb){ @@ -134,7 +140,12 @@ public: //handle late packets if (time_at < time_now()){ - //TODO post async message + async_metadata_t metadata; + metadata.channel = 0; + metadata.has_time_spec = true; + metadata.time_spec = this->time_now(); + metadata.event_code = async_metadata_t::EVENT_CODE_TIME_ERROR; + _async_msg_queue.push_with_pop_on_full(metadata); return true; } @@ -153,7 +164,13 @@ public: if (not cmd.stream_now){ time_spec_t time_at(cmd.time_spec - TWIDDLE); if (time_at < time_now()){ - //TODO inject late cmd inline error + rx_metadata_t metadata; + metadata.has_time_spec = true; + metadata.time_spec = this->time_now(); + metadata.error_code = rx_metadata_t::ERROR_CODE_LATE_COMMAND; + _inline_msg_queue.push_with_pop_on_full(metadata); + this->issue_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); + return; } else{ sleep_until_time(lock, time_at); @@ -177,15 +194,18 @@ public: _stream_mode = cmd.stream_mode; } - void recv_cmd_dispatcher(boost::barrier &spawn_barrier){ - spawn_barrier.wait(); - try{ - boost::any cmd; - while (true){ - _cmd_queue.pop_with_wait(cmd); - recv_cmd_handle_cmd(boost::any_cast<stream_cmd_t>(cmd)); - } - } catch(const boost::thread_interrupted &){} + void recv_cmd_task(void){ //task is looped + boost::shared_ptr<stream_cmd_t> cmd; + _cmd_queue.pop_with_wait(cmd); + recv_cmd_handle_cmd(*cmd); + } + + bounded_buffer<async_metadata_t> &get_async_queue(void){ + return _async_msg_queue; + } + + bounded_buffer<rx_metadata_t> &get_inline_queue(void){ + return _inline_msg_queue; } private: @@ -193,9 +213,11 @@ private: size_t _nsamps_remaining; stream_cmd_t::stream_mode_t _stream_mode; time_spec_t _time_offset; - bounded_buffer<boost::any> _cmd_queue; + bounded_buffer<boost::shared_ptr<stream_cmd_t> > _cmd_queue; + bounded_buffer<async_metadata_t> _async_msg_queue; + bounded_buffer<rx_metadata_t> _inline_msg_queue; const cb_fcn_type _stream_on_off; - boost::thread_group _thread_group; + task::sptr _recv_cmd_task; }; /*********************************************************************** diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.hpp b/host/lib/usrp/usrp1/soft_time_ctrl.hpp index 7fdac7fc8..e91aaf6a2 100644 --- a/host/lib/usrp/usrp1/soft_time_ctrl.hpp +++ b/host/lib/usrp/usrp1/soft_time_ctrl.hpp @@ -21,6 +21,7 @@ #include <uhd/types/stream_cmd.hpp> #include <uhd/types/time_spec.hpp> #include <uhd/types/metadata.hpp> +#include <uhd/transport/bounded_buffer.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> #include <boost/function.hpp> @@ -45,8 +46,6 @@ public: * \return a new soft time control object */ static sptr make(const cb_fcn_type &stream_on_off); - //TODO pass in the error queue for async msgs - //TODO pass in the queue for inline msgs //! Set the current time virtual void set_time(const time_spec_t &time) = 0; @@ -55,13 +54,19 @@ public: virtual time_spec_t get_time(void) = 0; //! Call after the internal recv function - virtual void recv_post(rx_metadata_t &md, size_t &nsamps) = 0; + virtual size_t recv_post(rx_metadata_t &md, const size_t nsamps) = 0; //! Call before the internal send function virtual bool send_pre(const tx_metadata_t &md, double &timeout) = 0; //! Issue a stream command to receive virtual void issue_stream_cmd(const stream_cmd_t &cmd) = 0; + + //! Get access to a buffer of async metadata + virtual transport::bounded_buffer<async_metadata_t> &get_async_queue(void) = 0; + + //! Get access to a buffer of inline metadata + virtual transport::bounded_buffer<rx_metadata_t> &get_inline_queue(void) = 0; }; }} //namespace diff --git a/host/lib/usrp/usrp1/usrp1_calc_mux.hpp b/host/lib/usrp/usrp1/usrp1_calc_mux.hpp new file mode 100644 index 000000000..31c190db0 --- /dev/null +++ b/host/lib/usrp/usrp1/usrp1_calc_mux.hpp @@ -0,0 +1,156 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/config.hpp> +#include <uhd/exception.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/utils/algorithm.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/format.hpp> +#include <utility> +#include <vector> +#include <string> + +#ifndef INCLUDED_USRP1_CALC_MUX_HPP +#define INCLUDED_USRP1_CALC_MUX_HPP + +//db_name, conn_type for the mux calculations below... +typedef std::pair<std::string, std::string> mapping_pair_t; + +/*********************************************************************** + * Calculate the RX mux value: + * The I and Q mux values are intentionally reversed to flip I and Q + * to account for the reversal in the type conversion routines. + **********************************************************************/ +static int calc_rx_mux_pair(int adc_for_i, int adc_for_q){ + return (adc_for_i << 2) | (adc_for_q << 0); //shift reversal here +} + +/*! + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------------------+-------+-------+-------+-------+-+-----+ + * | must be zero | Q3| I3| Q2| I2| Q1| I1| Q0| I0|Z| NCH | + * +-----------------------+-------+-------+-------+-------+-+-----+ + */ +static boost::uint32_t calc_rx_mux(const std::vector<mapping_pair_t> &mapping){ + //create look-up-table for mapping dboard name and connection type to ADC flags + static const int ADC0 = 0, ADC1 = 1, ADC2 = 2, ADC3 = 3; + static const uhd::dict<std::string, uhd::dict<std::string, int> > name_to_conn_to_flag = boost::assign::map_list_of + ("A", boost::assign::map_list_of + ("IQ", calc_rx_mux_pair(ADC0, ADC1)) //I and Q + ("QI", calc_rx_mux_pair(ADC1, ADC0)) //I and Q + ("I", calc_rx_mux_pair(ADC0, ADC0)) //I and Q (Q identical but ignored Z=1) + ("Q", calc_rx_mux_pair(ADC1, ADC1)) //I and Q (Q identical but ignored Z=1) + ) + ("B", boost::assign::map_list_of + ("IQ", calc_rx_mux_pair(ADC2, ADC3)) //I and Q + ("QI", calc_rx_mux_pair(ADC3, ADC2)) //I and Q + ("I", calc_rx_mux_pair(ADC2, ADC2)) //I and Q (Q identical but ignored Z=1) + ("Q", calc_rx_mux_pair(ADC3, ADC3)) //I and Q (Q identical but ignored Z=1) + ) + ; + + //extract the number of channels + const size_t nchan = mapping.size(); + + //calculate the channel flags + int channel_flags = 0; + size_t num_reals = 0, num_quads = 0; + BOOST_FOREACH(const mapping_pair_t &pair, uhd::reversed(mapping)){ + const std::string name = pair.first, conn = pair.second; + if (conn == "IQ" or conn == "QI") num_quads++; + if (conn == "I" or conn == "Q") num_reals++; + channel_flags = (channel_flags << 4) | name_to_conn_to_flag[name][conn]; + } + + //calculate Z: + // for all real sources: Z = 1 + // for all quadrature sources: Z = 0 + // for mixed sources: warning + Z = 0 + int Z = (num_quads > 0)? 0 : 1; + if (num_quads != 0 and num_reals != 0) UHD_MSG(warning) << boost::format( + "Mixing real and quadrature rx subdevices is not supported.\n" + "The Q input to the real source(s) will be non-zero.\n" + ); + + //calculate the rx mux value + return ((channel_flags & 0xffff) << 4) | ((Z & 0x1) << 3) | ((nchan & 0x7) << 0); +} + +/*********************************************************************** + * Calculate the TX mux value: + * The I and Q mux values are intentionally reversed to flip I and Q + * to account for the reversal in the type conversion routines. + **********************************************************************/ +static int calc_tx_mux_pair(int chn_for_i, int chn_for_q){ + return (chn_for_i << 4) | (chn_for_q << 0); //shift reversal here +} + +/*! + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------------------+-------+-------+-------+-------+-+-----+ + * | | DAC1Q | DAC1I | DAC0Q | DAC0I |0| NCH | + * +-----------------------------------------------+-------+-+-----+ + */ +static boost::uint32_t calc_tx_mux(const std::vector<mapping_pair_t> &mapping){ + //create look-up-table for mapping channel number and connection type to flags + static const int ENB = 1 << 3, CHAN_I0 = 0, CHAN_Q0 = 1, CHAN_I1 = 2, CHAN_Q1 = 3; + static const uhd::dict<size_t, uhd::dict<std::string, int> > chan_to_conn_to_flag = boost::assign::map_list_of + (0, boost::assign::map_list_of + ("IQ", calc_tx_mux_pair(CHAN_I0 | ENB, CHAN_Q0 | ENB)) + ("QI", calc_tx_mux_pair(CHAN_Q0 | ENB, CHAN_I0 | ENB)) + ("I", calc_tx_mux_pair(CHAN_I0 | ENB, 0 )) + ("Q", calc_tx_mux_pair(0, CHAN_I0 | ENB)) + ) + (1, boost::assign::map_list_of + ("IQ", calc_tx_mux_pair(CHAN_I1 | ENB, CHAN_Q1 | ENB)) + ("QI", calc_tx_mux_pair(CHAN_Q1 | ENB, CHAN_I1 | ENB)) + ("I", calc_tx_mux_pair(CHAN_I1 | ENB, 0 )) + ("Q", calc_tx_mux_pair(0, CHAN_I1 | ENB)) + ) + ; + + //extract the number of channels + size_t nchan = mapping.size(); + + //calculate the channel flags + int channel_flags = 0, chan = 0; + uhd::dict<std::string, int> slot_to_chan_count = boost::assign::map_list_of("A", 0)("B", 0); + BOOST_FOREACH(const mapping_pair_t &pair, mapping){ + const std::string name = pair.first, conn = pair.second; + + //combine the channel flags: shift for slot A vs B + if (name == "A") channel_flags |= chan_to_conn_to_flag[chan][conn] << 0; + if (name == "B") channel_flags |= chan_to_conn_to_flag[chan][conn] << 8; + + //sanity check, only 1 channel per slot + slot_to_chan_count[name]++; + if (slot_to_chan_count[name] > 1) throw uhd::value_error( + "cannot assign dboard slot to multiple channels: " + name + ); + + //increment for the next channel + chan++; + } + + //calculate the tx mux value + return ((channel_flags & 0xffff) << 4) | ((nchan & 0x7) << 0); +} + +#endif /* INCLUDED_USRP1_CALC_MUX_HPP */ diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index 8877f19db..c790aecb4 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -36,7 +36,6 @@ public: usrp1_iface_impl(uhd::usrp::fx2_ctrl::sptr ctrl_transport) { _ctrl_transport = ctrl_transport; - mb_eeprom = mboard_eeprom_t(*this, mboard_eeprom_t::MAP_B000); } ~usrp1_iface_impl(void) @@ -102,78 +101,16 @@ public: throw uhd::not_implemented_error("Unhandled command peek16()"); return 0; } - - void write_uart(boost::uint8_t, const std::string &) { - throw uhd::not_implemented_error("Unhandled command write_uart()"); - } - - std::string read_uart(boost::uint8_t) { - throw uhd::not_implemented_error("Unhandled command read_uart()"); - } /******************************************************************* * I2C ******************************************************************/ - static const size_t max_i2c_data_bytes = 64; - - //TODO: make this handle EEPROM page sizes. right now you can't write over a 16-byte boundary. - //to accomplish this you'll have to have addr offset as a separate parameter. - - void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) - { - UHD_LOGV(always) << "write_i2c:" << std::endl - << " addr 0x" << std::hex << int(addr) << std::endl - << " len " << bytes.size() << std::endl - ; - UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes); - - unsigned char buff[max_i2c_data_bytes]; - std::copy(bytes.begin(), bytes.end(), buff); - - int ret = _ctrl_transport->usrp_i2c_write(addr & 0xff, - buff, - bytes.size()); - - // TODO throw and catch i2c failures during eeprom read - if (ret < 0) - UHD_LOGV(often) << "USRP: failed i2c write: " << ret << std::endl; + void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ + return _ctrl_transport->write_i2c(addr, bytes); } - byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes) - { - UHD_LOGV(always) << "read_i2c:" << std::endl - << " addr 0x" << std::hex << int(addr) << std::endl - << " len " << num_bytes << std::endl - ; - UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes); - - unsigned char buff[max_i2c_data_bytes]; - int ret = _ctrl_transport->usrp_i2c_read(addr & 0xff, - buff, - num_bytes); - - // TODO throw and catch i2c failures during eeprom read - if (ret < 0 or (unsigned)ret < num_bytes) { - UHD_LOGV(often) << "USRP: failed i2c read: " << ret << std::endl; - return byte_vector_t(num_bytes, 0xff); - } - - byte_vector_t out_bytes; - for (size_t i = 0; i < num_bytes; i++) - out_bytes.push_back(buff[i]); - - return out_bytes; - } - - //! overload read_eeprom to handle multi-byte reads - byte_vector_t read_eeprom( - boost::uint8_t addr, - boost::uint8_t offset, - size_t num_bytes - ){ - //do a zero byte write to start read cycle - this->write_i2c(addr, byte_vector_t(1, offset)); - return this->read_i2c(addr, num_bytes); //read all bytes + byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ + return _ctrl_transport->read_i2c(addr, num_bytes); } /******************************************************************* @@ -255,37 +192,6 @@ public: } } - /******************************************************************* - * Firmware - * - * This call is deprecated. - ******************************************************************/ - void write_firmware_cmd(boost::uint8_t request, - boost::uint16_t value, - boost::uint16_t index, - unsigned char *buff, - boost::uint16_t length) - { - int ret; - - if (request & 0x80) { - ret = _ctrl_transport->usrp_control_read(request, - value, - index, - buff, - length); - } - else { - ret = _ctrl_transport->usrp_control_write(request, - value, - index, - buff, - length); - } - - if (ret < 0) throw uhd::io_error("USRP1: failed firmware command"); - } - private: uhd::usrp::fx2_ctrl::sptr _ctrl_transport; }; diff --git a/host/lib/usrp/usrp1/usrp1_iface.hpp b/host/lib/usrp/usrp1/usrp1_iface.hpp index e480c22ea..c1ac34f25 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.hpp +++ b/host/lib/usrp/usrp1/usrp1_iface.hpp @@ -18,43 +18,27 @@ #ifndef INCLUDED_USRP1_IFACE_HPP #define INCLUDED_USRP1_IFACE_HPP -#include <uhd/usrp/mboard_iface.hpp> +#include "fx2_ctrl.hpp" +#include "wb_iface.hpp" +#include <uhd/types/serial.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> -#include "../fx2/fx2_ctrl.hpp" /*! * The usrp1 interface class: * Provides a set of functions to implementation layer. * Including spi, peek, poke, control... */ -class usrp1_iface : public uhd::usrp::mboard_iface, boost::noncopyable{ +class usrp1_iface : public wb_iface, public uhd::i2c_iface, public uhd::spi_iface, boost::noncopyable{ public: typedef boost::shared_ptr<usrp1_iface> sptr; - //motherboard eeprom map structure - uhd::usrp::mboard_eeprom_t mb_eeprom; - /*! * Make a new usrp1 interface with the control transport. * \param ctrl_transport the usrp controller object * \return a new usrp1 interface object */ static sptr make(uhd::usrp::fx2_ctrl::sptr ctrl_transport); - - /*! - * Perform a general USB firmware OUT operation - * \param request - * \param value - * \param index - * \param data - * \return - */ - virtual void write_firmware_cmd(boost::uint8_t request, - boost::uint16_t value, - boost::uint16_t index, - unsigned char* buff, - boost::uint16_t length) = 0; }; #endif /* INCLUDED_USRP1_IFACE_HPP */ diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index a3d502038..f27fc0768 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -16,13 +16,14 @@ // #include "usrp1_impl.hpp" -#include "fpga_regs_standard.h" #include "usrp_spi_defs.h" +#include "usrp_commands.h" +#include "fpga_regs_standard.h" +#include "fpga_regs_common.h" +#include "usrp_i2c_addr.h" #include <uhd/utils/log.hpp> #include <uhd/utils/safe_call.hpp> #include <uhd/transport/usb_control.hpp> -#include <uhd/usrp/device_props.hpp> -#include <uhd/usrp/mboard_props.hpp> #include <uhd/utils/msg.hpp> #include <uhd/exception.hpp> #include <uhd/utils/static.hpp> @@ -101,10 +102,11 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) try{control = usb_control::make(handle);} catch(const uhd::exception &){continue;} //ignore claimed - usrp1_iface::sptr iface = usrp1_iface::make(fx2_ctrl::make(control)); + fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(control); + const mboard_eeprom_t mb_eeprom(*fx2_ctrl, mboard_eeprom_t::MAP_B000); device_addr_t new_addr; new_addr["type"] = "usrp1"; - new_addr["name"] = iface->mb_eeprom["name"]; + new_addr["name"] = mb_eeprom["name"]; new_addr["serial"] = handle->get_serial(); //this is a found usrp1 when the hint serial and name match or blank if ( @@ -122,6 +124,17 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) * Make **********************************************************************/ static device::sptr usrp1_make(const device_addr_t &device_addr){ + return device::sptr(new usrp1_impl(device_addr)); +} + +UHD_STATIC_BLOCK(register_usrp1_device){ + device::register_device(&usrp1_find, &usrp1_make); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +usrp1_impl::usrp1_impl(const device_addr_t &device_addr){ UHD_MSG(status) << "Opening a USRP1 device..." << std::endl; //extract the FPGA path for the USRP1 @@ -144,67 +157,232 @@ static device::sptr usrp1_make(const device_addr_t &device_addr){ } UHD_ASSERT_THROW(handle.get() != NULL); //better be found - //create control objects and a data transport - usb_control::sptr ctrl_transport = usb_control::make(handle); - fx2_ctrl::sptr usrp_ctrl = fx2_ctrl::make(ctrl_transport); - usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); - usrp_ctrl->usrp_init(); - usb_zero_copy::sptr data_transport = usb_zero_copy::make( + //////////////////////////////////////////////////////////////////// + // Create controller objects + //////////////////////////////////////////////////////////////////// + //usb_control::sptr usb_ctrl = usb_control::make(handle); + _fx2_ctrl = fx2_ctrl::make(usb_control::make(handle)); + _fx2_ctrl->usrp_load_fpga(usrp1_fpga_image); + _fx2_ctrl->usrp_init(); + _data_transport = usb_zero_copy::make( handle, // identifier 6, // IN endpoint 2, // OUT endpoint device_addr // param hints ); - - //create the usrp1 implementation guts - return device::sptr(new usrp1_impl(data_transport, usrp_ctrl)); -} - -UHD_STATIC_BLOCK(register_usrp1_device){ - device::register_device(&usrp1_find, &usrp1_make); -} - -/*********************************************************************** - * Structors - **********************************************************************/ -usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, - uhd::usrp::fx2_ctrl::sptr ctrl_transport) - : _data_transport(data_transport), _ctrl_transport(ctrl_transport) -{ - _iface = usrp1_iface::make(ctrl_transport); - - //create clock interface - _clock_ctrl = usrp1_clock_ctrl::make(_iface); - - //create codec interface - _codec_ctrls[DBOARD_SLOT_A] = usrp1_codec_ctrl::make( - _iface, _clock_ctrl, SPI_ENABLE_CODEC_A - ); - _codec_ctrls[DBOARD_SLOT_B] = usrp1_codec_ctrl::make( - _iface, _clock_ctrl, SPI_ENABLE_CODEC_B + _iface = usrp1_iface::make(_fx2_ctrl); + _soft_time_ctrl = soft_time_ctrl::make( + boost::bind(&usrp1_impl::rx_stream_on_off, this, _1) ); + _dbc["A"]; _dbc["B"]; //ensure that keys exist + + // Normal mode with no loopback or Rx counting + _iface->poke32(FR_MODE, 0x00000000); + _iface->poke32(FR_DEBUG_EN, 0x00000000); + _iface->poke32(FR_RX_SAMPLE_RATE_DIV, 0x00000001); //divide by 2 + _iface->poke32(FR_TX_SAMPLE_RATE_DIV, 0x00000001); //divide by 2 + _iface->poke32(FR_DC_OFFSET_CL_EN, 0x0000000f); + + // Reset offset correction registers + _iface->poke32(FR_ADC_OFFSET_0, 0x00000000); + _iface->poke32(FR_ADC_OFFSET_1, 0x00000000); + _iface->poke32(FR_ADC_OFFSET_2, 0x00000000); + _iface->poke32(FR_ADC_OFFSET_3, 0x00000000); + + // Set default for RX format to 16-bit I&Q and no half-band filter bypass + _iface->poke32(FR_RX_FORMAT, 0x00000300); + + // Set default for TX format to 16-bit I&Q + _iface->poke32(FR_TX_FORMAT, 0x00000000); + + UHD_LOG + << "USRP1 Capabilities" << std::endl + << " number of duc's: " << get_num_ddcs() << std::endl + << " number of ddc's: " << get_num_ducs() << std::endl + << " rx halfband: " << has_rx_halfband() << std::endl + << " tx halfband: " << has_tx_halfband() << std::endl + ; + + //////////////////////////////////////////////////////////////////// + // Initialize the properties tree + //////////////////////////////////////////////////////////////////// + _tree = property_tree::make(); + _tree->create<std::string>("/name").set("USRP1 Device"); + const property_tree::path_type mb_path = "/mboards/0"; + _tree->create<std::string>(mb_path / "name").set("USRP1 (Classic)"); + _tree->create<std::string>(mb_path / "load_eeprom") + .subscribe(boost::bind(&fx2_ctrl::usrp_load_eeprom, _fx2_ctrl, _1)); + + //////////////////////////////////////////////////////////////////// + // setup the mboard eeprom + //////////////////////////////////////////////////////////////////// + const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, mboard_eeprom_t::MAP_B000); + _tree->create<mboard_eeprom_t>(mb_path / "eeprom") + .set(mb_eeprom) + .subscribe(boost::bind(&usrp1_impl::set_mb_eeprom, this, _1)); + + //////////////////////////////////////////////////////////////////// + // create clock control objects + //////////////////////////////////////////////////////////////////// + _master_clock_rate = 64e6; + try{ + if (not mb_eeprom["mcr"].empty()) + _master_clock_rate = boost::lexical_cast<double>(mb_eeprom["mcr"]); + }catch(const std::exception &e){ + UHD_MSG(error) << "Error parsing FPGA clock rate from EEPROM: " << e.what() << std::endl; + } + UHD_MSG(status) << boost::format("Using FPGA clock rate of %fMHz...") % (_master_clock_rate/1e6) << std::endl; + _tree->create<double>(mb_path / "tick_rate").set(_master_clock_rate); + + //////////////////////////////////////////////////////////////////// + // create codec control objects + //////////////////////////////////////////////////////////////////// + BOOST_FOREACH(const std::string &db, _dbc.keys()){ + _dbc[db].codec = usrp1_codec_ctrl::make(_iface, (db == "A")? SPI_ENABLE_CODEC_A : SPI_ENABLE_CODEC_B); + const property_tree::path_type rx_codec_path = mb_path / "rx_codecs" / db; + const property_tree::path_type tx_codec_path = mb_path / "tx_codecs" / db; + _tree->create<std::string>(rx_codec_path / "name").set("ad9522"); + _tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(usrp1_codec_ctrl::rx_pga_gain_range); + _tree->create<double>(rx_codec_path / "gains/pga/value") + .coerce(boost::bind(&usrp1_impl::update_rx_codec_gain, this, db, _1)); + _tree->create<std::string>(tx_codec_path / "name").set("ad9522"); + _tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(usrp1_codec_ctrl::tx_pga_gain_range); + _tree->create<double>(tx_codec_path / "gains/pga/value") + .subscribe(boost::bind(&usrp1_codec_ctrl::set_tx_pga_gain, _dbc[db].codec, _1)) + .publish(boost::bind(&usrp1_codec_ctrl::get_tx_pga_gain, _dbc[db].codec)); + } - //initialize the codecs - codec_init(); + //////////////////////////////////////////////////////////////////// + // and do the misc mboard sensors + //////////////////////////////////////////////////////////////////// + //none for now... + _tree->create<int>(mb_path / "sensors"); //phony property so this dir exists + + //////////////////////////////////////////////////////////////////// + // create frontend control objects + //////////////////////////////////////////////////////////////////// + _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec") + .subscribe(boost::bind(&usrp1_impl::update_rx_subdev_spec, this, _1)); + _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec") + .subscribe(boost::bind(&usrp1_impl::update_tx_subdev_spec, this, _1)); + + //////////////////////////////////////////////////////////////////// + // create rx dsp control objects + //////////////////////////////////////////////////////////////////// + for (size_t dspno = 0; dspno < get_num_ddcs(); dspno++){ + property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno); + _tree->create<double>(rx_dsp_path / "rate/value") + .coerce(boost::bind(&usrp1_impl::update_rx_samp_rate, this, _1)); + _tree->create<double>(rx_dsp_path / "freq/value") + .coerce(boost::bind(&usrp1_impl::update_rx_dsp_freq, this, dspno, _1)); + _tree->create<meta_range_t>(rx_dsp_path / "freq/range") + .set(meta_range_t(-_master_clock_rate/2, +_master_clock_rate/2)); + _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd"); + if (dspno == 0){ + //only subscribe the callback for dspno 0 since it will stream all dsps + _tree->access<stream_cmd_t>(rx_dsp_path / "stream_cmd") + .subscribe(boost::bind(&soft_time_ctrl::issue_stream_cmd, _soft_time_ctrl, _1)); + } + } - //initialize the mboard - mboard_init(); + //////////////////////////////////////////////////////////////////// + // create tx dsp control objects + //////////////////////////////////////////////////////////////////// + for (size_t dspno = 0; dspno < get_num_ducs(); dspno++){ + property_tree::path_type tx_dsp_path = mb_path / str(boost::format("tx_dsps/%u") % dspno); + _tree->create<double>(tx_dsp_path / "rate/value") + .coerce(boost::bind(&usrp1_impl::update_tx_samp_rate, this, _1)); + _tree->create<double>(tx_dsp_path / "freq/value") + .coerce(boost::bind(&usrp1_impl::update_tx_dsp_freq, this, dspno, _1)); + _tree->create<meta_range_t>(tx_dsp_path / "freq/range") //magic scalar comes from codec control: + .set(meta_range_t(-_master_clock_rate*0.6875, +_master_clock_rate*0.6875)); + } - //initialize the dboards - dboard_init(); + //////////////////////////////////////////////////////////////////// + // create time control objects + //////////////////////////////////////////////////////////////////// + _tree->create<time_spec_t>(mb_path / "time/now") + .publish(boost::bind(&soft_time_ctrl::get_time, _soft_time_ctrl)) + .subscribe(boost::bind(&soft_time_ctrl::set_time, _soft_time_ctrl, _1)); + + _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(std::vector<std::string>(1, "internal")); + _tree->create<std::vector<std::string> >(mb_path / "time_source/options").set(std::vector<std::string>(1, "none")); + _tree->create<std::string>(mb_path / "clock_source/value").set("internal"); + _tree->create<std::string>(mb_path / "time_source/value").set("none"); + + //////////////////////////////////////////////////////////////////// + // create dboard control objects + //////////////////////////////////////////////////////////////////// + BOOST_FOREACH(const std::string &db, _dbc.keys()){ + + //read the dboard eeprom to extract the dboard ids + dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom; + rx_db_eeprom.load(*_fx2_ctrl, (db == "A")? (I2C_ADDR_RX_A) : (I2C_ADDR_RX_B)); + tx_db_eeprom.load(*_fx2_ctrl, (db == "A")? (I2C_ADDR_TX_A) : (I2C_ADDR_TX_B)); + gdb_eeprom.load(*_fx2_ctrl, (db == "A")? (I2C_ADDR_TX_A ^ 5) : (I2C_ADDR_TX_B ^ 5)); + + //create the properties and register subscribers + _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db/ "rx_eeprom") + .set(rx_db_eeprom) + .subscribe(boost::bind(&usrp1_impl::set_db_eeprom, this, db, "rx", _1)); + _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db/ "tx_eeprom") + .set(tx_db_eeprom) + .subscribe(boost::bind(&usrp1_impl::set_db_eeprom, this, db, "tx", _1)); + _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db/ "gdb_eeprom") + .set(gdb_eeprom) + .subscribe(boost::bind(&usrp1_impl::set_db_eeprom, this, db, "gdb", _1)); + + //create a new dboard interface and manager + _dbc[db].dboard_iface = make_dboard_iface( + _iface, _dbc[db].codec, + (db == "A")? DBOARD_SLOT_A : DBOARD_SLOT_B, + _master_clock_rate, rx_db_eeprom.id + ); + _tree->create<dboard_iface::sptr>(mb_path / "dboards" / db/ "iface").set(_dbc[db].dboard_iface); + _dbc[db].dboard_manager = dboard_manager::make( + rx_db_eeprom.id, + ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id, + _dbc[db].dboard_iface + ); + BOOST_FOREACH(const std::string &name, _dbc[db].dboard_manager->get_rx_subdev_names()){ + dboard_manager::populate_prop_tree_from_subdev( + _tree->subtree(mb_path / "dboards" / db/ "rx_frontends" / name), + _dbc[db].dboard_manager->get_rx_subdev(name) + ); + } + BOOST_FOREACH(const std::string &name, _dbc[db].dboard_manager->get_tx_subdev_names()){ + dboard_manager::populate_prop_tree_from_subdev( + _tree->subtree(mb_path / "dboards" / db/ "tx_frontends" / name), + _dbc[db].dboard_manager->get_tx_subdev(name) + ); + } - //initialize the dsps - rx_dsp_init(); + //init the subdev specs if we have a dboard (wont leave this loop empty) + if (rx_db_eeprom.id != dboard_id_t::none() or _rx_subdev_spec.empty()){ + _rx_subdev_spec = subdev_spec_t(db + ":" + _dbc[db].dboard_manager->get_rx_subdev_names()[0]); + } + if (tx_db_eeprom.id != dboard_id_t::none() or _tx_subdev_spec.empty()){ + _tx_subdev_spec = subdev_spec_t(db + ":" + _dbc[db].dboard_manager->get_tx_subdev_names()[0]); + } + } - //initialize the dsps - tx_dsp_init(); + //initialize io handling + this->io_init(); - //init the subdev specs - this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t()); - this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t()); + //////////////////////////////////////////////////////////////////// + // do some post-init tasks + //////////////////////////////////////////////////////////////////// + //and now that the tick rate is set, init the host rates to something + BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "rx_dsps")){ + _tree->access<double>(mb_path / "rx_dsps" / name / "rate" / "value").set(1e6); + } + BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "tx_dsps")){ + _tree->access<double>(mb_path / "tx_dsps" / name / "rate" / "value").set(1e6); + } - //initialize the send/recv - io_init(); + _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(_rx_subdev_spec); + _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(_tx_subdev_spec); + } usrp1_impl::~usrp1_impl(void){UHD_SAFE_CALL( @@ -212,42 +390,52 @@ usrp1_impl::~usrp1_impl(void){UHD_SAFE_CALL( this->enable_tx(false); )} -bool usrp1_impl::recv_async_msg(uhd::async_metadata_t &, double timeout){ - //dummy fill-in for the recv_async_msg - boost::this_thread::sleep(boost::posix_time::microseconds(long(timeout*1e6))); - return false; +/*! + * Capabilities Register + * + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------------------------------------------+-+-----+-+-----+ + * | Reserved |T|DUCs |R|DDCs | + * +-----------------------------------------------+-+-----+-+-----+ + */ +size_t usrp1_impl::get_num_ddcs(void){ + boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); + return (regval >> 0) & 0x0007; } -/*********************************************************************** - * Device Get - **********************************************************************/ -void usrp1_impl::get(const wax::obj &key_, wax::obj &val) -{ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<device_prop_t>()){ - case DEVICE_PROP_NAME: - val = std::string("usrp1 device"); - return; - - case DEVICE_PROP_MBOARD: - UHD_ASSERT_THROW(key.name == ""); - val = _mboard_proxy->get_link(); - return; +size_t usrp1_impl::get_num_ducs(void){ + boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); + return (regval >> 4) & 0x0007; +} - case DEVICE_PROP_MBOARD_NAMES: - val = prop_names_t(1, ""); //vector of size 1 with empty string - return; +bool usrp1_impl::has_rx_halfband(void){ + boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); + return (regval >> 3) & 0x0001; +} - default: UHD_THROW_PROP_GET_ERROR(); - } +bool usrp1_impl::has_tx_halfband(void){ + boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); + return (regval >> 7) & 0x0001; } /*********************************************************************** - * Device Set + * Properties callback methods below **********************************************************************/ -void usrp1_impl::set(const wax::obj &, const wax::obj &) -{ - UHD_THROW_PROP_SET_ERROR(); +void usrp1_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){ + mb_eeprom.commit(*_fx2_ctrl, mboard_eeprom_t::MAP_B000); +} + +void usrp1_impl::set_db_eeprom(const std::string &db, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){ + if (type == "rx") db_eeprom.store(*_fx2_ctrl, (db == "A")? (I2C_ADDR_RX_A) : (I2C_ADDR_RX_B)); + if (type == "tx") db_eeprom.store(*_fx2_ctrl, (db == "A")? (I2C_ADDR_TX_A) : (I2C_ADDR_TX_B)); + if (type == "gdb") db_eeprom.store(*_fx2_ctrl, (db == "A")? (I2C_ADDR_TX_A ^ 5) : (I2C_ADDR_TX_B ^ 5)); +} + +double usrp1_impl::update_rx_codec_gain(const std::string &db, const double gain){ + //set gain on both I and Q, readback on one + //TODO in the future, gains should have individual control + _dbc[db].codec->set_rx_pga_gain(gain, 'A'); + _dbc[db].codec->set_rx_pga_gain(gain, 'B'); + return _dbc[db].codec->get_rx_pga_gain('A'); } diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index bea1dbe3b..1fe0c1784 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -16,16 +16,17 @@ // #include "usrp1_iface.hpp" -#include "clock_ctrl.hpp" #include "codec_ctrl.hpp" #include "soft_time_ctrl.hpp" #include <uhd/device.hpp> +#include <uhd/property_tree.hpp> #include <uhd/utils/pimpl.hpp> #include <uhd/types/dict.hpp> #include <uhd/types/otw_type.hpp> #include <uhd/types/clock_config.hpp> #include <uhd/types/stream_cmd.hpp> #include <uhd/usrp/dboard_id.hpp> +#include <uhd/usrp/mboard_eeprom.hpp> #include <uhd/usrp/subdev_spec.hpp> #include <uhd/usrp/dboard_eeprom.hpp> #include <uhd/usrp/dboard_manager.hpp> @@ -35,29 +36,6 @@ #define INCLUDED_USRP1_IMPL_HPP /*! - * Simple wax obj proxy class: - * Provides a wax obj interface for a set and a get function. - * This allows us to create nested properties structures - * while maintaining flattened code within the implementation. - */ -class wax_obj_proxy : public wax::obj { -public: - typedef boost::function<void(const wax::obj &, wax::obj &)> get_t; - typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t; - typedef boost::shared_ptr<wax_obj_proxy> sptr; - - static sptr make(const get_t &get, const set_t &set){ - return sptr(new wax_obj_proxy(get, set)); - } - -private: - get_t _get; set_t _set; - wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set) {}; - void get(const wax::obj &key, wax::obj &val) {return _get(key, val);} - void set(const wax::obj &key, const wax::obj &val) {return _set(key, val);} -}; - -/*! * USRP1 implementation guts: * The implementation details are encapsulated here. * Handles properties on the mboard, dboard, dsps... @@ -73,9 +51,7 @@ public: static const std::vector<dboard_slot_t> _dboard_slots; //structors - usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, - uhd::usrp::fx2_ctrl::sptr ctrl_transport); - + usrp1_impl(const uhd::device_addr_t &); ~usrp1_impl(void); //the io interface @@ -97,125 +73,73 @@ public: bool recv_async_msg(uhd::async_metadata_t &, double); private: - /*! - * Make a usrp1 dboard interface. - * \param iface the usrp1 interface object - * \param clock the clock control interface - * \param codec the codec control interface - * \param dboard_slot the slot identifier - * \param rx_dboard_id the db id for the rx board (used for evil dbsrx purposes) - * \return a sptr to a new dboard interface - */ - static uhd::usrp::dboard_iface::sptr make_dboard_iface( - usrp1_iface::sptr iface, - usrp1_clock_ctrl::sptr clock, - usrp1_codec_ctrl::sptr codec, - dboard_slot_t dboard_slot, - const uhd::usrp::dboard_id_t &rx_dboard_id - ); + uhd::property_tree::sptr _tree; - //!call when the channel mapping is changed - void update_xport_channel_mapping(void); + //device properties interface + void get(const wax::obj &, wax::obj &val){ + val = _tree; //entry point into property tree + } - //soft time control emulation + //controllers + uhd::usrp::fx2_ctrl::sptr _fx2_ctrl; + usrp1_iface::sptr _iface; uhd::usrp::soft_time_ctrl::sptr _soft_time_ctrl; + uhd::transport::usb_zero_copy::sptr _data_transport; + struct db_container_type{ + usrp1_codec_ctrl::sptr codec; + uhd::usrp::dboard_iface::sptr dboard_iface; + uhd::usrp::dboard_manager::sptr dboard_manager; + }; + uhd::dict<std::string, db_container_type> _dbc; - //interface to ioctls and file descriptor - usrp1_iface::sptr _iface; + double _master_clock_rate; //clock rate shadow + + void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &); + void set_db_eeprom(const std::string &, const std::string &, const uhd::usrp::dboard_eeprom_t &); + double update_rx_codec_gain(const std::string &, const double); //sets A and B at once + void update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &); + void update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &); + double update_rx_samp_rate(const double); + double update_tx_samp_rate(const double); + double update_rx_dsp_freq(const size_t, const double); + double update_tx_dsp_freq(const size_t, const double); + + static uhd::usrp::dboard_iface::sptr make_dboard_iface( + usrp1_iface::sptr, + usrp1_codec_ctrl::sptr, + dboard_slot_t, + const double, + const uhd::usrp::dboard_id_t & + ); //handle io stuff UHD_PIMPL_DECL(io_impl) _io_impl; void io_init(void); void rx_stream_on_off(bool); + void tx_stream_on_off(bool); void handle_overrun(size_t); - //underrun and overrun poll intervals - size_t _rx_samps_per_poll_interval; - size_t _tx_samps_per_poll_interval; - //otw types - uhd::otw_type_t _rx_otw_type; - uhd::otw_type_t _tx_otw_type; - - //configuration shadows + uhd::otw_type_t _rx_otw_type, _tx_otw_type; uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec; - //clock control - usrp1_clock_ctrl::sptr _clock_ctrl; - - //ad9862 codec control interface - uhd::dict<dboard_slot_t, usrp1_codec_ctrl::sptr> _codec_ctrls; - - //codec properties interfaces - void codec_init(void); - void rx_codec_get(const wax::obj &, wax::obj &, dboard_slot_t); - void rx_codec_set(const wax::obj &, const wax::obj &, dboard_slot_t); - void tx_codec_get(const wax::obj &, wax::obj &, dboard_slot_t); - void tx_codec_set(const wax::obj &, const wax::obj &, dboard_slot_t); - uhd::dict<dboard_slot_t, wax_obj_proxy::sptr> _rx_codec_proxies, _tx_codec_proxies; - - //device functions and settings - void get(const wax::obj &, wax::obj &); - void set(const wax::obj &, const wax::obj &); - - //mboard functions and settings - void mboard_init(void); - void mboard_get(const wax::obj &, wax::obj &); - void mboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _mboard_proxy; - - //xx dboard functions and settings - void dboard_init(void); - uhd::dict<dboard_slot_t, uhd::usrp::dboard_manager::sptr> _dboard_managers; - uhd::dict<dboard_slot_t, uhd::usrp::dboard_iface::sptr> _dboard_ifaces; - - //rx dboard functions and settings - uhd::dict<dboard_slot_t, uhd::usrp::dboard_eeprom_t> _rx_db_eeproms; - void rx_dboard_get(const wax::obj &, wax::obj &, dboard_slot_t); - void rx_dboard_set(const wax::obj &, const wax::obj &, dboard_slot_t); - uhd::dict<dboard_slot_t, wax_obj_proxy::sptr> _rx_dboard_proxies; - - //tx dboard functions and settings - uhd::dict<dboard_slot_t, uhd::usrp::dboard_eeprom_t> _tx_db_eeproms, _gdb_eeproms; - void tx_dboard_get(const wax::obj &, wax::obj &, dboard_slot_t); - void tx_dboard_set(const wax::obj &, const wax::obj &, dboard_slot_t); - uhd::dict<dboard_slot_t, wax_obj_proxy::sptr> _tx_dboard_proxies; - - //rx dsp functions and settings - void rx_dsp_init(void); - void rx_dsp_get(const wax::obj &, wax::obj &, size_t); - void rx_dsp_set(const wax::obj &, const wax::obj &, size_t); - uhd::dict<size_t, double> _rx_dsp_freqs; - size_t _rx_dsp_decim; - uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dsp_proxies; - - //tx dsp functions and settings - void tx_dsp_init(void); - void tx_dsp_get(const wax::obj &, wax::obj &, size_t); - void tx_dsp_set(const wax::obj &, const wax::obj &, size_t); - uhd::dict<size_t, double> _tx_dsp_freqs; - size_t _tx_dsp_interp; - uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsp_proxies; - - //transports - uhd::transport::usb_zero_copy::sptr _data_transport; - uhd::usrp::fx2_ctrl::sptr _ctrl_transport; - //capabilities size_t get_num_ducs(void); size_t get_num_ddcs(void); bool has_rx_halfband(void); bool has_tx_halfband(void); + void vandal_conquest_loop(void); + //handle the enables bool _rx_enabled, _tx_enabled; void enable_rx(bool enb){ _rx_enabled = enb; - _ctrl_transport->usrp_rx_enable(enb); + _fx2_ctrl->usrp_rx_enable(enb); } void enable_tx(bool enb){ _tx_enabled = enb; - _ctrl_transport->usrp_tx_enable(enb); + _fx2_ctrl->usrp_tx_enable(enb); } //conditionally disable and enable rx diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index c3f138c24..10f7407b0 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2011 Ettus Research LLC +# Copyright 2011 Ettus Research LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -27,19 +27,10 @@ LIBUHD_REGISTER_COMPONENT("USRP2" ENABLE_USRP2 ON "ENABLE_LIBUHD" OFF) IF(ENABLE_USRP2) LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.hpp ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_regs.hpp ) ENDIF(ENABLE_USRP2) diff --git a/host/lib/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp deleted file mode 100644 index 26da42759..000000000 --- a/host/lib/usrp/usrp2/codec_impl.cpp +++ /dev/null @@ -1,181 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp2_impl.hpp" -#include <uhd/utils/assert_has.hpp> -#include <uhd/exception.hpp> -#include <uhd/usrp/codec_props.hpp> -#include <uhd/types/dict.hpp> -#include <uhd/types/ranges.hpp> -#include <boost/bind.hpp> -#include <boost/assign/list_of.hpp> - -using namespace uhd; -using namespace uhd::usrp; -using namespace boost::assign; - -//this only applies to N2XX -static const uhd::dict<std::string, gain_range_t> codec_rx_gain_ranges = map_list_of - ("digital", gain_range_t(0, 6.0, 0.5)) - ("digital-fine", gain_range_t(0, 0.5, 0.05)); - - -/*********************************************************************** - * Helper Methods - **********************************************************************/ -void usrp2_mboard_impl::codec_init(void){ - //make proxies - _rx_codec_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_mboard_impl::rx_codec_get, this, _1, _2), - boost::bind(&usrp2_mboard_impl::rx_codec_set, this, _1, _2) - ); - _tx_codec_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_mboard_impl::tx_codec_get, this, _1, _2), - boost::bind(&usrp2_mboard_impl::tx_codec_set, this, _1, _2) - ); - - //initialize gain names. keeps get_rx_gain() from getting a gain - //that hasn't been set yet. - BOOST_FOREACH(std::string key, codec_rx_gain_ranges.keys()) { - _codec_rx_gains[key] = codec_rx_gain_ranges[key].start(); - } -} - -/*********************************************************************** - * RX Codec Properties - **********************************************************************/ -void usrp2_mboard_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_NAME: - switch(_iface->get_rev()){ - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - val = _iface->get_cname() + " adc - ads62p44"; - break; - - case usrp2_iface::USRP2_REV3: - case usrp2_iface::USRP2_REV4: - val = _iface->get_cname() + " adc - ltc2284"; - break; - - case usrp2_iface::USRP_NXXX: - val = _iface->get_cname() + " adc - ??????"; - break; - } - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - switch(_iface->get_rev()){ - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - val = prop_names_t(codec_rx_gain_ranges.keys()); - return; - - default: val = prop_names_t(); - } - return; - - case CODEC_PROP_GAIN_I: - case CODEC_PROP_GAIN_Q: - assert_has(_codec_rx_gains.keys(), key.name, "codec rx gain name"); - val = _codec_rx_gains[key.name]; - return; - - case CODEC_PROP_GAIN_RANGE: - assert_has(codec_rx_gain_ranges.keys(), key.name, "codec rx gain range name"); - val = codec_rx_gain_ranges[key.name]; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp2_mboard_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<codec_prop_t>()) { - case CODEC_PROP_GAIN_I: - case CODEC_PROP_GAIN_Q: - this->rx_codec_set_gain(val.as<double>(), key.name); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * Helper function to set RX codec gain - ***********************************************************************/ - -void usrp2_mboard_impl::rx_codec_set_gain(double gain, const std::string &name){ - assert_has(codec_rx_gain_ranges.keys(), name, "codec rx gain name"); - - _codec_rx_gains[name] = gain; -/* - if(name == "analog") { - _codec_ctrl->set_rx_analog_gain(gain > 0); //just turn it on or off - return; - } -*/ - if(name == "digital") { - _codec_ctrl->set_rx_digital_gain(gain); - return; - } - if(name == "digital-fine") { - _codec_ctrl->set_rx_digital_fine_gain(gain); - return; - } - UHD_THROW_PROP_SET_ERROR(); -} - - -/*********************************************************************** - * TX Codec Properties - **********************************************************************/ -void usrp2_mboard_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_NAME: - val = _iface->get_cname() + " dac - ad9777"; - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - val = prop_names_t(); //no gain elements to be controlled - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp2_mboard_impl::tx_codec_set(const wax::obj &, const wax::obj &){ - UHD_THROW_PROP_SET_ERROR(); -} diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp deleted file mode 100644 index 8c6379d66..000000000 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ /dev/null @@ -1,183 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp2_impl.hpp" -#include "usrp2_regs.hpp" -#include "fw_common.h" -#include <uhd/usrp/misc_utils.hpp> -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/exception.hpp> -#include <boost/format.hpp> -#include <boost/bind.hpp> -#include <boost/asio.hpp> //htonl and ntohl -#include <iostream> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Helper Methods - **********************************************************************/ -void usrp2_mboard_impl::dboard_init(void){ - //read the dboard eeprom to extract the dboard ids - _rx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_RX_DB); - _tx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_TX_DB); - _gdb_eeprom.load(*_iface, USRP2_I2C_ADDR_TX_DB ^ 5); - - //create a new dboard interface and manager - _dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl); - _dboard_manager = dboard_manager::make( - _rx_db_eeprom.id, - ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id, - _dboard_iface - ); - - //load dboards - _rx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_mboard_impl::rx_dboard_get, this, _1, _2), - boost::bind(&usrp2_mboard_impl::rx_dboard_set, this, _1, _2) - ); - _tx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_mboard_impl::tx_dboard_get, this, _1, _2), - boost::bind(&usrp2_mboard_impl::tx_dboard_set, this, _1, _2) - ); -} - -/*********************************************************************** - * RX DBoard Properties - **********************************************************************/ -void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_NAME: - val = _iface->get_cname() + " dboard (rx unit)"; - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_rx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_rx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _rx_db_eeprom; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; - return; - - case DBOARD_PROP_CODEC: - val = _rx_codec_proxy->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _rx_db_eeprom.id, - _dboard_manager->get_rx_subdev(key.name), - _rx_codec_proxy->get_link(), - GAIN_GROUP_POLICY_RX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ - switch(key.as<dboard_prop_t>()){ - - case DBOARD_PROP_DBOARD_EEPROM: - _rx_db_eeprom = val.as<dboard_eeprom_t>(); - _rx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_RX_DB); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX DBoard Properties - **********************************************************************/ -void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_NAME: - val = _iface->get_cname() + " dboard (tx unit)"; - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_tx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_tx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _tx_db_eeprom; - return; - - case DBOARD_PROP_GBOARD_EEPROM: - val = _gdb_eeprom; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; - return; - - case DBOARD_PROP_CODEC: - val = _tx_codec_proxy->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _tx_db_eeprom.id, - _dboard_manager->get_tx_subdev(key.name), - _tx_codec_proxy->get_link(), - GAIN_GROUP_POLICY_TX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ - switch(key.as<dboard_prop_t>()){ - - case DBOARD_PROP_DBOARD_EEPROM: - _tx_db_eeprom = val.as<dboard_eeprom_t>(); - _tx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB); - return; - - case DBOARD_PROP_GBOARD_EEPROM: - _gdb_eeprom = val.as<dboard_eeprom_t>(); - _gdb_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB ^ 5); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp deleted file mode 100644 index 03cdeae42..000000000 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ /dev/null @@ -1,262 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp2_impl.hpp" -#include "usrp2_regs.hpp" -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/dsp_props.hpp> -#include <boost/bind.hpp> -#include <boost/math/special_functions/round.hpp> -#include <boost/math/special_functions/sign.hpp> -#include <algorithm> -#include <cmath> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * DSP impl and methods - **********************************************************************/ -struct usrp2_mboard_impl::dsp_impl{ - uhd::dict<size_t, size_t> ddc_decim; - uhd::dict<size_t, double> ddc_freq; - uhd::dict<size_t, size_t> duc_interp; - uhd::dict<size_t, double> duc_freq; - std::vector<size_t> decim_and_interp_rates; - uhd::dict<size_t, bool> continuous_streaming; -}; - -void usrp2_mboard_impl::dsp_init(void){ - //create new dsp impl - _dsp_impl = UHD_PIMPL_MAKE(dsp_impl, ()); - - //load the allowed decim/interp rates - //range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) - for (size_t i = 4; i <= 128; i+=1){ - _dsp_impl->decim_and_interp_rates.push_back(i); - } - for (size_t i = 130; i <= 256; i+=2){ - _dsp_impl->decim_and_interp_rates.push_back(i); - } - for (size_t i = 260; i <= 512; i+=4){ - _dsp_impl->decim_and_interp_rates.push_back(i); - } - - //bind and initialize the rx dsps - for (size_t i = 0; i < NUM_RX_DSPS; i++){ - _rx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( - boost::bind(&usrp2_mboard_impl::ddc_get, this, _1, _2, i), - boost::bind(&usrp2_mboard_impl::ddc_set, this, _1, _2, i) - ); - - //initial config and update - ddc_set(DSP_PROP_FREQ_SHIFT, double(0), i); - ddc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/16), i); - - //setup the rx control registers - _iface->poke32(U2_REG_RX_CTRL_CLEAR(i), 1); //reset - _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PP(i), _device.get_max_recv_samps_per_packet()); - _iface->poke32(U2_REG_RX_CTRL_NCHANNELS(i), 1); - _iface->poke32(U2_REG_RX_CTRL_VRT_HDR(i), 0 - | (0x1 << 28) //if data with stream id - | (0x1 << 26) //has trailer - | (0x3 << 22) //integer time other - | (0x1 << 20) //fractional time sample count - ); - _iface->poke32(U2_REG_RX_CTRL_VRT_SID(i), usrp2_impl::RECV_SID); - _iface->poke32(U2_REG_RX_CTRL_VRT_TLR(i), 0); - _iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq())); - } - - //bind and initialize the tx dsps - for (size_t i = 0; i < NUM_TX_DSPS; i++){ - _tx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( - boost::bind(&usrp2_mboard_impl::duc_get, this, _1, _2, i), - boost::bind(&usrp2_mboard_impl::duc_set, this, _1, _2, i) - ); - - //initial config and update - duc_set(DSP_PROP_FREQ_SHIFT, double(0), i); - duc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/16), i); - - //init the tx control registers - _iface->poke32(U2_REG_TX_CTRL_CLEAR_STATE, 1); //reset - _iface->poke32(U2_REG_TX_CTRL_NUM_CHAN, 0); //1 channel - _iface->poke32(U2_REG_TX_CTRL_REPORT_SID, usrp2_impl::ASYNC_SID); - _iface->poke32(U2_REG_TX_CTRL_POLICY, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET); - } -} - -template <typename rate_type> -static rate_type pick_closest_rate(double exact_rate, const std::vector<rate_type> &rates){ - unsigned closest_match = rates.front(); - BOOST_FOREACH(rate_type possible_rate, rates){ - if(std::abs(exact_rate - possible_rate) < std::abs(exact_rate - closest_match)) - closest_match = possible_rate; - } - return closest_match; -} - -void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd, size_t which_dsp){ - _dsp_impl->continuous_streaming[which_dsp] = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS; - _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD(which_dsp), dsp_type1::calc_stream_cmd_word(stream_cmd)); - _iface->poke32(U2_REG_RX_CTRL_TIME_SECS(which_dsp), boost::uint32_t(stream_cmd.time_spec.get_full_secs())); - _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS(which_dsp), stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); -} - -/*********************************************************************** - * DDC Properties - **********************************************************************/ -void usrp2_mboard_impl::ddc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_NAME: - val = str(boost::format("%s ddc%d") % _iface->get_cname() % which_dsp); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); //empty - return; - - case DSP_PROP_FREQ_SHIFT: - val = _dsp_impl->ddc_freq[which_dsp]; - return; - - case DSP_PROP_CODEC_RATE: - val = get_master_clock_freq(); - return; - - case DSP_PROP_HOST_RATE: - val = get_master_clock_freq()/_dsp_impl->ddc_decim[which_dsp]; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - - case DSP_PROP_STREAM_CMD: - issue_ddc_stream_cmd(val.as<stream_cmd_t>(), which_dsp); - return; - - case DSP_PROP_FREQ_SHIFT:{ - double new_freq = val.as<double>(); - _iface->poke32(U2_REG_DSP_RX_FREQ(which_dsp), - dsp_type1::calc_cordic_word_and_update(new_freq, get_master_clock_freq()) - ); - _dsp_impl->ddc_freq[which_dsp] = new_freq; //shadow - } - return; - - case DSP_PROP_HOST_RATE:{ - double extact_rate = get_master_clock_freq()/val.as<double>(); - _dsp_impl->ddc_decim[which_dsp] = pick_closest_rate(extact_rate, _dsp_impl->decim_and_interp_rates); - - //set the decimation - _iface->poke32(U2_REG_DSP_RX_DECIM(which_dsp), dsp_type1::calc_cic_filter_word(_dsp_impl->ddc_decim[which_dsp])); - - //set the scaling - static const boost::int16_t default_rx_scale_iq = 1024; - _iface->poke32(U2_REG_DSP_RX_SCALE_IQ(which_dsp), - dsp_type1::calc_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq) - ); - } - _device.update_xport_channel_mapping(); //rate changed -> update - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * DUC Properties - **********************************************************************/ -void usrp2_mboard_impl::duc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_NAME: - val = str(boost::format("%s duc%d") % _iface->get_cname() % which_dsp); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); //empty - return; - - case DSP_PROP_FREQ_SHIFT: - val = _dsp_impl->duc_freq[which_dsp]; - return; - - case DSP_PROP_CODEC_RATE: - val = get_master_clock_freq(); - return; - - case DSP_PROP_HOST_RATE: - val = get_master_clock_freq()/_dsp_impl->duc_interp[which_dsp]; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp2_mboard_impl::duc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - - case DSP_PROP_FREQ_SHIFT:{ - const double codec_rate = get_master_clock_freq(); - double new_freq = val.as<double>(); - - //calculate the DAC shift (multiples of rate) - const int sign = boost::math::sign(new_freq); - const int zone = std::min(boost::math::iround(new_freq/codec_rate), 2); - const double dac_shift = sign*zone*codec_rate; - new_freq -= dac_shift; //update FPGA DSP target freq - - //set the DAC shift (modulation mode) - if (zone == 0) _codec_ctrl->set_tx_mod_mode(0); //no shift - else _codec_ctrl->set_tx_mod_mode(sign*4/zone); //DAC interp = 4 - - _iface->poke32(U2_REG_DSP_TX_FREQ, - dsp_type1::calc_cordic_word_and_update(new_freq, codec_rate) - ); - _dsp_impl->duc_freq[which_dsp] = new_freq + dac_shift; //shadow - } - return; - - case DSP_PROP_HOST_RATE:{ - double extact_rate = get_master_clock_freq()/val.as<double>(); - _dsp_impl->duc_interp[which_dsp] = pick_closest_rate(extact_rate, _dsp_impl->decim_and_interp_rates); - - //set the interpolation - _iface->poke32(U2_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_dsp_impl->duc_interp[which_dsp])); - - //set the scaling - _iface->poke32(U2_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_dsp_impl->duc_interp[which_dsp])); - } - _device.update_xport_channel_mapping(); //rate changed -> update - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index e5c60f27c..83f4a1048 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -30,8 +30,9 @@ extern "C" { #endif //fpga and firmware compatibility numbers -#define USRP2_FPGA_COMPAT_NUM 6 +#define USRP2_FPGA_COMPAT_NUM 7 #define USRP2_FW_COMPAT_NUM 10 +#define USRP2_FW_VER_MINOR 1 //used to differentiate control packets over data port #define USRP2_INVALID_VRT_HEADER 0 @@ -40,9 +41,14 @@ extern "C" { // Dynamic and/or private ports: 49152-65535 #define USRP2_UDP_CTRL_PORT 49152 //#define USRP2_UDP_UPDATE_PORT 49154 -#define USRP2_UDP_DSP0_PORT 49156 -#define USRP2_UDP_ERR0_PORT 49157 -#define USRP2_UDP_DSP1_PORT 49158 +#define USRP2_UDP_RX_DSP0_PORT 49156 +#define USRP2_UDP_TX_DSP0_PORT 49157 +#define USRP2_UDP_RX_DSP1_PORT 49158 + +// Map for virtual firmware regs (not very big so we can keep it here for now) +#define U2_FW_REG_LOCK_TIME 0 +#define U2_FW_REG_LOCK_GPID 1 +#define U2_FW_REG_VER_MINOR 7 //////////////////////////////////////////////////////////////////////// // I2C addresses diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index df452942c..7e855d1bd 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -15,23 +15,22 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include "validate_subdev_spec.hpp" #include "../../transport/super_recv_packet_handler.hpp" #include "../../transport/super_send_packet_handler.hpp" #include "usrp2_impl.hpp" #include "usrp2_regs.hpp" #include <uhd/utils/log.hpp> #include <uhd/utils/msg.hpp> +#include <uhd/utils/tasks.hpp> #include <uhd/exception.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/usrp/dsp_props.hpp> #include <uhd/utils/byteswap.hpp> #include <uhd/utils/thread_priority.hpp> #include <uhd/transport/bounded_buffer.hpp> +#include <boost/thread/thread.hpp> #include <boost/format.hpp> #include <boost/bind.hpp> #include <boost/thread/mutex.hpp> -#include <boost/thread/thread.hpp> -#include <boost/thread/barrier.hpp> #include <iostream> using namespace uhd; @@ -54,11 +53,6 @@ static UHD_INLINE double from_time_dur(const pt::time_duration &time_dur){ /*********************************************************************** * constants **********************************************************************/ -static const int underflow_flags = 0 - | async_metadata_t::EVENT_CODE_UNDERFLOW - | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET -; - static const size_t vrt_send_header_offset_words32 = 1; /*********************************************************************** @@ -134,31 +128,20 @@ private: **********************************************************************/ struct usrp2_impl::io_impl{ - io_impl(std::vector<zero_copy_if::sptr> &dsp_xports): - dsp_xports(dsp_xports), //the assumption is that all data transports should be identical + io_impl(void): async_msg_fifo(100/*messages deep*/) { - for (size_t i = 0; i < dsp_xports.size(); i++){ - fc_mons.push_back(flow_control_monitor::sptr(new flow_control_monitor( - usrp2_impl::sram_bytes/dsp_xports.front()->get_send_frame_size() - ))); - } - } - - ~io_impl(void){ - recv_pirate_crew.interrupt_all(); - recv_pirate_crew.join_all(); + /* NOP */ } managed_send_buffer::sptr get_send_buff(size_t chan, double timeout){ - const size_t index = send_map[chan]; - flow_control_monitor &fc_mon = *fc_mons[index]; + flow_control_monitor &fc_mon = *fc_mons[chan]; //wait on flow control w/ timeout if (not fc_mon.check_fc_condition(timeout)) return managed_send_buffer::sptr(); //get a buffer from the transport w/ timeout - managed_send_buffer::sptr buff = dsp_xports[index]->get_send_buff(timeout); + managed_send_buffer::sptr buff = tx_xports[chan]->get_send_buff(timeout); //write the flow control word into the buffer if (buff.get()) buff->cast<boost::uint32_t *>()[0] = uhd::htonx(fc_mon.get_curr_seq_out()); @@ -166,15 +149,8 @@ struct usrp2_impl::io_impl{ return buff; } - std::vector<zero_copy_if::sptr> &dsp_xports; - - //mappings from channel index to dsp xport - std::vector<size_t> send_map, recv_map; - - //previous state for each buffer - std::vector<vrt::if_packet_info_t> prev_infos; - - //flow control monitors + //tx dsp: xports and flow control monitors + std::vector<zero_copy_if::sptr> tx_xports; std::vector<flow_control_monitor::sptr> fc_mons; //state management for the vrt packet handler code @@ -182,9 +158,10 @@ struct usrp2_impl::io_impl{ sph::send_packet_handler send_handler; //methods and variables for the pirate crew - void recv_pirate_loop(boost::barrier &, usrp2_mboard_impl::sptr, zero_copy_if::sptr, size_t); - boost::thread_group recv_pirate_crew; + void recv_pirate_loop(zero_copy_if::sptr, size_t); + std::list<task::sptr> pirate_tasks; bounded_buffer<async_metadata_t> async_msg_fifo; + double tick_rate; }; /*********************************************************************** @@ -194,16 +171,12 @@ struct usrp2_impl::io_impl{ * - put async message packets into queue **********************************************************************/ void usrp2_impl::io_impl::recv_pirate_loop( - boost::barrier &spawn_barrier, - usrp2_mboard_impl::sptr mboard, - zero_copy_if::sptr err_xport, - size_t index + zero_copy_if::sptr err_xport, size_t index ){ - spawn_barrier.wait(); set_thread_priority_safe(); //store a reference to the flow control monitor (offset by max dsps) - flow_control_monitor &fc_mon = *(this->fc_mons[index*usrp2_mboard_impl::MAX_NUM_DSPS]); + flow_control_monitor &fc_mon = *(this->fc_mons[index]); while (not boost::this_thread::interruption_requested()){ managed_recv_buffer::sptr buff = err_xport->get_recv_buff(); @@ -217,14 +190,14 @@ void usrp2_impl::io_impl::recv_pirate_loop( vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info); //handle a tx async report message - if (if_packet_info.sid == usrp2_impl::ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ + if (if_packet_info.sid == USRP2_TX_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ //fill in the async metadata async_metadata_t metadata; metadata.channel = index; metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; metadata.time_spec = time_spec_t( - time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), mboard->get_master_clock_freq() + time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), tick_rate ); metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); @@ -234,17 +207,23 @@ void usrp2_impl::io_impl::recv_pirate_loop( fc_mon.update_fc_condition(uhd::ntohx(fc_word32)); continue; } - - //print the famous U, and push the metadata into the message queue - if (metadata.event_code & underflow_flags) UHD_MSG(fastpath) << "U"; //else UHD_MSG(often) << "metadata.event_code " << metadata.event_code << std::endl; async_msg_fifo.push_with_pop_on_full(metadata); + + if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_UNDERFLOW + | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) + ) UHD_MSG(fastpath) << "U"; + else if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_SEQ_ERROR + | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) + ) UHD_MSG(fastpath) << "S"; } else{ //TODO unknown received packet, may want to print error... } }catch(const std::exception &e){ - UHD_MSG(error) << "Error (usrp2 recv pirate loop): " << e.what() << std::endl; + UHD_MSG(error) << "Error in recv pirate loop: " << e.what() << std::endl; } } } @@ -254,80 +233,150 @@ void usrp2_impl::io_impl::recv_pirate_loop( **********************************************************************/ void usrp2_impl::io_init(void){ + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + //create new io impl - _io_impl = UHD_PIMPL_MAKE(io_impl, (dsp_xports)); + _io_impl = UHD_PIMPL_MAKE(io_impl, ()); + + //init first so we dont have an access race + BOOST_FOREACH(const std::string &mb, _mbc.keys()){ + //init the tx xport and flow control monitor + _io_impl->tx_xports.push_back(_mbc[mb].tx_dsp_xport); + _io_impl->fc_mons.push_back(flow_control_monitor::sptr(new flow_control_monitor( + USRP2_SRAM_BYTES/_mbc[mb].tx_dsp_xport->get_send_frame_size() + ))); + } //create a new pirate thread for each zc if (yarr!!) - boost::barrier spawn_barrier(_mboards.size()+1); - for (size_t i = 0; i < _mboards.size(); i++){ + size_t index = 0; + BOOST_FOREACH(const std::string &mb, _mbc.keys()){ //spawn a new pirate to plunder the recv booty - _io_impl->recv_pirate_crew.create_thread(boost::bind( - &usrp2_impl::io_impl::recv_pirate_loop, - _io_impl.get(), boost::ref(spawn_barrier), - _mboards.at(i), err_xports.at(i), i - )); + _io_impl->pirate_tasks.push_back(task::make(boost::bind( + &usrp2_impl::io_impl::recv_pirate_loop, _io_impl.get(), + _mbc[mb].tx_dsp_xport, index++ + ))); } - spawn_barrier.wait(); - //update mapping here since it didnt b4 when io init not called first - update_xport_channel_mapping(); -} + //init some handler stuff + _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_be); + _io_impl->recv_handler.set_converter(_rx_otw_type); + _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_be, vrt_send_header_offset_words32); + _io_impl->send_handler.set_converter(_tx_otw_type); + _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); -void usrp2_impl::update_xport_channel_mapping(void){ - if (_io_impl.get() == NULL) return; //not inited yet + //set the packet threshold to be an entire socket buffer's worth + const size_t packets_per_sock_buff = 50e6/_mbc[_mbc.keys().front()].rx_dsp_xports[0]->get_recv_frame_size(); + _io_impl->recv_handler.set_alignment_failure_threshold(packets_per_sock_buff); +} - _io_impl->recv_map.clear(); - _io_impl->send_map.clear(); +void usrp2_impl::update_tick_rate(const double rate){ + _io_impl->tick_rate = rate; + boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); + _io_impl->recv_handler.set_tick_rate(rate); + boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); + _io_impl->send_handler.set_tick_rate(rate); +} - for (size_t i = 0; i < _mboards.size(); i++){ +void usrp2_impl::update_rx_samp_rate(const double rate){ + boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); + _io_impl->recv_handler.set_samp_rate(rate); + const double adj = _mbc[_mbc.keys().front()].rx_dsps.front()->get_scaling_adjustment(); + _io_impl->recv_handler.set_scale_factor(adj/32767.); +} - subdev_spec_t rx_subdev_spec = _mboards[i]->get_link()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>(); - for (size_t j = 0; j < rx_subdev_spec.size(); j++){ - _io_impl->recv_map.push_back(i*usrp2_mboard_impl::MAX_NUM_DSPS+j); - UHD_LOG << "recv_map.back() " << _io_impl->recv_map.back() << std::endl; - } +void usrp2_impl::update_tx_samp_rate(const double rate){ + boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); + _io_impl->send_handler.set_samp_rate(rate); +} - subdev_spec_t tx_subdev_spec = _mboards[i]->get_link()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>(); - for (size_t j = 0; j < tx_subdev_spec.size(); j++){ - _io_impl->send_map.push_back(i*usrp2_mboard_impl::MAX_NUM_DSPS+j); - UHD_LOG << "send_map.back() " << _io_impl->send_map.back() << std::endl; +static subdev_spec_t replace_zero_in_spec(const std::string &type, const subdev_spec_t &spec){ + subdev_spec_t new_spec; + BOOST_FOREACH(const subdev_spec_pair_t &pair, spec){ + if (pair.db_name == "0"){ + UHD_MSG(warning) + << boost::format("In the %s subdevice specification: %s") % type % spec.to_string() << std::endl + << "Accepting dboard slot name \"0\" for backward compatibility." << std::endl + << "The official name of the dboard slot on USRP2/N-Series is \"A\"." << std::endl + ; + new_spec.push_back(subdev_spec_pair_t("A", pair.sd_name)); } - + else new_spec.push_back(pair); } + return new_spec; +} - //set all of the relevant properties on the handler +subdev_spec_t usrp2_impl::update_rx_subdev_spec(const std::string &which_mb, const subdev_spec_t &spec_){ + const subdev_spec_t spec = replace_zero_in_spec("RX", spec_); boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); - _io_impl->recv_handler.resize(_io_impl->recv_map.size()); - _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_be); - _io_impl->recv_handler.set_tick_rate(_mboards.front()->get_master_clock_freq()); - //TODO temporarily use the first dsp rate until we support non-homo rates - const std::string rx_dsp_name = _mboards.at(0)->get_link()[MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>().at(0); - const double rx_host_rate = _mboards.at(0)->get_link()[named_prop_t(MBOARD_PROP_RX_DSP, rx_dsp_name)][DSP_PROP_HOST_RATE].as<double>(); - _io_impl->recv_handler.set_samp_rate(rx_host_rate); - for (size_t chan = 0; chan < _io_impl->recv_handler.size(); chan++){ - _io_impl->recv_handler.set_xport_chan_get_buff(chan, boost::bind( - &uhd::transport::zero_copy_if::get_recv_buff, - _io_impl->dsp_xports[_io_impl->recv_map[chan]], _1 - )); + property_tree::path_type root = "/mboards/" + which_mb + "/dboards"; + + //sanity checking + validate_subdev_spec(_tree, spec, "rx", which_mb); + + //setup mux for this spec + bool fe_swapped = false; + for (size_t i = 0; i < spec.size(); i++){ + const std::string conn = _tree->access<std::string>(root / spec[i].db_name / "rx_frontends" / spec[i].sd_name / "connection").get(); + if (i == 0 and (conn == "QI" or conn == "Q")) fe_swapped = true; + _mbc[which_mb].rx_dsps[i]->set_mux(conn, fe_swapped); } - _io_impl->recv_handler.set_converter(_rx_otw_type); + _mbc[which_mb].rx_fe->set_mux(fe_swapped); + + //compute the new occupancy and resize + _mbc[which_mb].rx_chan_occ = spec.size(); + size_t nchan = 0; + BOOST_FOREACH(const std::string &mb, _mbc.keys()) nchan += _mbc[mb].rx_chan_occ; + _io_impl->recv_handler.resize(nchan); + + //bind new callbacks for the handler + size_t chan = 0; + BOOST_FOREACH(const std::string &mb, _mbc.keys()){ + for (size_t dsp = 0; dsp < _mbc[mb].rx_chan_occ; dsp++){ + _mbc[mb].rx_dsps[dsp]->set_nsamps_per_packet(get_max_recv_samps_per_packet()); //seems to be a good place to set this + _io_impl->recv_handler.set_xport_chan_get_buff(chan++, boost::bind( + &zero_copy_if::get_recv_buff, _mbc[mb].rx_dsp_xports[dsp], _1 + )); + } + } + return spec; +} - //set all of the relevant properties on the handler +subdev_spec_t usrp2_impl::update_tx_subdev_spec(const std::string &which_mb, const subdev_spec_t &spec_){ + const subdev_spec_t spec = replace_zero_in_spec("TX", spec_); boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); - _io_impl->send_handler.resize(_io_impl->send_map.size()); - _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_be, vrt_send_header_offset_words32); - _io_impl->send_handler.set_tick_rate(_mboards.front()->get_master_clock_freq()); - //TODO temporarily use the first dsp rate until we support non-homo rates - const std::string tx_dsp_name = _mboards.at(0)->get_link()[MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>().at(0); - const double tx_host_rate = _mboards.at(0)->get_link()[named_prop_t(MBOARD_PROP_TX_DSP, tx_dsp_name)][DSP_PROP_HOST_RATE].as<double>(); - _io_impl->send_handler.set_samp_rate(tx_host_rate); - for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){ - _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind( - &usrp2_impl::io_impl::get_send_buff, _io_impl.get(), chan, _1 - )); + property_tree::path_type root = "/mboards/" + which_mb + "/dboards"; + + //sanity checking + validate_subdev_spec(_tree, spec, "tx", which_mb); + + //set the mux for this spec + const std::string conn = _tree->access<std::string>(root / spec[0].db_name / "tx_frontends" / spec[0].sd_name / "connection").get(); + _mbc[which_mb].tx_fe->set_mux(conn); + + //compute the new occupancy and resize + _mbc[which_mb].tx_chan_occ = spec.size(); + size_t nchan = 0; + BOOST_FOREACH(const std::string &mb, _mbc.keys()) nchan += _mbc[mb].tx_chan_occ; + _io_impl->send_handler.resize(nchan); + + //bind new callbacks for the handler + size_t chan = 0, i = 0; + BOOST_FOREACH(const std::string &mb, _mbc.keys()){ + for (size_t dsp = 0; dsp < _mbc[mb].tx_chan_occ; dsp++){ + _io_impl->send_handler.set_xport_chan_get_buff(chan++, boost::bind( + &usrp2_impl::io_impl::get_send_buff, _io_impl.get(), i++, _1 + )); + } } - _io_impl->send_handler.set_converter(_tx_otw_type); - _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); + return spec; } /*********************************************************************** @@ -349,7 +398,7 @@ size_t usrp2_impl::get_max_send_samps_per_packet(void) const{ + vrt_send_header_offset_words32*sizeof(boost::uint32_t) - sizeof(vrt::if_packet_info_t().cid) //no class id ever used ; - const size_t bpp = dsp_xports.front()->get_send_frame_size() - hdr_size; + const size_t bpp = _mbc[_mbc.keys().front()].tx_dsp_xport->get_send_frame_size() - hdr_size; return bpp/_tx_otw_type.get_sample_size(); } @@ -374,7 +423,7 @@ size_t usrp2_impl::get_max_recv_samps_per_packet(void) const{ + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer - sizeof(vrt::if_packet_info_t().cid) //no class id ever used ; - const size_t bpp = dsp_xports.front()->get_recv_frame_size() - hdr_size; + const size_t bpp = _mbc[_mbc.keys().front()].rx_dsp_xports[0]->get_recv_frame_size() - hdr_size; return bpp/_rx_otw_type.get_sample_size(); } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp deleted file mode 100644 index 61ceb95ca..000000000 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ /dev/null @@ -1,490 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp2_impl.hpp" -#include "usrp2_regs.hpp" -#include "fw_common.h" -#include <uhd/utils/log.hpp> -#include <uhd/utils/msg.hpp> -#include <uhd/utils/safe_call.hpp> -#include <uhd/exception.hpp> -#include <uhd/usrp/gps_ctrl.hpp> -#include <uhd/usrp/misc_utils.hpp> -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/algorithm.hpp> -#include <uhd/types/sensors.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/bind.hpp> - -static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9; -static const double mimo_clock_delay_usrp_n2xx = 3.55e-9; -static const size_t mimo_clock_sync_delay_cycles = 137; - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::transport; - -/*********************************************************************** - * Helpers - **********************************************************************/ -static void init_xport(zero_copy_if::sptr xport){ - //Send a small data packet so the usrp2 knows the udp source port. - //This setup must happen before further initialization occurs - //or the async update packets will cause ICMP destination unreachable. - static const boost::uint32_t data[2] = { - uhd::htonx(boost::uint32_t(0 /* don't care seq num */)), - uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER)) - }; - - transport::managed_send_buffer::sptr send_buff = xport->get_send_buff(); - std::memcpy(send_buff->cast<void*>(), &data, sizeof(data)); - send_buff->commit(sizeof(data)); -} - -/*********************************************************************** - * Structors - **********************************************************************/ -usrp2_mboard_impl::usrp2_mboard_impl( - const device_addr_t &device_addr, - size_t index, usrp2_impl &device -): - _index(index), _device(device), - _iface(usrp2_iface::make(udp_simple::make_connected( - device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT) - ))) -{ - - //check the fpga compatibility number - const boost::uint32_t fpga_compat_num = _iface->peek32(U2_REG_COMPAT_NUM_RB); - if (fpga_compat_num != USRP2_FPGA_COMPAT_NUM){ - throw uhd::runtime_error(str(boost::format( - "\nPlease update the firmware and FPGA images for your device.\n" - "See the application notes for USRP2/N-Series for instructions.\n" - "Expected FPGA compatibility number %d, but got %d:\n" - "The FPGA build is not compatible with the host code build." - ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_compat_num)); - } - - //lock the device/motherboard to this process - _iface->lock_device(true); - - //construct transports for dsp and async errors - UHD_LOG << "Making transport for DSP0..." << std::endl; - device.dsp_xports.push_back(udp_zero_copy::make( - device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_DSP0_PORT), device_addr - )); - init_xport(device.dsp_xports.back()); - - UHD_LOG << "Making transport for DSP1..." << std::endl; - device.dsp_xports.push_back(udp_zero_copy::make( - device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_DSP1_PORT), device_addr - )); - init_xport(device.dsp_xports.back()); - - UHD_LOG << "Making transport for ERR0..." << std::endl; - device.err_xports.push_back(udp_zero_copy::make( - device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_ERR0_PORT), device_addr_t() - )); - init_xport(device.err_xports.back()); - - //contruct the interfaces to mboard perifs - _clock_ctrl = usrp2_clock_ctrl::make(_iface); - _codec_ctrl = usrp2_codec_ctrl::make(_iface); - if (_iface->mb_eeprom["gpsdo"] == "internal"){ - _gps_ctrl = gps_ctrl::make( - _iface->get_gps_write_fn(), - _iface->get_gps_read_fn()); - } - - //init the dsp stuff (before setting update packets) - dsp_init(); - - //setting the cycles per update (disabled by default) - const double ups_per_sec = device_addr.cast<double>("ups_per_sec", 20); - if (ups_per_sec > 0.0){ - const size_t cycles_per_up = size_t(_clock_ctrl->get_master_clock_rate()/ups_per_sec); - _iface->poke32(U2_REG_TX_CTRL_CYCLES_PER_UP, U2_FLAG_TX_CTRL_UP_ENB | cycles_per_up); - } - - //setting the packets per update (enabled by default) - size_t send_frame_size = device.dsp_xports[0]->get_send_frame_size(); - const double ups_per_fifo = device_addr.cast<double>("ups_per_fifo", 8.0); - if (ups_per_fifo > 0.0){ - const size_t packets_per_up = size_t(usrp2_impl::sram_bytes/ups_per_fifo/send_frame_size); - _iface->poke32(U2_REG_TX_CTRL_PACKETS_PER_UP, U2_FLAG_TX_CTRL_UP_ENB | packets_per_up); - } - - //initialize the clock configuration - if (device_addr.has_key("mimo_mode")){ - if (device_addr["mimo_mode"] == "master"){ - _mimo_clocking_mode_is_master = true; - } - else if (device_addr["mimo_mode"] == "slave"){ - _mimo_clocking_mode_is_master = false; - } - else throw uhd::value_error( - "mimo_mode must be set to master or slave" - ); - } - else { - _mimo_clocking_mode_is_master = (_iface->peek32(U2_REG_STATUS) & (1 << 8)) != 0; - } - UHD_MSG(status) << boost::format("mboard%d is MIMO %s") % _index % - (_mimo_clocking_mode_is_master?"master":"slave") << std::endl; - - //init the clock config - if(_iface->mb_eeprom["gpsdo"] == "internal" or - _iface->mb_eeprom["gpsdo"] == "external") { - _clock_config = clock_config_t::external(); - } - else { - _clock_config = clock_config_t::internal(); - } - update_clock_config(); - - //init the codec before the dboard - codec_init(); - - //init the tx and rx dboards (do last) - dboard_init(); - - //set default subdev specs - (*this)[MBOARD_PROP_RX_SUBDEV_SPEC] = subdev_spec_t(); - (*this)[MBOARD_PROP_TX_SUBDEV_SPEC] = subdev_spec_t(); - - //------------------------------------------------------------------ - //This is a hack/fix for the lingering packet problem. - stream_cmd_t stream_cmd(stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); - for (size_t i = 0; i < NUM_RX_DSPS; i++){ - size_t index = device.dsp_xports.size() - NUM_RX_DSPS + i; - stream_cmd.num_samps = 1; - this->issue_ddc_stream_cmd(stream_cmd, i); - device.dsp_xports.at(index)->get_recv_buff(0.01).get(); //recv with timeout for lingering - device.dsp_xports.at(index)->get_recv_buff(0.01).get(); //recv with timeout for expected - _iface->poke32(U2_REG_RX_CTRL_CLEAR(i), 1); //resets sequence - } - //------------------------------------------------------------------ - - //initialize VITA time to GPS time - if( _gps_ctrl.get() - and _gps_ctrl->gps_detected()) { - UHD_MSG(status) << "Setting device time to GPS time...\n"; - set_time_spec(time_spec_t(double(_gps_ctrl->get_sensor("gps_time").to_int()+1)), false); - } -} - -usrp2_mboard_impl::~usrp2_mboard_impl(void){UHD_SAFE_CALL( - _iface->poke32(U2_REG_TX_CTRL_CYCLES_PER_UP, 0); - _iface->poke32(U2_REG_TX_CTRL_PACKETS_PER_UP, 0); -)} - -/*********************************************************************** - * Helper Methods - **********************************************************************/ -void usrp2_mboard_impl::update_clock_config(void){ - boost::uint32_t pps_flags = 0; - - //slave mode overrides clock config settings - if (not _mimo_clocking_mode_is_master){ - _clock_config.ref_source = clock_config_t::REF_MIMO; - _clock_config.pps_source = clock_config_t::PPS_MIMO; - } - - //translate pps source enums - switch(_clock_config.pps_source){ - case clock_config_t::PPS_MIMO: - _iface->poke32(U2_REG_TIME64_MIMO_SYNC, - (1 << 8) | (mimo_clock_sync_delay_cycles & 0xff) - ); - break; - - case clock_config_t::PPS_SMA: - _iface->poke32(U2_REG_TIME64_MIMO_SYNC, 0); - pps_flags |= U2_FLAG_TIME64_PPS_SMA; - break; - - default: throw uhd::value_error("unhandled clock configuration pps source"); - } - - //translate pps polarity enums - switch(_clock_config.pps_polarity){ - case clock_config_t::PPS_POS: pps_flags |= U2_FLAG_TIME64_PPS_POSEDGE; break; - case clock_config_t::PPS_NEG: pps_flags |= U2_FLAG_TIME64_PPS_NEGEDGE; break; - default: throw uhd::value_error("unhandled clock configuration pps polarity"); - } - - //set the pps flags - _iface->poke32(U2_REG_TIME64_FLAGS, pps_flags); - - //clock source ref 10mhz - switch(_iface->get_rev()){ - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - switch(_clock_config.ref_source){ - case clock_config_t::REF_INT : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12); break; - case clock_config_t::REF_SMA : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); break; - case clock_config_t::REF_MIMO: _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); break; - default: throw uhd::value_error("unhandled clock configuration reference source"); - } - _clock_ctrl->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO - break; - - case usrp2_iface::USRP2_REV3: - case usrp2_iface::USRP2_REV4: - switch(_clock_config.ref_source){ - case clock_config_t::REF_INT : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10); break; - case clock_config_t::REF_SMA : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); break; - case clock_config_t::REF_MIMO: _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); break; - default: throw uhd::value_error("unhandled clock configuration reference source"); - } - _clock_ctrl->enable_external_ref(_clock_config.ref_source != clock_config_t::REF_INT); - break; - - case usrp2_iface::USRP_NXXX: break; - } - - //masters always drive the clock over serdes - _clock_ctrl->enable_mimo_clock_out(_mimo_clocking_mode_is_master); - - //set the mimo clock delay over the serdes - if (_mimo_clocking_mode_is_master){ - switch(_iface->get_rev()){ - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx); - break; - - case usrp2_iface::USRP2_REV4: - _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4); - break; - - default: break; //not handled - } - } - -} - -void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){ - //dont set the time for slave devices, they always take from mimo cable - if (not _mimo_clocking_mode_is_master) return; - - //set the ticks - _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq())); - - //set the flags register - boost::uint32_t imm_flags = (now)? U2_FLAG_TIME64_LATCH_NOW : U2_FLAG_TIME64_LATCH_NEXT_PPS; - _iface->poke32(U2_REG_TIME64_IMM, imm_flags); - - //set the seconds (latches in all 3 registers) - _iface->poke32(U2_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs())); -} - -/*********************************************************************** - * MBoard Get Properties - **********************************************************************/ -static const std::string dboard_name = "0"; - -void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - //handle the get request conditioned on the key - switch(key.as<mboard_prop_t>()){ - case MBOARD_PROP_NAME: - val = _iface->get_cname() + " mboard"; - return; - - case MBOARD_PROP_OTHERS: - val = prop_names_t(); - return; - - case MBOARD_PROP_RX_DBOARD: - UHD_ASSERT_THROW(key.name == dboard_name); - val = _rx_dboard_proxy->get_link(); - return; - - case MBOARD_PROP_RX_DBOARD_NAMES: - val = prop_names_t(1, dboard_name); - return; - - case MBOARD_PROP_TX_DBOARD: - UHD_ASSERT_THROW(key.name == dboard_name); - val = _tx_dboard_proxy->get_link(); - return; - - case MBOARD_PROP_TX_DBOARD_NAMES: - val = prop_names_t(1, dboard_name); - return; - - case MBOARD_PROP_RX_DSP: - val = _rx_dsp_proxies[key.name]->get_link(); - return; - - case MBOARD_PROP_RX_DSP_NAMES: - val = _rx_dsp_proxies.keys(); - return; - - case MBOARD_PROP_TX_DSP: - val = _tx_dsp_proxies[key.name]->get_link(); - return; - - case MBOARD_PROP_TX_DSP_NAMES: - val = _tx_dsp_proxies.keys(); - return; - - case MBOARD_PROP_CLOCK_CONFIG: - val = _clock_config; - return; - - case MBOARD_PROP_TIME_NOW: while(true){ - uint32_t secs = _iface->peek32(U2_REG_TIME64_SECS_RB_IMM); - uint32_t ticks = _iface->peek32(U2_REG_TIME64_TICKS_RB_IMM); - if (secs != _iface->peek32(U2_REG_TIME64_SECS_RB_IMM)) continue; - val = time_spec_t(secs, ticks, get_master_clock_freq()); - return; - } - - case MBOARD_PROP_TIME_PPS: while(true){ - uint32_t secs = _iface->peek32(U2_REG_TIME64_SECS_RB_PPS); - uint32_t ticks = _iface->peek32(U2_REG_TIME64_TICKS_RB_PPS); - if (secs != _iface->peek32(U2_REG_TIME64_SECS_RB_PPS)) continue; - val = time_spec_t(secs, ticks, get_master_clock_freq()); - return; - } - - case MBOARD_PROP_RX_SUBDEV_SPEC: - val = _rx_subdev_spec; - return; - - case MBOARD_PROP_TX_SUBDEV_SPEC: - val = _tx_subdev_spec; - return; - - case MBOARD_PROP_EEPROM_MAP: - val = _iface->mb_eeprom; - return; - - case MBOARD_PROP_CLOCK_RATE: - val = this->get_master_clock_freq(); - return; - - case SUBDEV_PROP_SENSOR_NAMES:{ - prop_names_t names = boost::assign::list_of("mimo_locked")("ref_locked"); - if (_gps_ctrl.get()) { - std::vector<std::string> gs = _gps_ctrl->get_sensors(); - names.insert(names.end(), gs.begin(), gs.end()); - } - val = names; - } - return; - - case MBOARD_PROP_SENSOR: - if(key.name == "mimo_locked") { - val = sensor_value_t("MIMO", this->get_mimo_locked(), "locked", "unlocked"); - return; - } - else if(key.name == "ref_locked") { - val = sensor_value_t("Ref", this->get_ref_locked(), "locked", "unlocked"); - return; - } - else if(uhd::has(_gps_ctrl->get_sensors(), key.name) and _gps_ctrl.get()) { - val = _gps_ctrl->get_sensor(key.name); - } - else { - UHD_THROW_PROP_GET_ERROR(); - } - break; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -bool usrp2_mboard_impl::get_mimo_locked(void) { - return bool((_iface->peek32(U2_REG_IRQ_RB) & (1<<10)) > 0); -} - -bool usrp2_mboard_impl::get_ref_locked(void) { - return bool((_iface->peek32(U2_REG_IRQ_RB) & (1<<11)) > 0); -} - -/*********************************************************************** - * MBoard Set Properties - **********************************************************************/ -void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){ - //handle the set request conditioned on the key - switch(key.as<mboard_prop_t>()){ - - case MBOARD_PROP_CLOCK_CONFIG: - _clock_config = val.as<clock_config_t>(); - update_clock_config(); - return; - - case MBOARD_PROP_TIME_NOW: - set_time_spec(val.as<time_spec_t>(), true); - return; - - case MBOARD_PROP_TIME_PPS: - set_time_spec(val.as<time_spec_t>(), false); - return; - - case MBOARD_PROP_RX_SUBDEV_SPEC: - _rx_subdev_spec = val.as<subdev_spec_t>(); - verify_rx_subdev_spec(_rx_subdev_spec, this->get_link()); - //sanity check - UHD_ASSERT_THROW(_rx_subdev_spec.size() <= NUM_RX_DSPS); - //set the mux - for (size_t i = 0; i < _rx_subdev_spec.size(); i++){ - _iface->poke32(U2_REG_DSP_RX_MUX(i), dsp_type1::calc_rx_mux_word( - _dboard_manager->get_rx_subdev(_rx_subdev_spec[i].sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() - )); - } - _device.update_xport_channel_mapping(); - return; - - case MBOARD_PROP_TX_SUBDEV_SPEC: - _tx_subdev_spec = val.as<subdev_spec_t>(); - verify_tx_subdev_spec(_tx_subdev_spec, this->get_link()); - //sanity check - UHD_ASSERT_THROW(_tx_subdev_spec.size() <= NUM_TX_DSPS); - //set the mux - for (size_t i = 0; i < _rx_subdev_spec.size(); i++){ - _iface->poke32(U2_REG_DSP_TX_MUX, dsp_type1::calc_tx_mux_word( - _dboard_manager->get_tx_subdev(_tx_subdev_spec[i].sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() - )); - } - _device.update_xport_channel_mapping(); - return; - - case MBOARD_PROP_EEPROM_MAP: - // Step1: commit the map, writing only those values set. - // Step2: readback the entire eeprom map into the iface. - val.as<mboard_eeprom_t>().commit(*_iface, mboard_eeprom_t::MAP_N100); - _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_N100); - return; - - case MBOARD_PROP_CLOCK_RATE: - UHD_ASSERT_THROW(val.as<double>() == this->get_master_clock_freq()); - _device.update_xport_channel_mapping(); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 6ba364b28..aaa5acbd5 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -20,15 +20,15 @@ #include "usrp2_iface.hpp" #include <uhd/exception.hpp> #include <uhd/utils/msg.hpp> +#include <uhd/utils/tasks.hpp> #include <uhd/types/dict.hpp> #include <boost/thread.hpp> #include <boost/foreach.hpp> #include <boost/asio.hpp> //used for htonl and ntohl #include <boost/assign/list_of.hpp> #include <boost/format.hpp> +#include <boost/bind.hpp> #include <boost/tokenizer.hpp> -#include <boost/thread/thread.hpp> -#include <boost/thread/barrier.hpp> #include <boost/functional/hash.hpp> #include <algorithm> #include <iostream> @@ -46,10 +46,6 @@ static const boost::uint32_t MIN_PROTO_COMPAT_I2C = 7; static const boost::uint32_t MIN_PROTO_COMPAT_REG = USRP2_FW_COMPAT_NUM; static const boost::uint32_t MIN_PROTO_COMPAT_UART = 7; -// Map for virtual firmware regs (not very big so we can keep it here for now) -#define U2_FW_REG_LOCK_TIME 0 -#define U2_FW_REG_LOCK_GPID 1 - //Define get_gpid() to get a globally unique identifier for this process. //The gpid is implemented as a hash of the pid and a unique machine identifier. #ifdef UHD_PLATFORM_WIN32 @@ -110,13 +106,12 @@ public: void lock_device(bool lock){ if (lock){ - boost::barrier spawn_barrier(2); - _lock_thread_group.create_thread(boost::bind(&usrp2_iface_impl::lock_loop, this, boost::ref(spawn_barrier))); - spawn_barrier.wait(); + this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_GPID, boost::uint32_t(get_gpid())); + _lock_task = task::make(boost::bind(&usrp2_iface_impl::lock_task, this)); } else{ - _lock_thread_group.interrupt_all(); - _lock_thread_group.join_all(); + _lock_task.reset(); //shutdown the task + this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, 0); //unlock } } @@ -132,52 +127,35 @@ public: return lock_gpid != boost::uint32_t(get_gpid()); } - void lock_loop(boost::barrier &spawn_barrier){ - spawn_barrier.wait(); - - try{ - this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_GPID, boost::uint32_t(get_gpid())); - while(true){ - //re-lock in loop - boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM); - this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, curr_secs); - //sleep for a bit - boost::this_thread::sleep(boost::posix_time::milliseconds(1500)); - } - } - catch(const boost::thread_interrupted &){ - this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, 0); //unlock on exit - } - catch(const std::exception &e){ - UHD_MSG(error) - << "An unexpected exception was caught in the locker loop." << std::endl - << "The device will automatically unlock from this process." << std::endl - << e.what() << std::endl - ; - } + void lock_task(void){ + //re-lock in task + boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM); + this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, curr_secs); + //sleep for a bit + boost::this_thread::sleep(boost::posix_time::milliseconds(1500)); } /*********************************************************************** * Peek and Poke **********************************************************************/ - void poke32(boost::uint32_t addr, boost::uint32_t data){ + void poke32(wb_addr_type addr, boost::uint32_t data){ this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FPGA_POKE32>(addr, data); } - boost::uint32_t peek32(boost::uint32_t addr){ + boost::uint32_t peek32(wb_addr_type addr){ return this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FPGA_PEEK32>(addr); } - void poke16(boost::uint32_t addr, boost::uint16_t data){ + void poke16(wb_addr_type addr, boost::uint16_t data){ this->get_reg<boost::uint16_t, USRP2_REG_ACTION_FPGA_POKE16>(addr, data); } - boost::uint16_t peek16(boost::uint32_t addr){ + boost::uint16_t peek16(wb_addr_type addr){ return this->get_reg<boost::uint16_t, USRP2_REG_ACTION_FPGA_PEEK16>(addr); } template <class T, usrp2_reg_action_t action> - T get_reg(boost::uint32_t addr, T data = 0){ + T get_reg(wb_addr_type addr, T data = 0){ //setup the out data usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t(); out_data.id = htonl(USRP2_CTRL_ID_GET_THIS_REGISTER_FOR_ME_BRO); @@ -390,6 +368,11 @@ public: UHD_THROW_INVALID_CODE_PATH(); } + const std::string get_fw_version_string(void){ + boost::uint32_t minor = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_VER_MINOR); + return str(boost::format("%u.%u") % _protocol_compat % minor); + } + private: //this lovely lady makes it all possible udp_simple::sptr _ctrl_transport; @@ -400,7 +383,7 @@ private: boost::uint32_t _protocol_compat; //lock thread stuff - boost::thread_group _lock_thread_group; + task::sptr _lock_task; }; /*********************************************************************** diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index 16b640a70..b3c3ef4a2 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -19,15 +19,14 @@ #define INCLUDED_USRP2_IFACE_HPP #include <uhd/transport/udp_simple.hpp> -#include <uhd/usrp/mboard_iface.hpp> +#include <uhd/types/serial.hpp> +#include <uhd/usrp/mboard_eeprom.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> -#include <boost/cstdint.hpp> #include <boost/function.hpp> -#include <utility> -#include <string> #include "usrp2_regs.hpp" - +#include "wb_iface.hpp" +#include <string> //TODO: kill this crap when you have the top level GPS include file typedef boost::function<void(std::string)> gps_send_fn_t; @@ -38,7 +37,7 @@ typedef boost::function<std::string(void)> gps_recv_fn_t; * Provides a set of functions to implementation layer. * Including spi, peek, poke, control... */ -class usrp2_iface : public uhd::usrp::mboard_iface, boost::noncopyable{ +class usrp2_iface : public wb_iface, public uhd::spi_iface, public uhd::i2c_iface, public uhd::uart_iface{ public: typedef boost::shared_ptr<usrp2_iface> sptr; /*! @@ -74,6 +73,9 @@ public: //! Is this device locked? virtual bool is_device_locked(void) = 0; + //! A version string for firmware + virtual const std::string get_fw_version_string(void) = 0; + //motherboard eeprom map structure uhd::usrp::mboard_eeprom_t mb_eeprom; }; diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index aa584ac8b..45db0d081 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -22,18 +22,18 @@ #include <uhd/exception.hpp> #include <uhd/transport/if_addrs.hpp> #include <uhd/transport/udp_zero_copy.hpp> -#include <uhd/usrp/device_props.hpp> +#include <uhd/types/ranges.hpp> #include <uhd/exception.hpp> #include <uhd/utils/static.hpp> #include <uhd/utils/byteswap.hpp> -#include <boost/assign/list_of.hpp> +#include <uhd/utils/safe_call.hpp> #include <boost/format.hpp> #include <boost/foreach.hpp> #include <boost/lexical_cast.hpp> #include <boost/bind.hpp> +#include <boost/assign/list_of.hpp> #include <boost/asio/ip/address_v4.hpp> #include <boost/asio.hpp> //used for htonl and ntohl -#include <vector> using namespace uhd; using namespace uhd::usrp; @@ -227,6 +227,40 @@ static mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &u } /*********************************************************************** + * Helpers + **********************************************************************/ +static zero_copy_if::sptr make_xport( + const std::string &addr, + const std::string &port, + const device_addr_t &hints, + const std::string &filter +){ + + //only copy hints that contain the filter word + device_addr_t filtered_hints; + BOOST_FOREACH(const std::string &key, hints.keys()){ + if (key.find(filter) == std::string::npos) continue; + filtered_hints[key] = hints[key]; + } + + //make the transport object with the filtered hints + zero_copy_if::sptr xport = udp_zero_copy::make(addr, port, filtered_hints); + + //Send a small data packet so the usrp2 knows the udp source port. + //This setup must happen before further initialization occurs + //or the async update packets will cause ICMP destination unreachable. + static const boost::uint32_t data[2] = { + uhd::htonx(boost::uint32_t(0 /* don't care seq num */)), + uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER)) + }; + transport::managed_send_buffer::sptr send_buff = xport->get_send_buff(); + std::memcpy(send_buff->cast<void*>(), &data, sizeof(data)); + send_buff->commit(sizeof(data)); + + return xport; +} + +/*********************************************************************** * Structors **********************************************************************/ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ @@ -272,67 +306,405 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ device_args = separate_device_addr(device_addr); //update args for new frame sizes - //setup rx otw type - _rx_otw_type.width = 16; - _rx_otw_type.shift = 0; - _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; - - //setup tx otw type - _tx_otw_type.width = 16; - _tx_otw_type.shift = 0; - _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + //////////////////////////////////////////////////////////////////// + // create controller objects and initialize the properties tree + //////////////////////////////////////////////////////////////////// + _tree = property_tree::make(); + _tree->create<std::string>("/name").set("USRP2 / N-Series Device"); + + for (size_t mbi = 0; mbi < device_args.size(); mbi++){ + const device_addr_t device_args_i = device_args[mbi]; + const std::string mb = boost::lexical_cast<std::string>(mbi); + const std::string addr = device_args_i["addr"]; + const property_tree::path_type mb_path = "/mboards/" + mb; + + //////////////////////////////////////////////////////////////// + // create the iface that controls i2c, spi, uart, and wb + //////////////////////////////////////////////////////////////// + _mbc[mb].iface = usrp2_iface::make(udp_simple::make_connected( + addr, BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT) + )); + _tree->create<std::string>(mb_path / "name").set(_mbc[mb].iface->get_cname()); + _tree->create<std::string>(mb_path / "fw_version").set(_mbc[mb].iface->get_fw_version_string()); + + //check the fpga compatibility number + const boost::uint32_t fpga_compat_num = _mbc[mb].iface->peek32(U2_REG_COMPAT_NUM_RB); + boost::uint16_t fpga_major = fpga_compat_num >> 16, fpga_minor = fpga_compat_num & 0xffff; + if (fpga_major == 0){ //old version scheme + fpga_major = fpga_minor; + fpga_minor = 0; + } + if (fpga_major != USRP2_FPGA_COMPAT_NUM){ + throw uhd::runtime_error(str(boost::format( + "\nPlease update the firmware and FPGA images for your device.\n" + "See the application notes for USRP2/N-Series for instructions.\n" + "Expected FPGA compatibility number %d, but got %d:\n" + "The FPGA build is not compatible with the host code build." + ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_major)); + } + _tree->create<std::string>(mb_path / "fpga_version").set(str(boost::format("%u.%u") % fpga_major % fpga_minor)); - //!!!!! set the otw type here before continuing, its used below + //lock the device/motherboard to this process + _mbc[mb].iface->lock_device(true); - //create a new mboard handler for each control transport - for(size_t i = 0; i < device_args.size(); i++){ - device_addr_t dev_addr_i = device_args[i]; - BOOST_FOREACH(const std::string &key, device_addr.keys()){ - if (dev_addr_i.has_key(key)) continue; - dev_addr_i[key] = device_addr[key]; + //////////////////////////////////////////////////////////////// + // construct transports for RX and TX DSPs + //////////////////////////////////////////////////////////////// + UHD_LOG << "Making transport for RX DSP0..." << std::endl; + _mbc[mb].rx_dsp_xports.push_back(make_xport( + addr, BOOST_STRINGIZE(USRP2_UDP_RX_DSP0_PORT), device_args_i, "recv" + )); + UHD_LOG << "Making transport for RX DSP1..." << std::endl; + _mbc[mb].rx_dsp_xports.push_back(make_xport( + addr, BOOST_STRINGIZE(USRP2_UDP_RX_DSP1_PORT), device_args_i, "recv" + )); + UHD_LOG << "Making transport for TX DSP0..." << std::endl; + _mbc[mb].tx_dsp_xport = make_xport( + addr, BOOST_STRINGIZE(USRP2_UDP_TX_DSP0_PORT), device_args_i, "send" + ); + //set the filter on the router to take dsp data from this port + _mbc[mb].iface->poke32(U2_REG_ROUTER_CTRL_PORTS, USRP2_UDP_TX_DSP0_PORT); + + //////////////////////////////////////////////////////////////// + // setup the mboard eeprom + //////////////////////////////////////////////////////////////// + _tree->create<mboard_eeprom_t>(mb_path / "eeprom") + .set(_mbc[mb].iface->mb_eeprom) + .subscribe(boost::bind(&usrp2_impl::set_mb_eeprom, this, mb, _1)); + + //////////////////////////////////////////////////////////////// + // create clock control objects + //////////////////////////////////////////////////////////////// + _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface); + _tree->create<double>(mb_path / "tick_rate") + .publish(boost::bind(&usrp2_clock_ctrl::get_master_clock_rate, _mbc[mb].clock)) + .subscribe(boost::bind(&usrp2_impl::update_tick_rate, this, _1)); + + //////////////////////////////////////////////////////////////// + // create codec control objects + //////////////////////////////////////////////////////////////// + const property_tree::path_type rx_codec_path = mb_path / "rx_codecs/A"; + const property_tree::path_type tx_codec_path = mb_path / "tx_codecs/A"; + _tree->create<int>(rx_codec_path / "gains"); //phony property so this dir exists + _tree->create<int>(tx_codec_path / "gains"); //phony property so this dir exists + _mbc[mb].codec = usrp2_codec_ctrl::make(_mbc[mb].iface); + switch(_mbc[mb].iface->get_rev()){ + case usrp2_iface::USRP_N200: + case usrp2_iface::USRP_N210: + case usrp2_iface::USRP_N200_R4: + case usrp2_iface::USRP_N210_R4:{ + _tree->create<std::string>(rx_codec_path / "name").set("ads62p44"); + _tree->create<meta_range_t>(rx_codec_path / "gains/digital/range").set(meta_range_t(0, 6.0, 0.5)); + _tree->create<double>(rx_codec_path / "gains/digital/value") + .subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_gain, _mbc[mb].codec, _1)).set(0); + _tree->create<meta_range_t>(rx_codec_path / "gains/fine/range").set(meta_range_t(0, 0.5, 0.05)); + _tree->create<double>(rx_codec_path / "gains/fine/value") + .subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_fine_gain, _mbc[mb].codec, _1)).set(0); + }break; + + case usrp2_iface::USRP2_REV3: + case usrp2_iface::USRP2_REV4: + _tree->create<std::string>(rx_codec_path / "name").set("ltc2284"); + break; + + case usrp2_iface::USRP_NXXX: + _tree->create<std::string>(rx_codec_path / "name").set("??????"); + break; } - _mboards.push_back(usrp2_mboard_impl::sptr( - new usrp2_mboard_impl(dev_addr_i, i, *this) + _tree->create<std::string>(tx_codec_path / "name").set("ad9777"); + + //////////////////////////////////////////////////////////////// + // create gpsdo control objects + //////////////////////////////////////////////////////////////// + if (_mbc[mb].iface->mb_eeprom["gpsdo"] == "internal"){ + _mbc[mb].gps = gps_ctrl::make( + _mbc[mb].iface->get_gps_write_fn(), + _mbc[mb].iface->get_gps_read_fn() + ); + BOOST_FOREACH(const std::string &name, _mbc[mb].gps->get_sensors()){ + _tree->create<sensor_value_t>(mb_path / "sensors" / name) + .publish(boost::bind(&gps_ctrl::get_sensor, _mbc[mb].gps, name)); + } + } + + //////////////////////////////////////////////////////////////// + // and do the misc mboard sensors + //////////////////////////////////////////////////////////////// + _tree->create<sensor_value_t>(mb_path / "sensors/mimo_locked") + .publish(boost::bind(&usrp2_impl::get_mimo_locked, this, mb)); + _tree->create<sensor_value_t>(mb_path / "sensors/ref_locked") + .publish(boost::bind(&usrp2_impl::get_ref_locked, this, mb)); + + //////////////////////////////////////////////////////////////// + // create frontend control objects + //////////////////////////////////////////////////////////////// + _mbc[mb].rx_fe = rx_frontend_core_200::make( + _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_FRONT) + ); + _mbc[mb].tx_fe = tx_frontend_core_200::make( + _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_FRONT) + ); + //TODO lots of properties to expose here for frontends + _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec") + .coerce(boost::bind(&usrp2_impl::update_rx_subdev_spec, this, mb, _1)); + _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec") + .coerce(boost::bind(&usrp2_impl::update_tx_subdev_spec, this, mb, _1)); + + //////////////////////////////////////////////////////////////// + // create rx dsp control objects + //////////////////////////////////////////////////////////////// + _mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make( + _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), USRP2_RX_SID_BASE + 0, true )); - //use an empty name when there is only one mboard - std::string name = (device_args.size() > 1)? boost::lexical_cast<std::string>(i) : ""; - _mboard_dict[name] = _mboards.back(); + _mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make( + _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), USRP2_RX_SID_BASE + 1, true + )); + for (size_t dspno = 0; dspno < _mbc[mb].rx_dsps.size(); dspno++){ + _mbc[mb].rx_dsps[dspno]->set_link_rate(USRP2_LINK_RATE_BPS); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _mbc[mb].rx_dsps[dspno], _1)); + //This is a hack/fix for the lingering packet problem. + //The dsp core starts streaming briefly... now we flush + _mbc[mb].rx_dsp_xports[dspno]->get_recv_buff(0.01).get(); //recv with timeout for lingering + _mbc[mb].rx_dsp_xports[dspno]->get_recv_buff(0.01).get(); //recv with timeout for expected + property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno); + _tree->create<double>(rx_dsp_path / "rate/value") + .coerce(boost::bind(&rx_dsp_core_200::set_host_rate, _mbc[mb].rx_dsps[dspno], _1)) + .subscribe(boost::bind(&usrp2_impl::update_rx_samp_rate, this, _1)); + _tree->create<double>(rx_dsp_path / "freq/value") + .coerce(boost::bind(&rx_dsp_core_200::set_freq, _mbc[mb].rx_dsps[dspno], _1)); + _tree->create<meta_range_t>(rx_dsp_path / "freq/range") + .publish(boost::bind(&rx_dsp_core_200::get_freq_range, _mbc[mb].rx_dsps[dspno])); + _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd") + .subscribe(boost::bind(&rx_dsp_core_200::issue_stream_command, _mbc[mb].rx_dsps[dspno], _1)); + } + + //////////////////////////////////////////////////////////////// + // create tx dsp control objects + //////////////////////////////////////////////////////////////// + _mbc[mb].tx_dsp = tx_dsp_core_200::make( + _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_DSP), U2_REG_SR_ADDR(SR_TX_CTRL), USRP2_TX_ASYNC_SID + ); + _mbc[mb].tx_dsp->set_link_rate(USRP2_LINK_RATE_BPS); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _mbc[mb].tx_dsp, _1)); + _tree->create<double>(mb_path / "tx_dsps/0/rate/value") + .coerce(boost::bind(&tx_dsp_core_200::set_host_rate, _mbc[mb].tx_dsp, _1)) + .subscribe(boost::bind(&usrp2_impl::update_tx_samp_rate, this, _1)); + _tree->create<double>(mb_path / "tx_dsps/0/freq/value") + .coerce(boost::bind(&usrp2_impl::set_tx_dsp_freq, this, mb, _1)); + _tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range") + .publish(boost::bind(&usrp2_impl::get_tx_dsp_freq_range, this, mb)); + + //setup dsp flow control + const double ups_per_sec = device_args_i.cast<double>("ups_per_sec", 20); + const size_t send_frame_size = _mbc[mb].tx_dsp_xport->get_send_frame_size(); + const double ups_per_fifo = device_args_i.cast<double>("ups_per_fifo", 8.0); + _mbc[mb].tx_dsp->set_updates( + (ups_per_sec > 0.0)? size_t(100e6/*approx tick rate*//ups_per_sec) : 0, + (ups_per_fifo > 0.0)? size_t(USRP2_SRAM_BYTES/ups_per_fifo/send_frame_size) : 0 + ); + + //////////////////////////////////////////////////////////////// + // create time control objects + //////////////////////////////////////////////////////////////// + time64_core_200::readback_bases_type time64_rb_bases; + time64_rb_bases.rb_secs_now = U2_REG_TIME64_SECS_RB_IMM; + time64_rb_bases.rb_ticks_now = U2_REG_TIME64_TICKS_RB_IMM; + time64_rb_bases.rb_secs_pps = U2_REG_TIME64_SECS_RB_PPS; + time64_rb_bases.rb_ticks_pps = U2_REG_TIME64_TICKS_RB_PPS; + _mbc[mb].time64 = time64_core_200::make( + _mbc[mb].iface, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles + ); + _tree->access<double>(mb_path / "tick_rate") + .subscribe(boost::bind(&time64_core_200::set_tick_rate, _mbc[mb].time64, _1)); + _tree->create<time_spec_t>(mb_path / "time/now") + .publish(boost::bind(&time64_core_200::get_time_now, _mbc[mb].time64)) + .subscribe(boost::bind(&time64_core_200::set_time_now, _mbc[mb].time64, _1)); + _tree->create<time_spec_t>(mb_path / "time/pps") + .publish(boost::bind(&time64_core_200::get_time_last_pps, _mbc[mb].time64)) + .subscribe(boost::bind(&time64_core_200::set_time_next_pps, _mbc[mb].time64, _1)); + //setup time source props + _tree->create<std::string>(mb_path / "time_source/value") + .subscribe(boost::bind(&time64_core_200::set_time_source, _mbc[mb].time64, _1)); + _tree->create<std::vector<std::string> >(mb_path / "time_source/options") + .publish(boost::bind(&time64_core_200::get_time_sources, _mbc[mb].time64)); + //setup reference source props + _tree->create<std::string>(mb_path / "clock_source/value") + .subscribe(boost::bind(&usrp2_impl::update_clock_source, this, mb, _1)); + static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("mimo"); + _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources); + + //////////////////////////////////////////////////////////////// + // create dboard control objects + //////////////////////////////////////////////////////////////// + + //read the dboard eeprom to extract the dboard ids + dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom; + rx_db_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_RX_DB); + tx_db_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB); + gdb_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB ^ 5); + + //create the properties and register subscribers + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/rx_eeprom") + .set(rx_db_eeprom) + .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "rx", _1)); + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/tx_eeprom") + .set(tx_db_eeprom) + .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "tx", _1)); + _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/gdb_eeprom") + .set(gdb_eeprom) + .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "gdb", _1)); + + //create a new dboard interface and manager + _mbc[mb].dboard_iface = make_usrp2_dboard_iface(_mbc[mb].iface, _mbc[mb].clock); + _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_mbc[mb].dboard_iface); + _mbc[mb].dboard_manager = dboard_manager::make( + rx_db_eeprom.id, + ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id, + _mbc[mb].dboard_iface + ); + BOOST_FOREACH(const std::string &name, _mbc[mb].dboard_manager->get_rx_subdev_names()){ + dboard_manager::populate_prop_tree_from_subdev( + _tree->subtree(mb_path / "dboards/A/rx_frontends" / name), + _mbc[mb].dboard_manager->get_rx_subdev(name) + ); + } + BOOST_FOREACH(const std::string &name, _mbc[mb].dboard_manager->get_tx_subdev_names()){ + dboard_manager::populate_prop_tree_from_subdev( + _tree->subtree(mb_path / "dboards/A/tx_frontends" / name), + _mbc[mb].dboard_manager->get_tx_subdev(name) + ); + } } - //init the send and recv io - io_init(); + //initialize io handling + this->io_init(); + + //do some post-init tasks + BOOST_FOREACH(const std::string &mb, _mbc.keys()){ + property_tree::path_type root = "/mboards/" + mb; + _tree->access<double>(root / "tick_rate").update(); + + //and now that the tick rate is set, init the host rates to something + BOOST_FOREACH(const std::string &name, _tree->list(root / "rx_dsps")){ + _tree->access<double>(root / "rx_dsps" / name / "rate" / "value").set(1e6); + } + BOOST_FOREACH(const std::string &name, _tree->list(root / "tx_dsps")){ + _tree->access<double>(root / "tx_dsps" / name / "rate" / "value").set(1e6); + } + + _tree->access<subdev_spec_t>(root / "rx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_rx_subdev_names()[0])); + _tree->access<subdev_spec_t>(root / "tx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_tx_subdev_names()[0])); + _tree->access<std::string>(root / "clock_source/value").set("internal"); + _tree->access<std::string>(root / "time_source/value").set("none"); + + //GPS installed: use external ref, time, and init time spec + if (_mbc[mb].gps.get() != NULL){ + _tree->access<std::string>(root / "time_source/value").set("external"); + _tree->access<std::string>(root / "clock_source/value").set("external"); + _mbc[mb].time64->set_time_next_pps(time_spec_t(time_t(_mbc[mb].gps->get_sensor("gps_time").to_int()+1))); + } + } } -usrp2_impl::~usrp2_impl(void){ - /* NOP */ +usrp2_impl::~usrp2_impl(void){UHD_SAFE_CALL( + BOOST_FOREACH(const std::string &mb, _mbc.keys()){ + _mbc[mb].tx_dsp->set_updates(0, 0); + } +)} + +void usrp2_impl::set_mb_eeprom(const std::string &mb, const uhd::usrp::mboard_eeprom_t &mb_eeprom){ + mb_eeprom.commit(*(_mbc[mb].iface), mboard_eeprom_t::MAP_N100); } -/*********************************************************************** - * Device Properties - **********************************************************************/ -void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); +void usrp2_impl::set_db_eeprom(const std::string &mb, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){ + if (type == "rx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_RX_DB); + if (type == "tx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB); + if (type == "gdb") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB ^ 5); +} + +sensor_value_t usrp2_impl::get_mimo_locked(const std::string &mb){ + const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<10)) != 0; + return sensor_value_t("MIMO", lock, "locked", "unlocked"); +} - //handle the get request conditioned on the key - switch(key.as<device_prop_t>()){ - case DEVICE_PROP_NAME: - if (_mboards.size() > 1) val = std::string("USRP2/N Series multi-device"); - else val = std::string("USRP2/N Series device"); - return; +sensor_value_t usrp2_impl::get_ref_locked(const std::string &mb){ + const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<11)) != 0; + return sensor_value_t("Ref", lock, "locked", "unlocked"); +} - case DEVICE_PROP_MBOARD: - val = _mboard_dict[key.name]->get_link(); - return; +#include <boost/math/special_functions/round.hpp> +#include <boost/math/special_functions/sign.hpp> - case DEVICE_PROP_MBOARD_NAMES: - val = prop_names_t(_mboard_dict.keys()); - return; +double usrp2_impl::set_tx_dsp_freq(const std::string &mb, const double freq_){ + double new_freq = freq_; + const double tick_rate = _tree->access<double>("/mboards/"+mb+"/tick_rate").get(); - default: UHD_THROW_PROP_GET_ERROR(); - } + //calculate the DAC shift (multiples of rate) + const int sign = boost::math::sign(new_freq); + const int zone = std::min(boost::math::iround(new_freq/tick_rate), 2); + const double dac_shift = sign*zone*tick_rate; + new_freq -= dac_shift; //update FPGA DSP target freq + + //set the DAC shift (modulation mode) + if (zone == 0) _mbc[mb].codec->set_tx_mod_mode(0); //no shift + else _mbc[mb].codec->set_tx_mod_mode(sign*4/zone); //DAC interp = 4 + + return _mbc[mb].tx_dsp->set_freq(new_freq) + dac_shift; //actual freq } -void usrp2_impl::set(const wax::obj &, const wax::obj &){ - UHD_THROW_PROP_SET_ERROR(); +meta_range_t usrp2_impl::get_tx_dsp_freq_range(const std::string &mb){ + const double tick_rate = _tree->access<double>("/mboards/"+mb+"/tick_rate").get(); + const meta_range_t dsp_range = _mbc[mb].tx_dsp->get_freq_range(); + return meta_range_t(dsp_range.start() - tick_rate*2, dsp_range.stop() + tick_rate*2, dsp_range.step()); +} + +void usrp2_impl::update_clock_source(const std::string &mb, const std::string &source){ + //clock source ref 10mhz + switch(_mbc[mb].iface->get_rev()){ + case usrp2_iface::USRP_N200: + case usrp2_iface::USRP_N210: + case usrp2_iface::USRP_N200_R4: + case usrp2_iface::USRP_N210_R4: + if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12); + else if (source == "external") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); + else if (source == "mimo") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); + else throw uhd::value_error("unhandled clock configuration reference source: " + source); + _mbc[mb].clock->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO + break; + + case usrp2_iface::USRP2_REV3: + case usrp2_iface::USRP2_REV4: + if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10); + else if (source == "external") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); + else if (source == "mimo") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); + else throw uhd::value_error("unhandled clock configuration reference source: " + source); + _mbc[mb].clock->enable_external_ref(source != "internal"); + break; + + case usrp2_iface::USRP_NXXX: break; + } + + //always drive the clock over serdes if not locking to it + _mbc[mb].clock->enable_mimo_clock_out(source != "mimo"); + + //set the mimo clock delay over the serdes + if (source != "mimo"){ + switch(_mbc[mb].iface->get_rev()){ + case usrp2_iface::USRP_N200: + case usrp2_iface::USRP_N210: + case usrp2_iface::USRP_N200_R4: + case usrp2_iface::USRP_N210_R4: + _mbc[mb].clock->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx); + break; + + case usrp2_iface::USRP2_REV4: + _mbc[mb].clock->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4); + break; + + default: break; //not handled + } + } } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 4d19863b1..644eab824 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -21,6 +21,12 @@ #include "usrp2_iface.hpp" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" +#include "rx_frontend_core_200.hpp" +#include "tx_frontend_core_200.hpp" +#include "rx_dsp_core_200.hpp" +#include "tx_dsp_core_200.hpp" +#include "time64_core_200.hpp" +#include <uhd/property_tree.hpp> #include <uhd/usrp/gps_ctrl.hpp> #include <uhd/device.hpp> #include <uhd/utils/pimpl.hpp> @@ -37,6 +43,14 @@ #include <uhd/usrp/dboard_manager.hpp> #include <uhd/usrp/subdev_spec.hpp> +static const double USRP2_LINK_RATE_BPS = 1000e6/8; +static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9; +static const double mimo_clock_delay_usrp_n2xx = 3.55e-9; +static const size_t mimo_clock_sync_delay_cycles = 137; +static const size_t USRP2_SRAM_BYTES = size_t(1 << 20); +static const boost::uint32_t USRP2_TX_ASYNC_SID = 2; +static const boost::uint32_t USRP2_RX_SID_BASE = 3; + /*! * Make a usrp2 dboard interface. * \param iface the usrp2 interface object @@ -49,139 +63,13 @@ uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface( ); /*! - * Simple wax obj proxy class: - * Provides a wax obj interface for a set and a get function. - * This allows us to create nested properties structures - * while maintaining flattened code within the implementation. - */ -class wax_obj_proxy : public wax::obj{ -public: - typedef boost::function<void(const wax::obj &, wax::obj &)> get_t; - typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t; - typedef boost::shared_ptr<wax_obj_proxy> sptr; - - static sptr make(const get_t &get, const set_t &set){ - return sptr(new wax_obj_proxy(get, set)); - } - -private: - get_t _get; set_t _set; - wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set){}; - void get(const wax::obj &key, wax::obj &val){return _get(key, val);} - void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} -}; - -class usrp2_impl; - -/*! - * USRP2 mboard implementation guts: - * The implementation details are encapsulated here. - * Handles properties on the mboard, dboard, dsps... - */ -class usrp2_mboard_impl : public wax::obj{ -public: - typedef boost::shared_ptr<usrp2_mboard_impl> sptr; - - static const size_t NUM_RX_DSPS = 2; - static const size_t NUM_TX_DSPS = 1; - static const size_t MAX_NUM_DSPS = 2; - - //structors - usrp2_mboard_impl( - const uhd::device_addr_t &device_addr, - size_t index, usrp2_impl &device - ); - ~usrp2_mboard_impl(void); - - inline double get_master_clock_freq(void){ - return _clock_ctrl->get_master_clock_rate(); - } - - void handle_overflow(size_t); - -private: - size_t _index; - usrp2_impl &_device; - bool _mimo_clocking_mode_is_master; - - //interfaces - usrp2_iface::sptr _iface; - usrp2_clock_ctrl::sptr _clock_ctrl; - usrp2_codec_ctrl::sptr _codec_ctrl; - gps_ctrl::sptr _gps_ctrl; - - //properties for this mboard - void get(const wax::obj &, wax::obj &); - void set(const wax::obj &, const wax::obj &); - uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec; - - //rx and tx dboard methods and objects - uhd::usrp::dboard_manager::sptr _dboard_manager; - uhd::usrp::dboard_iface::sptr _dboard_iface; - void dboard_init(void); - - //methods and shadows for clock configuration - uhd::clock_config_t _clock_config; - void update_clock_config(void); - void set_time_spec(const uhd::time_spec_t &time_spec, bool now); - - //properties interface for the codec - void codec_init(void); - void rx_codec_get(const wax::obj &, wax::obj &); - void rx_codec_set(const wax::obj &, const wax::obj &); - void tx_codec_get(const wax::obj &, wax::obj &); - void tx_codec_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _rx_codec_proxy; - wax_obj_proxy::sptr _tx_codec_proxy; - - void rx_codec_set_gain(double, const std::string &); - uhd::dict<std::string, double> _codec_rx_gains; - - //properties interface for rx dboard - void rx_dboard_get(const wax::obj &, wax::obj &); - void rx_dboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _rx_dboard_proxy; - uhd::usrp::dboard_eeprom_t _rx_db_eeprom; - - //properties interface for tx dboard - void tx_dboard_get(const wax::obj &, wax::obj &); - void tx_dboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _tx_dboard_proxy; - uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom; - - //methods and shadows for the dsps - UHD_PIMPL_DECL(dsp_impl) _dsp_impl; - void dsp_init(void); - void issue_ddc_stream_cmd(const uhd::stream_cmd_t &, size_t); - - //properties interface for ddc - void ddc_get(const wax::obj &, wax::obj &, size_t); - void ddc_set(const wax::obj &, const wax::obj &, size_t); - uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dsp_proxies; - - //properties interface for duc - void duc_get(const wax::obj &, wax::obj &, size_t); - void duc_set(const wax::obj &, const wax::obj &, size_t); - uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsp_proxies; - - //sensors methods for mboard - bool get_mimo_locked(void); - bool get_ref_locked(void); -}; - -/*! * USRP2 implementation guts: * The implementation details are encapsulated here. * Handles device properties and streaming... */ class usrp2_impl : public uhd::device{ public: - static const size_t sram_bytes = size_t(1 << 20); - static const boost::uint32_t RECV_SID = 1; - static const boost::uint32_t ASYNC_SID = 2; - usrp2_impl(const uhd::device_addr_t &); - ~usrp2_impl(void); //the io interface @@ -199,27 +87,50 @@ public: size_t get_max_recv_samps_per_packet(void) const; bool recv_async_msg(uhd::async_metadata_t &, double); - void update_xport_channel_mapping(void); - - //public frame sizes, set by mboard, used by io impl - size_t recv_frame_size, send_frame_size; - - std::vector<uhd::transport::zero_copy_if::sptr> dsp_xports; - std::vector<uhd::transport::zero_copy_if::sptr> err_xports; - private: - //device properties interface - void get(const wax::obj &, wax::obj &); - void set(const wax::obj &, const wax::obj &); + uhd::property_tree::sptr _tree; + struct mb_container_type{ + usrp2_iface::sptr iface; + usrp2_clock_ctrl::sptr clock; + usrp2_codec_ctrl::sptr codec; + gps_ctrl::sptr gps; + rx_frontend_core_200::sptr rx_fe; + tx_frontend_core_200::sptr tx_fe; + std::vector<rx_dsp_core_200::sptr> rx_dsps; + tx_dsp_core_200::sptr tx_dsp; + time64_core_200::sptr time64; + std::vector<uhd::transport::zero_copy_if::sptr> rx_dsp_xports; + uhd::transport::zero_copy_if::sptr tx_dsp_xport; + uhd::usrp::dboard_manager::sptr dboard_manager; + uhd::usrp::dboard_iface::sptr dboard_iface; + size_t rx_chan_occ, tx_chan_occ; + }; + uhd::dict<std::string, mb_container_type> _mbc; + + void set_mb_eeprom(const std::string &, const uhd::usrp::mboard_eeprom_t &); + void set_db_eeprom(const std::string &, const std::string &, const uhd::usrp::dboard_eeprom_t &); + + uhd::sensor_value_t get_mimo_locked(const std::string &); + uhd::sensor_value_t get_ref_locked(const std::string &); - //pointers to mboards on this device (think mimo setup) - std::vector<usrp2_mboard_impl::sptr> _mboards; - uhd::dict<std::string, usrp2_mboard_impl::sptr> _mboard_dict; + //device properties interface + void get(const wax::obj &, wax::obj &val){ + val = _tree; //entry point into property tree + } //io impl methods and members uhd::otw_type_t _rx_otw_type, _tx_otw_type; UHD_PIMPL_DECL(io_impl) _io_impl; void io_init(void); + void update_tick_rate(const double rate); + void update_rx_samp_rate(const double rate); + void update_tx_samp_rate(const double rate); + //update spec methods are coercers until we only accept db_name == A + uhd::usrp::subdev_spec_t update_rx_subdev_spec(const std::string &, const uhd::usrp::subdev_spec_t &); + uhd::usrp::subdev_spec_t update_tx_subdev_spec(const std::string &, const uhd::usrp::subdev_spec_t &); + double set_tx_dsp_freq(const std::string &, const double); + uhd::meta_range_t get_tx_dsp_freq_range(const std::string &); + void update_clock_source(const std::string &, const std::string &); }; #endif /* INCLUDED_USRP2_IMPL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index dbb78275b..555e4a3e7 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -54,6 +54,8 @@ #define U2_REG_SR_ADDR(sr) (SETTING_REGS_BASE + (4 * (sr))) +#define U2_REG_ROUTER_CTRL_PORTS U2_REG_SR_ADDR(SR_BUF_POOL) + 8 + ///////////////////////////////////////////////// // SPI Slave Constants //////////////////////////////////////////////// @@ -90,25 +92,6 @@ #define U2_FLAG_MISC_CTRL_ADC_OFF 0x00 ///////////////////////////////////////////////// -// VITA49 64 bit time (write only) -//////////////////////////////////////////////// -#define U2_REG_TIME64_SECS U2_REG_SR_ADDR(SR_TIME64 + 0) -#define U2_REG_TIME64_TICKS U2_REG_SR_ADDR(SR_TIME64 + 1) -#define U2_REG_TIME64_FLAGS U2_REG_SR_ADDR(SR_TIME64 + 2) -#define U2_REG_TIME64_IMM U2_REG_SR_ADDR(SR_TIME64 + 3) -#define U2_REG_TIME64_TPS U2_REG_SR_ADDR(SR_TIME64 + 4) -#define U2_REG_TIME64_MIMO_SYNC U2_REG_SR_ADDR(SR_TIME64 + 5) - -//pps flags (see above) -#define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0) -#define U2_FLAG_TIME64_PPS_POSEDGE (1 << 0) -#define U2_FLAG_TIME64_PPS_SMA (0 << 1) -#define U2_FLAG_TIME64_PPS_MIMO (1 << 1) - -#define U2_FLAG_TIME64_LATCH_NOW 1 -#define U2_FLAG_TIME64_LATCH_NEXT_PPS 0 - -///////////////////////////////////////////////// // Readback regs //////////////////////////////////////////////// #define U2_REG_STATUS READBACK_BASE + 4*8 @@ -119,26 +102,6 @@ #define U2_REG_TIME64_SECS_RB_PPS READBACK_BASE + 4*14 #define U2_REG_TIME64_TICKS_RB_PPS READBACK_BASE + 4*15 -///////////////////////////////////////////////// -// DSP TX Regs -//////////////////////////////////////////////// -#define U2_REG_DSP_TX_FREQ U2_REG_SR_ADDR(SR_TX_DSP + 0) -#define U2_REG_DSP_TX_SCALE_IQ U2_REG_SR_ADDR(SR_TX_DSP + 1) -#define U2_REG_DSP_TX_INTERP_RATE U2_REG_SR_ADDR(SR_TX_DSP + 2) -#define U2_REG_DSP_TX_MUX U2_REG_SR_ADDR(SR_TX_DSP + 4) - -///////////////////////////////////////////////// -// DSP RX Regs -//////////////////////////////////////////////// -#define U2_REG_DSP_RX_HELPER(which, offset) ((which == 0)? \ - (U2_REG_SR_ADDR(SR_RX_DSP0 + offset)) : \ - (U2_REG_SR_ADDR(SR_RX_DSP1 + offset))) - -#define U2_REG_DSP_RX_FREQ(which) U2_REG_DSP_RX_HELPER(which, 0) -#define U2_REG_DSP_RX_SCALE_IQ(which) U2_REG_DSP_RX_HELPER(which, 1) -#define U2_REG_DSP_RX_DECIM(which) U2_REG_DSP_RX_HELPER(which, 2) -#define U2_REG_DSP_RX_MUX(which) U2_REG_DSP_RX_HELPER(which, 5) - //////////////////////////////////////////////// // GPIO //////////////////////////////////////////////// @@ -165,38 +128,4 @@ #define U2_REG_ATR_FULL_TXSIDE ATR_BASE + 12 #define U2_REG_ATR_FULL_RXSIDE ATR_BASE + 14 -/////////////////////////////////////////////////// -// RX CTRL regs -/////////////////////////////////////////////////// -#define U2_REG_RX_CTRL_HELPER(which, offset) ((which == 0)? \ - (U2_REG_SR_ADDR(SR_RX_CTRL0 + offset)) : \ - (U2_REG_SR_ADDR(SR_RX_CTRL1 + offset))) - -#define U2_REG_RX_CTRL_STREAM_CMD(which) U2_REG_RX_CTRL_HELPER(which, 0) -#define U2_REG_RX_CTRL_TIME_SECS(which) U2_REG_RX_CTRL_HELPER(which, 1) -#define U2_REG_RX_CTRL_TIME_TICKS(which) U2_REG_RX_CTRL_HELPER(which, 2) -#define U2_REG_RX_CTRL_CLEAR(which) U2_REG_RX_CTRL_HELPER(which, 3) -#define U2_REG_RX_CTRL_VRT_HDR(which) U2_REG_RX_CTRL_HELPER(which, 4) -#define U2_REG_RX_CTRL_VRT_SID(which) U2_REG_RX_CTRL_HELPER(which, 5) -#define U2_REG_RX_CTRL_VRT_TLR(which) U2_REG_RX_CTRL_HELPER(which, 6) -#define U2_REG_RX_CTRL_NSAMPS_PP(which) U2_REG_RX_CTRL_HELPER(which, 7) -#define U2_REG_RX_CTRL_NCHANNELS(which) U2_REG_RX_CTRL_HELPER(which, 8) - -/////////////////////////////////////////////////// -// TX CTRL regs -/////////////////////////////////////////////////// -#define U2_REG_TX_CTRL_NUM_CHAN U2_REG_SR_ADDR(SR_TX_CTRL + 0) -#define U2_REG_TX_CTRL_CLEAR_STATE U2_REG_SR_ADDR(SR_TX_CTRL + 1) -#define U2_REG_TX_CTRL_REPORT_SID U2_REG_SR_ADDR(SR_TX_CTRL + 2) -#define U2_REG_TX_CTRL_POLICY U2_REG_SR_ADDR(SR_TX_CTRL + 3) -#define U2_REG_TX_CTRL_CYCLES_PER_UP U2_REG_SR_ADDR(SR_TX_CTRL + 4) -#define U2_REG_TX_CTRL_PACKETS_PER_UP U2_REG_SR_ADDR(SR_TX_CTRL + 5) - -#define U2_FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0) -#define U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1) -#define U2_FLAG_TX_CTRL_POLICY_NEXT_BURST (0x1 << 2) - -//enable flag for registers: cycles and packets per update packet -#define U2_FLAG_TX_CTRL_UP_ENB (1ul << 31) - #endif /* INCLUDED_USRP2_REGS_HPP */ diff --git a/host/lib/usrp/usrp_e100/codec_impl.cpp b/host/lib/usrp/usrp_e100/codec_impl.cpp deleted file mode 100644 index ae198aaa5..000000000 --- a/host/lib/usrp/usrp_e100/codec_impl.cpp +++ /dev/null @@ -1,149 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp_e100_impl.hpp" -#include <uhd/exception.hpp> -#include <uhd/usrp/codec_props.hpp> -#include <boost/bind.hpp> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Helper Methods - **********************************************************************/ -void usrp_e100_impl::codec_init(void){ - //make proxies - _rx_codec_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::rx_codec_get, this, _1, _2), - boost::bind(&usrp_e100_impl::rx_codec_set, this, _1, _2) - ); - _tx_codec_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::tx_codec_get, this, _1, _2), - boost::bind(&usrp_e100_impl::tx_codec_set, this, _1, _2) - ); -} - -/*********************************************************************** - * RX Codec Properties - **********************************************************************/ -static const std::string ad9862_pga_gain_name = "ad9862 pga"; - -void usrp_e100_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_NAME: - val = std::string("usrp-e adc - ad9522"); - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - val = prop_names_t(1, ad9862_pga_gain_name); - return; - - case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = usrp_e100_codec_ctrl::rx_pga_gain_range; - return; - - case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_rx_pga_gain('A'); - return; - - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_rx_pga_gain('B'); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp_e100_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the set request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'A'); - return; - - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'B'); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX Codec Properties - **********************************************************************/ -void usrp_e100_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_NAME: - val = std::string("usrp-e dac - ad9522"); - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - val = prop_names_t(1, ad9862_pga_gain_name); - return; - - case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = usrp_e100_codec_ctrl::tx_pga_gain_range; - return; - - case CODEC_PROP_GAIN_I: //only one gain for I and Q - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_tx_pga_gain(); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp_e100_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the set request conditioned on the key - switch(key.as<codec_prop_t>()){ - case CODEC_PROP_GAIN_I: //only one gain for I and Q - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_tx_pga_gain(val.as<double>()); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp_e100/dboard_impl.cpp b/host/lib/usrp/usrp_e100/dboard_impl.cpp deleted file mode 100644 index f6bbbd5e8..000000000 --- a/host/lib/usrp/usrp_e100/dboard_impl.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp_e100_impl.hpp" -#include "usrp_e100_regs.hpp" -#include <uhd/exception.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/usrp/misc_utils.hpp> -#include <boost/bind.hpp> -#include <iostream> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Dboard Initialization - **********************************************************************/ -void usrp_e100_impl::dboard_init(void){ - //read the dboard eeprom to extract the dboard ids - _rx_db_eeprom.load(*_iface, I2C_ADDR_RX_DB); - _tx_db_eeprom.load(*_iface, I2C_ADDR_TX_DB); - _gdb_eeprom.load(*_iface, I2C_ADDR_TX_DB ^ 5); - - //create a new dboard interface and manager - _dboard_iface = make_usrp_e100_dboard_iface( - _iface, _clock_ctrl, _codec_ctrl - ); - _dboard_manager = dboard_manager::make( - _rx_db_eeprom.id, - ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id, - _dboard_iface - ); - - //setup the dboard proxies - _rx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::rx_dboard_get, this, _1, _2), - boost::bind(&usrp_e100_impl::rx_dboard_set, this, _1, _2) - ); - _tx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::tx_dboard_get, this, _1, _2), - boost::bind(&usrp_e100_impl::tx_dboard_set, this, _1, _2) - ); -} - -/*********************************************************************** - * RX Dboard Get - **********************************************************************/ -void usrp_e100_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_NAME: - val = std::string("usrp-e dboard (rx unit)"); - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_rx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_rx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _rx_db_eeprom; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; - return; - - case DBOARD_PROP_CODEC: - val = _rx_codec_proxy->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _rx_db_eeprom.id, - _dboard_manager->get_rx_subdev(key.name), - _rx_codec_proxy->get_link(), - GAIN_GROUP_POLICY_RX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * RX Dboard Set - **********************************************************************/ -void usrp_e100_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_DBOARD_EEPROM: - _rx_db_eeprom = val.as<dboard_eeprom_t>(); - _rx_db_eeprom.store(*_iface, I2C_ADDR_RX_DB); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX Dboard Get - **********************************************************************/ -void usrp_e100_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_NAME: - val = std::string("usrp-e dboard (tx unit)"); - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_tx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_tx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _tx_db_eeprom; - return; - - case DBOARD_PROP_GBOARD_EEPROM: - val = _gdb_eeprom; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; - return; - - case DBOARD_PROP_CODEC: - val = _tx_codec_proxy->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _tx_db_eeprom.id, - _dboard_manager->get_tx_subdev(key.name), - _tx_codec_proxy->get_link(), - GAIN_GROUP_POLICY_TX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * TX Dboard Set - **********************************************************************/ -void usrp_e100_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ - switch(key.as<dboard_prop_t>()){ - case DBOARD_PROP_DBOARD_EEPROM: - _tx_db_eeprom = val.as<dboard_eeprom_t>(); - _tx_db_eeprom.store(*_iface, I2C_ADDR_TX_DB); - return; - - case DBOARD_PROP_GBOARD_EEPROM: - _gdb_eeprom = val.as<dboard_eeprom_t>(); - _gdb_eeprom.store(*_iface, I2C_ADDR_TX_DB ^ 5); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp_e100/dsp_impl.cpp b/host/lib/usrp/usrp_e100/dsp_impl.cpp deleted file mode 100644 index 93034b5dc..000000000 --- a/host/lib/usrp/usrp_e100/dsp_impl.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp_e100_impl.hpp" -#include "usrp_e100_regs.hpp" -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/dsp_props.hpp> -#include <boost/math/special_functions/round.hpp> -#include <boost/bind.hpp> - -#define rint boost::math::iround - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * RX DDC Initialization - **********************************************************************/ -void usrp_e100_impl::rx_ddc_init(void){ - _rx_ddc_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::rx_ddc_get, this, _1, _2), - boost::bind(&usrp_e100_impl::rx_ddc_set, this, _1, _2) - ); - - //initial config and update - rx_ddc_set(DSP_PROP_FREQ_SHIFT, double(0)); - rx_ddc_set(DSP_PROP_HOST_RATE, double(16e6)); -} - -/*********************************************************************** - * RX DDC Get - **********************************************************************/ -void usrp_e100_impl::rx_ddc_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_NAME: - val = std::string("usrp-e ddc0"); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); //empty - return; - - case DSP_PROP_FREQ_SHIFT: - val = _ddc_freq; - return; - - case DSP_PROP_CODEC_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_fpga_clock_rate()/_ddc_decim; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * RX DDC Set - **********************************************************************/ -void usrp_e100_impl::rx_ddc_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - - case DSP_PROP_STREAM_CMD: - issue_stream_cmd(val.as<stream_cmd_t>()); - return; - - case DSP_PROP_FREQ_SHIFT:{ - double new_freq = val.as<double>(); - _iface->poke32(UE_REG_DSP_RX_FREQ, - dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate()) - ); - _ddc_freq = new_freq; //shadow - } - return; - - case DSP_PROP_HOST_RATE:{ - //set the decimation - _ddc_decim = rint(_clock_ctrl->get_fpga_clock_rate()/val.as<double>()); - _iface->poke32(UE_REG_DSP_RX_DECIM_RATE, dsp_type1::calc_cic_filter_word(_ddc_decim)); - - //set the scaling - static const boost::int16_t default_rx_scale_iq = 1024; - _iface->poke32(UE_REG_DSP_RX_SCALE_IQ, - dsp_type1::calc_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq) - ); - } - this->update_xport_channel_mapping(); //rate changed -> update - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX DUC Initialization - **********************************************************************/ -void usrp_e100_impl::tx_duc_init(void){ - _tx_duc_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::tx_duc_get, this, _1, _2), - boost::bind(&usrp_e100_impl::tx_duc_set, this, _1, _2) - ); - - //initial config and update - tx_duc_set(DSP_PROP_FREQ_SHIFT, double(0)); - tx_duc_set(DSP_PROP_HOST_RATE, double(16e6)); -} - -/*********************************************************************** - * TX DUC Get - **********************************************************************/ -void usrp_e100_impl::tx_duc_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_NAME: - val = std::string("usrp-e duc0"); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); //empty - return; - - case DSP_PROP_FREQ_SHIFT: - val = _duc_freq; - return; - - case DSP_PROP_CODEC_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_fpga_clock_rate()/_duc_interp; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * TX DUC Set - **********************************************************************/ -void usrp_e100_impl::tx_duc_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as<dsp_prop_t>()){ - - case DSP_PROP_FREQ_SHIFT:{ - double new_freq = val.as<double>(); - _iface->poke32(UE_REG_DSP_TX_FREQ, - dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate()) - ); - _duc_freq = new_freq; //shadow - } - return; - - case DSP_PROP_HOST_RATE:{ - _duc_interp = rint(_clock_ctrl->get_fpga_clock_rate()/val.as<double>()); - - //set the interpolation - _iface->poke32(UE_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_duc_interp)); - - //set the scaling - _iface->poke32(UE_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_duc_interp)); - } - this->update_xport_channel_mapping(); //rate changed -> update - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp_e100/io_impl.cpp b/host/lib/usrp/usrp_e100/io_impl.cpp deleted file mode 100644 index 998a715fe..000000000 --- a/host/lib/usrp/usrp_e100/io_impl.cpp +++ /dev/null @@ -1,315 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "../../transport/super_recv_packet_handler.hpp" -#include "../../transport/super_send_packet_handler.hpp" -#include "usrp_e100_impl.hpp" -#include "usrp_e100_regs.hpp" -#include <uhd/utils/msg.hpp> -#include <uhd/utils/log.hpp> -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/dsp_props.hpp> -#include <uhd/utils/thread_priority.hpp> -#include <uhd/transport/bounded_buffer.hpp> -#include <boost/bind.hpp> -#include <boost/format.hpp> -#include <boost/thread/thread.hpp> -#include <boost/thread/barrier.hpp> -#include <sstream> - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::transport; - -/*********************************************************************** - * Constants - **********************************************************************/ -static const size_t rx_data_inline_sid = 1; -static const size_t tx_async_report_sid = 2; -static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET; -#define fp_recv_debug false - -/*********************************************************************** - * io impl details (internal to this file) - * - pirate crew of 1 - * - bounded buffer - * - thread loop - * - vrt packet handler states - **********************************************************************/ -struct usrp_e100_impl::io_impl{ - io_impl(zero_copy_if::sptr &xport): - data_xport(xport), - recv_pirate_booty(data_xport->get_num_recv_frames()), - async_msg_fifo(100/*messages deep*/) - { - /* NOP */ - } - - ~io_impl(void){ - recv_pirate_crew_raiding = false; - recv_pirate_crew.interrupt_all(); - recv_pirate_crew.join_all(); - } - - managed_recv_buffer::sptr get_recv_buff(double timeout){ - boost::this_thread::disable_interruption di; //disable because the wait can throw - managed_recv_buffer::sptr buff; - recv_pirate_booty.pop_with_timed_wait(buff, timeout); - return buff; //ASSUME buff == NULL when pop times-out - } - - //The data transport is listed first so that it is deconstructed last, - //which is after the states and booty which may hold managed buffers. - //This comment is invalid because its now a reference and not stored here. - zero_copy_if::sptr &data_xport; - - //state management for the vrt packet handler code - sph::recv_packet_handler recv_handler; - sph::send_packet_handler send_handler; - bool continuous_streaming; - - //a pirate's life is the life for me! - void recv_pirate_loop(boost::barrier &, usrp_e100_clock_ctrl::sptr); - bounded_buffer<managed_recv_buffer::sptr> recv_pirate_booty; - bounded_buffer<async_metadata_t> async_msg_fifo; - boost::thread_group recv_pirate_crew; - bool recv_pirate_crew_raiding; -}; - -/*********************************************************************** - * Receive Pirate Loop - * - while raiding, loot for recv buffers - * - put booty into the alignment buffer - **********************************************************************/ -void usrp_e100_impl::io_impl::recv_pirate_loop( - boost::barrier &spawn_barrier, usrp_e100_clock_ctrl::sptr clock_ctrl -){ - recv_pirate_crew_raiding = true; - spawn_barrier.wait(); - set_thread_priority_safe(); - - while(recv_pirate_crew_raiding){ - managed_recv_buffer::sptr buff = this->data_xport->get_recv_buff(); - if (not buff.get()) continue; //ignore timeout/error buffers - - if (fp_recv_debug){ - std::ostringstream ss; - ss << "len " << buff->size() << std::endl; - for (size_t i = 0; i < 9; i++){ - ss << boost::format(" 0x%08x") % buff->cast<const boost::uint32_t *>()[i] << std::endl; - } - ss << std::endl << std::endl; - UHD_LOGV(always) << ss.str(); - } - - try{ - //extract the vrt header packet info - vrt::if_packet_info_t if_packet_info; - if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); - const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>(); - - //handle an rx data packet or inline message - if (uhd::wtohx(vrt_hdr[1]) == rx_data_inline_sid){ //ASSUME has_sid - if (fp_recv_debug) UHD_LOGV(always) << "this is rx_data_inline_sid\n"; - //same number of frames as the data transport -> always immediate - recv_pirate_booty.push_with_wait(buff); - continue; - } - - //unpack the vrt header and process below... - vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info); - - //handle a tx async report message - if (if_packet_info.sid == tx_async_report_sid and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ - if (fp_recv_debug) UHD_LOGV(always) << "this is tx_async_report_sid\n"; - - //fill in the async metadata - async_metadata_t metadata; - metadata.channel = 0; - metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; - metadata.time_spec = time_spec_t( - time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), clock_ctrl->get_fpga_clock_rate() - ); - metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); - - //print the famous U, and push the metadata into the message queue - if (metadata.event_code & underflow_flags) UHD_MSG(fastpath) << "U"; - async_msg_fifo.push_with_pop_on_full(metadata); - continue; - } - - //TODO replace this below with a UHD_MSG(error) - if (fp_recv_debug) UHD_LOGV(always) << "this is unknown packet\n"; - - }catch(const std::exception &e){ - UHD_MSG(error) << "Error (usrp-e recv pirate loop): " << e.what() << std::endl; - } - } -} - -/*********************************************************************** - * Helper Functions - **********************************************************************/ -void usrp_e100_impl::io_init(void){ - //setup otw types - _send_otw_type.width = 16; - _send_otw_type.shift = 0; - _send_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - - _recv_otw_type.width = 16; - _recv_otw_type.shift = 0; - _recv_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - - //setup before the registers (transport called to calculate max spp) - _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_xport)); - - //clear state machines - _iface->poke32(UE_REG_CTRL_RX_CLEAR, 0); - _iface->poke32(UE_REG_CTRL_TX_CLEAR, 0); - - //setup rx data path - _iface->poke32(UE_REG_CTRL_RX_NSAMPS_PER_PKT, get_max_recv_samps_per_packet()); - _iface->poke32(UE_REG_CTRL_RX_NCHANNELS, 1); - _iface->poke32(UE_REG_CTRL_RX_VRT_HEADER, 0 - | (0x1 << 28) //if data with stream id - | (0x1 << 26) //has trailer - | (0x3 << 22) //integer time other - | (0x1 << 20) //fractional time sample count - ); - _iface->poke32(UE_REG_CTRL_RX_VRT_STREAM_ID, rx_data_inline_sid); - _iface->poke32(UE_REG_CTRL_RX_VRT_TRAILER, 0); - - //setup the tx policy - _iface->poke32(UE_REG_CTRL_TX_REPORT_SID, tx_async_report_sid); - _iface->poke32(UE_REG_CTRL_TX_POLICY, UE_FLAG_CTRL_TX_POLICY_NEXT_PACKET); - - //spawn a pirate, yarrr! - boost::barrier spawn_barrier(2); - _io_impl->recv_pirate_crew.create_thread(boost::bind( - &usrp_e100_impl::io_impl::recv_pirate_loop, _io_impl.get(), - boost::ref(spawn_barrier), _clock_ctrl - )); - spawn_barrier.wait(); - //update mapping here since it didnt b4 when io init not called first - update_xport_channel_mapping(); -} - -void usrp_e100_impl::update_xport_channel_mapping(void){ - if (_io_impl.get() == NULL) return; //not inited yet - - //set all of the relevant properties on the handler - boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); - _io_impl->recv_handler.resize(_rx_subdev_spec.size()); - _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le); - _io_impl->recv_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate()); - _io_impl->recv_handler.set_samp_rate(_rx_ddc_proxy->get_link()[DSP_PROP_HOST_RATE].as<double>()); - for (size_t chan = 0; chan < _io_impl->recv_handler.size(); chan++){ - _io_impl->recv_handler.set_xport_chan_get_buff(chan, boost::bind( - &usrp_e100_impl::io_impl::get_recv_buff, _io_impl.get(), _1 - )); - _io_impl->recv_handler.set_overflow_handler(chan, boost::bind( - &usrp_e100_impl::handle_overrun, this, chan - )); - } - _io_impl->recv_handler.set_converter(_recv_otw_type); - - //set all of the relevant properties on the handler - boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); - _io_impl->send_handler.resize(_tx_subdev_spec.size()); - _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le); - _io_impl->send_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate()); - _io_impl->send_handler.set_samp_rate(_tx_duc_proxy->get_link()[DSP_PROP_HOST_RATE].as<double>()); - for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){ - _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind( - &uhd::transport::zero_copy_if::get_send_buff, _io_impl->data_xport, _1 - )); - } - _io_impl->send_handler.set_converter(_send_otw_type); - _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); -} - -void usrp_e100_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd){ - _io_impl->continuous_streaming = (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - _iface->poke32(UE_REG_CTRL_RX_STREAM_CMD, dsp_type1::calc_stream_cmd_word(stream_cmd)); - _iface->poke32(UE_REG_CTRL_RX_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs())); - _iface->poke32(UE_REG_CTRL_RX_TIME_TICKS, stream_cmd.time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate())); -} - -void usrp_e100_impl::handle_overrun(size_t /*chan*/){ - if (_io_impl->continuous_streaming){ - this->issue_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - } -} - -/*********************************************************************** - * Data Send - **********************************************************************/ -size_t usrp_e100_impl::get_max_send_samps_per_packet(void) const{ - static const size_t hdr_size = 0 - + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - - sizeof(vrt::if_packet_info_t().cid) //no class id ever used - ; - size_t bpp = _send_frame_size - hdr_size; - return bpp/_send_otw_type.get_sample_size(); -} - -size_t usrp_e100_impl::send( - const send_buffs_type &buffs, size_t nsamps_per_buff, - const tx_metadata_t &metadata, const io_type_t &io_type, - send_mode_t send_mode, double timeout -){ - return _io_impl->send_handler.send( - buffs, nsamps_per_buff, - metadata, io_type, - send_mode, timeout - ); -} - -/*********************************************************************** - * Data Recv - **********************************************************************/ -size_t usrp_e100_impl::get_max_recv_samps_per_packet(void) const{ - static const size_t hdr_size = 0 - + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer - - sizeof(vrt::if_packet_info_t().cid) //no class id ever used - ; - size_t bpp = _recv_frame_size - hdr_size; - return bpp/_recv_otw_type.get_sample_size(); -} - -size_t usrp_e100_impl::recv( - const recv_buffs_type &buffs, size_t nsamps_per_buff, - rx_metadata_t &metadata, const io_type_t &io_type, - recv_mode_t recv_mode, double timeout -){ - return _io_impl->recv_handler.recv( - buffs, nsamps_per_buff, - metadata, io_type, - recv_mode, timeout - ); -} - -/*********************************************************************** - * Async Recv - **********************************************************************/ -bool usrp_e100_impl::recv_async_msg( - async_metadata_t &async_metadata, double timeout -){ - boost::this_thread::disable_interruption di; //disable because the wait can throw - return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout); -} diff --git a/host/lib/usrp/usrp_e100/mboard_impl.cpp b/host/lib/usrp/usrp_e100/mboard_impl.cpp deleted file mode 100644 index f4b8d79f6..000000000 --- a/host/lib/usrp/usrp_e100/mboard_impl.cpp +++ /dev/null @@ -1,222 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp_e100_impl.hpp" -#include "usrp_e100_regs.hpp" -#include <uhd/utils/msg.hpp> -#include <uhd/exception.hpp> -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/misc_utils.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <boost/bind.hpp> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Mboard Initialization - **********************************************************************/ -void usrp_e100_impl::mboard_init(void){ - _mboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::mboard_get, this, _1, _2), - boost::bind(&usrp_e100_impl::mboard_set, this, _1, _2) - ); - - //init the clock config - _clock_config = clock_config_t::internal(); - update_clock_config(); -} - -void usrp_e100_impl::update_clock_config(void){ - boost::uint32_t pps_flags = 0; - - //translate pps polarity enums - switch(_clock_config.pps_polarity){ - case clock_config_t::PPS_POS: pps_flags |= UE_FLAG_TIME64_PPS_POSEDGE; break; - case clock_config_t::PPS_NEG: pps_flags |= UE_FLAG_TIME64_PPS_NEGEDGE; break; - default: throw uhd::value_error("unhandled clock configuration pps polarity"); - } - - //set the pps flags - _iface->poke32(UE_REG_TIME64_FLAGS, pps_flags); - - //clock source ref 10mhz - switch(_clock_config.ref_source){ - case clock_config_t::REF_AUTO: _clock_ctrl->use_auto_ref(); break; - case clock_config_t::REF_INT: _clock_ctrl->use_internal_ref(); break; - case clock_config_t::REF_SMA: _clock_ctrl->use_auto_ref(); break; - default: throw uhd::value_error("unhandled clock configuration ref source"); - } -} - -/*********************************************************************** - * Mboard Get - **********************************************************************/ -void usrp_e100_impl::mboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<mboard_prop_t>()){ - case MBOARD_PROP_NAME: - val = std::string("usrp-e mboard"); - return; - - case MBOARD_PROP_OTHERS: - val = prop_names_t(); - return; - - case MBOARD_PROP_RX_DBOARD: - UHD_ASSERT_THROW(key.name == ""); - val = _rx_dboard_proxy->get_link(); - return; - - case MBOARD_PROP_RX_DBOARD_NAMES: - val = prop_names_t(1, ""); //vector of size 1 with empty string - return; - - case MBOARD_PROP_TX_DBOARD: - UHD_ASSERT_THROW(key.name == ""); - val = _tx_dboard_proxy->get_link(); - return; - - case MBOARD_PROP_TX_DBOARD_NAMES: - val = prop_names_t(1, ""); //vector of size 1 with empty string - return; - - case MBOARD_PROP_RX_DSP: - UHD_ASSERT_THROW(key.name == ""); - val = _rx_ddc_proxy->get_link(); - return; - - case MBOARD_PROP_RX_DSP_NAMES: - val = prop_names_t(1, ""); - return; - - case MBOARD_PROP_TX_DSP: - UHD_ASSERT_THROW(key.name == ""); - val = _tx_duc_proxy->get_link(); - return; - - case MBOARD_PROP_TX_DSP_NAMES: - val = prop_names_t(1, ""); - return; - - case MBOARD_PROP_CLOCK_CONFIG: - val = _clock_config; - return; - - case MBOARD_PROP_RX_SUBDEV_SPEC: - val = _rx_subdev_spec; - return; - - case MBOARD_PROP_TX_SUBDEV_SPEC: - val = _tx_subdev_spec; - return; - - case MBOARD_PROP_EEPROM_MAP: - val = _iface->mb_eeprom; - return; - - case MBOARD_PROP_TIME_NOW: while(true){ - uint32_t secs = _iface->peek32(UE_REG_RB_TIME_NOW_SECS); - uint32_t ticks = _iface->peek32(UE_REG_RB_TIME_NOW_TICKS); - if (secs != _iface->peek32(UE_REG_RB_TIME_NOW_SECS)) continue; - val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); - return; - } - - case MBOARD_PROP_TIME_PPS: while(true){ - uint32_t secs = _iface->peek32(UE_REG_RB_TIME_PPS_SECS); - uint32_t ticks = _iface->peek32(UE_REG_RB_TIME_PPS_TICKS); - if (secs != _iface->peek32(UE_REG_RB_TIME_PPS_SECS)) continue; - val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); - return; - } - - case MBOARD_PROP_CLOCK_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * Mboard Set - **********************************************************************/ -void usrp_e100_impl::mboard_set(const wax::obj &key, const wax::obj &val){ - //handle the get request conditioned on the key - switch(key.as<mboard_prop_t>()){ - - case MBOARD_PROP_TIME_NOW: - case MBOARD_PROP_TIME_PPS:{ - time_spec_t time_spec = val.as<time_spec_t>(); - _iface->poke32(UE_REG_TIME64_TICKS, time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate())); - boost::uint32_t imm_flags = (key.as<mboard_prop_t>() == MBOARD_PROP_TIME_NOW)? 1 : 0; - _iface->poke32(UE_REG_TIME64_IMM, imm_flags); - _iface->poke32(UE_REG_TIME64_SECS, time_spec.get_full_secs()); - } - return; - - case MBOARD_PROP_RX_SUBDEV_SPEC: - _rx_subdev_spec = val.as<subdev_spec_t>(); - verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link()); - //sanity check - UHD_ASSERT_THROW(_rx_subdev_spec.size() == 1); - //set the mux - _iface->poke32(UE_REG_DSP_RX_MUX, dsp_type1::calc_rx_mux_word( - _dboard_manager->get_rx_subdev(_rx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() - )); - return; - - case MBOARD_PROP_TX_SUBDEV_SPEC: - _tx_subdev_spec = val.as<subdev_spec_t>(); - verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link()); - //sanity check - UHD_ASSERT_THROW(_tx_subdev_spec.size() == 1); - //set the mux - _iface->poke32(UE_REG_DSP_TX_MUX, dsp_type1::calc_tx_mux_word( - _dboard_manager->get_tx_subdev(_tx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() - )); - return; - - case MBOARD_PROP_EEPROM_MAP: - // Step1: commit the map, writing only those values set. - // Step2: readback the entire eeprom map into the iface. - val.as<mboard_eeprom_t>().commit(_iface->get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100); - _iface->mb_eeprom = mboard_eeprom_t(_iface->get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100); - return; - - case MBOARD_PROP_CLOCK_CONFIG: - _clock_config = val.as<clock_config_t>(); - update_clock_config(); - return; - - case MBOARD_PROP_CLOCK_RATE: - UHD_MSG(warning) - << "I see that you are setting the master clock rate from the API.\n" - << "You may pass this into the device address as master_clock_rate=<rate>.\n" - << "This way, the clock rate is guaranteed to be initialized first.\n" - << "See the application notes for USRP-E1XX for further instructions.\n" - ; - _clock_ctrl->set_fpga_clock_rate(val.as<double>()); - this->update_xport_channel_mapping(); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp b/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp deleted file mode 100644 index d9fe96db7..000000000 --- a/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_USRP_E100_IFACE_HPP -#define INCLUDED_USRP_E100_IFACE_HPP - -#include <uhd/transport/udp_simple.hpp> -#include <uhd/usrp/mboard_eeprom.hpp> -#include <uhd/types/serial.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> -#include <boost/cstdint.hpp> -#include <uhd/usrp/mboard_iface.hpp> - -//////////////////////////////////////////////////////////////////////// -// I2C addresses -//////////////////////////////////////////////////////////////////////// -#define I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx -#define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0) -#define I2C_ADDR_TX_DB (I2C_DEV_EEPROM | 0x4) -#define I2C_ADDR_RX_DB (I2C_DEV_EEPROM | 0x5) -//////////////////////////////////////////////////////////////////////// - -/*! - * The usrp-e interface class: - * Provides a set of functions to implementation layer. - * Including spi, peek, poke, control... - */ -class usrp_e100_iface : boost::noncopyable, public uhd::usrp::mboard_iface{ -public: - typedef boost::shared_ptr<usrp_e100_iface> sptr; - - /*! - * Make a new usrp-e interface with the control transport. - * \param node the device node name - * \return a new usrp-e interface object - */ - static sptr make(const std::string &node); - - /*! - * Get the underlying file descriptor. - * \return the file descriptor - */ - virtual int get_file_descriptor(void) = 0; - - /*! - * Perform an ioctl call on the device node file descriptor. - * This will throw when the internal ioctl call fails. - * \param request the control word - * \param mem pointer to some memory - */ - virtual void ioctl(int request, void *mem) = 0; - - //! Get the I2C interface for the I2C device node - virtual uhd::i2c_iface &get_i2c_dev_iface(void) = 0; - - //motherboard eeprom map structure - uhd::usrp::mboard_eeprom_t mb_eeprom; -}; - -#endif /* INCLUDED_USRP_E100_IFACE_HPP */ diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp deleted file mode 100644 index ae0c0b1b7..000000000 --- a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp +++ /dev/null @@ -1,217 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp_e100_impl.hpp" -#include "usrp_e100_regs.hpp" -#include <uhd/utils/msg.hpp> -#include <uhd/usrp/device_props.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/exception.hpp> -#include <uhd/utils/static.hpp> -#include <uhd/utils/images.hpp> -#include <boost/format.hpp> -#include <boost/filesystem.hpp> -#include <boost/functional/hash.hpp> -#include <fstream> - -using namespace uhd; -using namespace uhd::usrp; -namespace fs = boost::filesystem; - -/*********************************************************************** - * Discovery - **********************************************************************/ -static device_addrs_t usrp_e100_find(const device_addr_t &hint){ - device_addrs_t usrp_e100_addrs; - - //return an empty list of addresses when type is set to non-usrp-e - if (hint.has_key("type") and hint["type"] != "e100") return usrp_e100_addrs; - - //device node not provided, assume its 0 - if (not hint.has_key("node")){ - device_addr_t new_addr = hint; - new_addr["node"] = "/dev/usrp_e0"; - return usrp_e100_find(new_addr); - } - - //use the given device node name - if (fs::exists(hint["node"])){ - device_addr_t new_addr; - new_addr["type"] = "usrp-e"; - new_addr["node"] = fs::system_complete(fs::path(hint["node"])).string(); - try{ - usrp_e100_iface::sptr iface = usrp_e100_iface::make(new_addr["node"]); - new_addr["name"] = "";//FIXME for double open on next branch iface->mb_eeprom["name"]; - new_addr["serial"] = "";//FIXME for double open on next branch iface->mb_eeprom["serial"]; - } - catch(const std::exception &e){ - new_addr["name"] = ""; - new_addr["serial"] = ""; - } - if ( - (not hint.has_key("name") or hint["name"] == new_addr["name"]) and - (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]) - ){ - usrp_e100_addrs.push_back(new_addr); - } - } - - return usrp_e100_addrs; -} - -/*********************************************************************** - * Make - **********************************************************************/ -static size_t hash_fpga_file(const std::string &file_path){ - size_t hash = 0; - std::ifstream file(file_path.c_str()); - if (not file.good()) throw uhd::io_error("cannot open fpga file for read: " + file_path); - while (file.good()) boost::hash_combine(hash, file.get()); - file.close(); - return hash; -} - -static device::sptr usrp_e100_make(const device_addr_t &device_addr){ - - //setup the main interface into fpga - std::string node = device_addr["node"]; - UHD_MSG(status) << boost::format("Opening USRP-E on %s") % node << std::endl; - usrp_e100_iface::sptr iface = usrp_e100_iface::make(node); - - //extract the fpga path for usrp-e - std::string usrp_e100_fpga_image = find_image_path(device_addr.get("fpga", "usrp_e100_fpga.bin")); - - //compute a hash of the fpga file - const boost::uint32_t file_hash = boost::uint32_t(hash_fpga_file(usrp_e100_fpga_image)); - - //When the hash does not match: - // - unload the iface to free the node - // - load the fpga configuration file - // - re-open the iface on the node - if (iface->peek32(UE_REG_RB_MISC_TEST32) != file_hash){ - iface.reset(); - usrp_e100_load_fpga(usrp_e100_fpga_image); - sleep(1); ///\todo do this better one day. - UHD_MSG(status) << boost::format("re-Opening USRP-E on %s") % node << std::endl; - iface = usrp_e100_iface::make(node); - } - - //store the hash into the FPGA register - iface->poke32(UE_REG_SR_MISC_TEST32, file_hash); - - //check that the hash can be readback correctly - if (iface->peek32(UE_REG_RB_MISC_TEST32) != file_hash){ - UHD_MSG(error) << boost::format( - "The FPGA hash readback failed!\n" - "The FPGA is either clocked improperly\n" - "or the FPGA build is not compatible.\n" - ); - } - - //check that the compatibility is correct - const boost::uint16_t fpga_compat_num = iface->peek16(UE_REG_MISC_COMPAT); - if (fpga_compat_num != USRP_E_FPGA_COMPAT_NUM){ - throw uhd::runtime_error(str(boost::format( - "\nPlease update the FPGA image for your device.\n" - "See the application notes for USRP E-Series for instructions.\n" - "Expected FPGA compatibility number 0x%x, but got 0x%x:\n" - "The FPGA build is not compatible with the host code build." - ) % USRP_E_FPGA_COMPAT_NUM % fpga_compat_num)); - } - - return device::sptr(new usrp_e100_impl(iface, device_addr)); -} - -UHD_STATIC_BLOCK(register_usrp_e100_device){ - device::register_device(&usrp_e100_find, &usrp_e100_make); -} - -/*********************************************************************** - * Structors - **********************************************************************/ -usrp_e100_impl::usrp_e100_impl( - usrp_e100_iface::sptr iface, - const device_addr_t &device_addr -): - _iface(iface), - _data_xport(usrp_e100_make_mmap_zero_copy(_iface)), - _recv_frame_size(std::min(_data_xport->get_recv_frame_size(), size_t(device_addr.cast<double>("recv_frame_size", 1e9)))), - _send_frame_size(std::min(_data_xport->get_send_frame_size(), size_t(device_addr.cast<double>("send_frame_size", 1e9)))) -{ - - //setup interfaces into hardware - const double master_clock_rate = device_addr.cast<double>("master_clock_rate", 64e6); - _clock_ctrl = usrp_e100_clock_ctrl::make(_iface, master_clock_rate); - _codec_ctrl = usrp_e100_codec_ctrl::make(_iface); - - //initialize the mboard - mboard_init(); - - //initialize the dboards - dboard_init(); - - //initialize the dsps - rx_ddc_init(); - tx_duc_init(); - - //init the codec properties - codec_init(); - - //set default subdev specs - this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t()); - this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t()); - - //init the io send/recv - io_init(); - -} - -usrp_e100_impl::~usrp_e100_impl(void){ - /* NOP */ -} - -/*********************************************************************** - * Device Get - **********************************************************************/ -void usrp_e100_impl::get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the get request conditioned on the key - switch(key.as<device_prop_t>()){ - case DEVICE_PROP_NAME: - val = std::string("usrp-e device"); - return; - - case DEVICE_PROP_MBOARD: - UHD_ASSERT_THROW(key.name == ""); - val = _mboard_proxy->get_link(); - return; - - case DEVICE_PROP_MBOARD_NAMES: - val = prop_names_t(1, ""); //vector of size 1 with empty string - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * Device Set - **********************************************************************/ -void usrp_e100_impl::set(const wax::obj &, const wax::obj &){ - UHD_THROW_PROP_SET_ERROR(); -} diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp deleted file mode 100644 index 1c17863fb..000000000 --- a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp +++ /dev/null @@ -1,173 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "usrp_e100_iface.hpp" -#include "clock_ctrl.hpp" -#include "codec_ctrl.hpp" -#include <uhd/device.hpp> -#include <uhd/utils/pimpl.hpp> -#include <uhd/usrp/subdev_spec.hpp> -#include <uhd/usrp/dboard_eeprom.hpp> -#include <uhd/types/otw_type.hpp> -#include <uhd/types/clock_config.hpp> -#include <uhd/types/stream_cmd.hpp> -#include <uhd/usrp/dboard_manager.hpp> -#include <uhd/transport/zero_copy.hpp> - -#ifndef INCLUDED_USRP_E100_IMPL_HPP -#define INCLUDED_USRP_E100_IMPL_HPP - -uhd::transport::zero_copy_if::sptr usrp_e100_make_mmap_zero_copy(usrp_e100_iface::sptr iface); - -static const boost::uint16_t USRP_E_FPGA_COMPAT_NUM = 0x04; - -//! load an fpga image from a bin file into the usrp-e fpga -extern void usrp_e100_load_fpga(const std::string &bin_file); - -/*! - * Make a usrp-e dboard interface. - * \param iface the usrp-e interface object - * \param clock the clock control interface - * \param codec the codec control interface - * \return a sptr to a new dboard interface - */ -uhd::usrp::dboard_iface::sptr make_usrp_e100_dboard_iface( - usrp_e100_iface::sptr iface, - usrp_e100_clock_ctrl::sptr clock, - usrp_e100_codec_ctrl::sptr codec -); - -/*! - * Simple wax obj proxy class: - * Provides a wax obj interface for a set and a get function. - * This allows us to create nested properties structures - * while maintaining flattened code within the implementation. - */ -class wax_obj_proxy : public wax::obj{ -public: - typedef boost::function<void(const wax::obj &, wax::obj &)> get_t; - typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t; - typedef boost::shared_ptr<wax_obj_proxy> sptr; - - static sptr make(const get_t &get, const set_t &set){ - return sptr(new wax_obj_proxy(get, set)); - } - -private: - get_t _get; set_t _set; - wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set){}; - void get(const wax::obj &key, wax::obj &val){return _get(key, val);} - void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} -}; - -/*! - * USRP-E100 implementation guts: - * The implementation details are encapsulated here. - * Handles properties on the mboard, dboard, dsps... - */ -class usrp_e100_impl : public uhd::device{ -public: - //structors - usrp_e100_impl(usrp_e100_iface::sptr, const uhd::device_addr_t &); - ~usrp_e100_impl(void); - - //the io interface - size_t send(const send_buffs_type &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double); - size_t recv(const recv_buffs_type &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double); - bool recv_async_msg(uhd::async_metadata_t &, double); - size_t get_max_send_samps_per_packet(void) const; - size_t get_max_recv_samps_per_packet(void) const; - -private: - //interface to ioctls and file descriptor - usrp_e100_iface::sptr _iface; - - //handle io stuff - uhd::transport::zero_copy_if::sptr _data_xport; - UHD_PIMPL_DECL(io_impl) _io_impl; - size_t _recv_frame_size, _send_frame_size; - uhd::otw_type_t _send_otw_type, _recv_otw_type; - void io_init(void); - void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd); - void handle_overrun(size_t); - void update_xport_channel_mapping(void); - - //configuration shadows - uhd::clock_config_t _clock_config; - - //ad9522 clock control - usrp_e100_clock_ctrl::sptr _clock_ctrl; - - //ad9862 codec control - usrp_e100_codec_ctrl::sptr _codec_ctrl; - - //device functions and settings - void get(const wax::obj &, wax::obj &); - void set(const wax::obj &, const wax::obj &); - - //mboard functions and settings - void mboard_init(void); - void mboard_get(const wax::obj &, wax::obj &); - void mboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _mboard_proxy; - uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec; - - //xx dboard functions and settings - void dboard_init(void); - uhd::usrp::dboard_manager::sptr _dboard_manager; - uhd::usrp::dboard_iface::sptr _dboard_iface; - - //rx dboard functions and settings - uhd::usrp::dboard_eeprom_t _rx_db_eeprom; - void rx_dboard_get(const wax::obj &, wax::obj &); - void rx_dboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _rx_dboard_proxy; - - //tx dboard functions and settings - uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom; - void tx_dboard_get(const wax::obj &, wax::obj &); - void tx_dboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _tx_dboard_proxy; - - //rx ddc functions and settings - void rx_ddc_init(void); - void rx_ddc_get(const wax::obj &, wax::obj &); - void rx_ddc_set(const wax::obj &, const wax::obj &); - double _ddc_freq; size_t _ddc_decim; - wax_obj_proxy::sptr _rx_ddc_proxy; - - //tx duc functions and settings - void tx_duc_init(void); - void tx_duc_get(const wax::obj &, wax::obj &); - void tx_duc_set(const wax::obj &, const wax::obj &); - double _duc_freq; size_t _duc_interp; - wax_obj_proxy::sptr _tx_duc_proxy; - - //codec functions and settings - void codec_init(void); - void rx_codec_get(const wax::obj &, wax::obj &); - void rx_codec_set(const wax::obj &, const wax::obj &); - void tx_codec_get(const wax::obj &, wax::obj &); - void tx_codec_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _rx_codec_proxy, _tx_codec_proxy; - - //clock control functions and settings - void init_clock_config(void); - void update_clock_config(void); -}; - -#endif /* INCLUDED_USRP_E100_IMPL_HPP */ diff --git a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp b/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp deleted file mode 100644 index 1bcae64c7..000000000 --- a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp +++ /dev/null @@ -1,221 +0,0 @@ - - -//////////////////////////////////////////////////////////////// -// -// Memory map for embedded wishbone bus -// -//////////////////////////////////////////////////////////////// - -// All addresses are byte addresses. All accesses are word (16-bit) accesses. -// This means that address bit 0 is usually 0. -// There are 11 bits of address for the control. - -#ifndef INCLUDED_USRP_E100_REGS_HPP -#define INCLUDED_USRP_E100_REGS_HPP - -///////////////////////////////////////////////////// -// Slave pointers - -#define UE_REG_SLAVE(n) ((n)<<7) - -///////////////////////////////////////////////////// -// Slave 0 -- Misc Regs - -#define UE_REG_MISC_BASE UE_REG_SLAVE(0) - -#define UE_REG_MISC_LED UE_REG_MISC_BASE + 0 -#define UE_REG_MISC_SW UE_REG_MISC_BASE + 2 -#define UE_REG_MISC_CGEN_CTRL UE_REG_MISC_BASE + 4 -#define UE_REG_MISC_CGEN_ST UE_REG_MISC_BASE + 6 -#define UE_REG_MISC_TEST UE_REG_MISC_BASE + 8 -#define UE_REG_MISC_RX_LEN UE_REG_MISC_BASE + 10 -#define UE_REG_MISC_TX_LEN UE_REG_MISC_BASE + 12 -#define UE_REG_MISC_XFER_RATE UE_REG_MISC_BASE + 14 -#define UE_REG_MISC_COMPAT UE_REG_MISC_BASE + 16 - -///////////////////////////////////////////////////// -// Slave 1 -- UART -// CLKDIV is 16 bits, others are only 8 - -#define UE_REG_UART_BASE UE_REG_SLAVE(1) - -#define UE_REG_UART_CLKDIV UE_REG_UART_BASE + 0 -#define UE_REG_UART_TXLEVEL UE_REG_UART_BASE + 2 -#define UE_REG_UART_RXLEVEL UE_REG_UART_BASE + 4 -#define UE_REG_UART_TXCHAR UE_REG_UART_BASE + 6 -#define UE_REG_UART_RXCHAR UE_REG_UART_BASE + 8 - -///////////////////////////////////////////////////// -// Slave 2 -- SPI Core -// This should be accessed through the IOCTL -// Users should not touch directly - -#define UE_REG_SPI_BASE UE_REG_SLAVE(2) - -//spi slave constants -#define UE_SPI_SS_AD9522 (1 << 3) -#define UE_SPI_SS_AD9862 (1 << 2) -#define UE_SPI_SS_TX_DB (1 << 1) -#define UE_SPI_SS_RX_DB (1 << 0) - -//////////////////////////////////////////////// -// Slave 3 -- I2C Core -// This should be accessed through the IOCTL -// Users should not touch directly - -#define UE_REG_I2C_BASE UE_REG_SLAVE(3) - - -//////////////////////////////////////////////// -// Slave 4 -- GPIO - -#define UE_REG_GPIO_BASE UE_REG_SLAVE(4) - -#define UE_REG_GPIO_RX_IO UE_REG_GPIO_BASE + 0 -#define UE_REG_GPIO_TX_IO UE_REG_GPIO_BASE + 2 -#define UE_REG_GPIO_RX_DDR UE_REG_GPIO_BASE + 4 -#define UE_REG_GPIO_TX_DDR UE_REG_GPIO_BASE + 6 -#define UE_REG_GPIO_RX_SEL UE_REG_GPIO_BASE + 8 -#define UE_REG_GPIO_TX_SEL UE_REG_GPIO_BASE + 10 -#define UE_REG_GPIO_RX_DBG UE_REG_GPIO_BASE + 12 -#define UE_REG_GPIO_TX_DBG UE_REG_GPIO_BASE + 14 - -//possible bit values for sel when dbg is 0: -#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg -#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic - -//possible bit values for sel when dbg is 1: -#define GPIO_SEL_DEBUG_0 0 // if pin is an output, debug lines from FPGA fabric -#define GPIO_SEL_DEBUG_1 1 // if pin is an output, debug lines from FPGA fabric - -/////////////////////////////////////////////////// -// Slave 6 -- ATR Controller -// 16 regs - -#define UE_REG_ATR_BASE UE_REG_SLAVE(6) - -#define UE_REG_ATR_IDLE_RXSIDE UE_REG_ATR_BASE + 0 -#define UE_REG_ATR_IDLE_TXSIDE UE_REG_ATR_BASE + 2 -#define UE_REG_ATR_INTX_RXSIDE UE_REG_ATR_BASE + 4 -#define UE_REG_ATR_INTX_TXSIDE UE_REG_ATR_BASE + 6 -#define UE_REG_ATR_INRX_RXSIDE UE_REG_ATR_BASE + 8 -#define UE_REG_ATR_INRX_TXSIDE UE_REG_ATR_BASE + 10 -#define UE_REG_ATR_FULL_RXSIDE UE_REG_ATR_BASE + 12 -#define UE_REG_ATR_FULL_TXSIDE UE_REG_ATR_BASE + 14 - -/////////////////////////////////////////////////// -// Slave 7 -- Readback Mux 32 - -#define UE_REG_RB_MUX_32_BASE UE_REG_SLAVE(7) - -#define UE_REG_RB_TIME_NOW_SECS UE_REG_RB_MUX_32_BASE + 0 -#define UE_REG_RB_TIME_NOW_TICKS UE_REG_RB_MUX_32_BASE + 4 -#define UE_REG_RB_TIME_PPS_SECS UE_REG_RB_MUX_32_BASE + 8 -#define UE_REG_RB_TIME_PPS_TICKS UE_REG_RB_MUX_32_BASE + 12 -#define UE_REG_RB_MISC_TEST32 UE_REG_RB_MUX_32_BASE + 16 - -//////////////////////////////////////////////////// -// Slave 8 -- Settings Bus -// -// Output-only, no readback, 64 registers total -// Each register must be written 64 bits at a time -// First the address xxx_xx00 and then xxx_xx10 - -#define UE_REG_SETTINGS_BASE_ADDR(n) (UE_REG_SLAVE(8) + (4*(n))) - -#define UE_REG_SR_MISC_TEST32 UE_REG_SETTINGS_BASE_ADDR(52) - -///////////////////////////////////////////////// -// Magic reset regs -//////////////////////////////////////////////// -#define UE_REG_CLEAR_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(48) + (4*(n))) -#define UE_REG_CLEAR_RX UE_REG_CLEAR_ADDR(0) -#define UE_REG_CLEAR_TX UE_REG_CLEAR_ADDR(1) - -///////////////////////////////////////////////// -// DSP RX Regs -//////////////////////////////////////////////// -#define UE_REG_DSP_RX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(16) + (4*(n))) -#define UE_REG_DSP_RX_FREQ UE_REG_DSP_RX_ADDR(0) -#define UE_REG_DSP_RX_SCALE_IQ UE_REG_DSP_RX_ADDR(1) // {scale_i,scale_q} -#define UE_REG_DSP_RX_DECIM_RATE UE_REG_DSP_RX_ADDR(2) // hb and decim rate -#define UE_REG_DSP_RX_DCOFFSET_I UE_REG_DSP_RX_ADDR(3) // Bit 31 high sets fixed offset mode, using lower 14 bits, // otherwise it is automatic -#define UE_REG_DSP_RX_DCOFFSET_Q UE_REG_DSP_RX_ADDR(4) // Bit 31 high sets fixed offset mode, using lower 14 bits -#define UE_REG_DSP_RX_MUX UE_REG_DSP_RX_ADDR(5) - -/////////////////////////////////////////////////// -// VITA RX CTRL regs -/////////////////////////////////////////////////// -#define UE_REG_CTRL_RX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(0) + (4*(n))) -// The following 3 are logically a single command register. -// They are clocked into the underlying fifo when time_ticks is written. -#define UE_REG_CTRL_RX_STREAM_CMD UE_REG_CTRL_RX_ADDR(0) // {now, chain, num_samples(30) -#define UE_REG_CTRL_RX_TIME_SECS UE_REG_CTRL_RX_ADDR(1) -#define UE_REG_CTRL_RX_TIME_TICKS UE_REG_CTRL_RX_ADDR(2) -#define UE_REG_CTRL_RX_CLEAR UE_REG_CTRL_RX_ADDR(3) // write anything to clear -#define UE_REG_CTRL_RX_VRT_HEADER UE_REG_CTRL_RX_ADDR(4) // word 0 of packet. FPGA fills in packet counter -#define UE_REG_CTRL_RX_VRT_STREAM_ID UE_REG_CTRL_RX_ADDR(5) // word 1 of packet. -#define UE_REG_CTRL_RX_VRT_TRAILER UE_REG_CTRL_RX_ADDR(6) -#define UE_REG_CTRL_RX_NSAMPS_PER_PKT UE_REG_CTRL_RX_ADDR(7) -#define UE_REG_CTRL_RX_NCHANNELS UE_REG_CTRL_RX_ADDR(8) // 1 in basic case, up to 4 for vector sources - -///////////////////////////////////////////////// -// DSP TX Regs -//////////////////////////////////////////////// -#define UE_REG_DSP_TX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(32) + (4*(n))) -#define UE_REG_DSP_TX_FREQ UE_REG_DSP_TX_ADDR(0) -#define UE_REG_DSP_TX_SCALE_IQ UE_REG_DSP_TX_ADDR(1) // {scale_i,scale_q} -#define UE_REG_DSP_TX_INTERP_RATE UE_REG_DSP_TX_ADDR(2) -#define UE_REG_DSP_TX_UNUSED UE_REG_DSP_TX_ADDR(3) -#define UE_REG_DSP_TX_MUX UE_REG_DSP_TX_ADDR(4) - -///////////////////////////////////////////////// -// VITA TX CTRL regs -//////////////////////////////////////////////// -#define UE_REG_CTRL_TX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(24) + (4*(n))) -#define UE_REG_CTRL_TX_NCHANNELS UE_REG_CTRL_TX_ADDR(0) -#define UE_REG_CTRL_TX_CLEAR UE_REG_CTRL_TX_ADDR(1) -#define UE_REG_CTRL_TX_REPORT_SID UE_REG_CTRL_TX_ADDR(2) -#define UE_REG_CTRL_TX_POLICY UE_REG_CTRL_TX_ADDR(3) - -#define UE_FLAG_CTRL_TX_POLICY_WAIT (0x1 << 0) -#define UE_FLAG_CTRL_TX_POLICY_NEXT_PACKET (0x1 << 1) -#define UE_FLAG_CTRL_TX_POLICY_NEXT_BURST (0x1 << 2) - -///////////////////////////////////////////////// -// VITA49 64 bit time (write only) -//////////////////////////////////////////////// - /*! - * \brief Time 64 flags - * - * <pre> - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-----------------------------------------------------------+-+-+ - * | |S|P| - * +-----------------------------------------------------------+-+-+ - * - * P - PPS edge selection (0=negedge, 1=posedge, default=0) - * S - Source (0=sma, 1=mimo, 0=default) - * - * </pre> - */ -#define UE_REG_TIME64_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(40) + (4*(n))) -#define UE_REG_TIME64_SECS UE_REG_TIME64_ADDR(0) // value to set absolute secs to on next PPS -#define UE_REG_TIME64_TICKS UE_REG_TIME64_ADDR(1) // value to set absolute ticks to on next PPS -#define UE_REG_TIME64_FLAGS UE_REG_TIME64_ADDR(2) // flags - see chart above -#define UE_REG_TIME64_IMM UE_REG_TIME64_ADDR(3) // set immediate (0=latch on next pps, 1=latch immediate, default=0) -#define UE_REG_TIME64_TPS UE_REG_TIME64_ADDR(4) // clock ticks per second (counter rollover) - -//pps flags (see above) -#define UE_FLAG_TIME64_PPS_NEGEDGE (0 << 0) -#define UE_FLAG_TIME64_PPS_POSEDGE (1 << 0) -#define UE_FLAG_TIME64_PPS_SMA (0 << 1) -#define UE_FLAG_TIME64_PPS_MIMO (1 << 1) - -#define UE_FLAG_TIME64_LATCH_NOW 1 -#define UE_FLAG_TIME64_LATCH_NEXT_PPS 0 - -#endif - diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt index c8268c7b0..fd3249099 100644 --- a/host/lib/utils/CMakeLists.txt +++ b/host/lib/utils/CMakeLists.txt @@ -136,5 +136,6 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/paths.cpp ${CMAKE_CURRENT_SOURCE_DIR}/props.cpp ${CMAKE_CURRENT_SOURCE_DIR}/static.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tasks.cpp ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp ) diff --git a/host/lib/utils/tasks.cpp b/host/lib/utils/tasks.cpp new file mode 100644 index 000000000..ef56bb2de --- /dev/null +++ b/host/lib/utils/tasks.cpp @@ -0,0 +1,75 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/utils/tasks.hpp> +#include <uhd/utils/msg.hpp> +#include <boost/thread/thread.hpp> +#include <boost/thread/barrier.hpp> +#include <exception> +#include <iostream> + +using namespace uhd; + +class task_impl : public task{ +public: + + task_impl(const task_fcn_type &task_fcn){ + boost::barrier spawn_barrier(2); + _thread_group.create_thread(boost::bind(&task_impl::task_loop, this, task_fcn, boost::ref(spawn_barrier))); + spawn_barrier.wait(); + } + + ~task_impl(void){ + _thread_group.interrupt_all(); + _thread_group.join_all(); + } + +private: + + void task_loop(const task_fcn_type &task_fcn, boost::barrier &spawn_barrier){ + spawn_barrier.wait(); + + try{ + while (not boost::this_thread::interruption_requested()){ + task_fcn(); + } + } + catch(const boost::thread_interrupted &){ + //this is an ok way to exit the task loop + } + catch(const std::exception &e){ + do_error_msg(e.what()); + } + catch(...){ + do_error_msg("unknown exception"); + } + } + + void do_error_msg(const std::string &msg){ + UHD_MSG(error) + << "An unexpected exception was caught in a task loop." << std::endl + << "The task loop will now exit, things may not work." << std::endl + << msg << std::endl + ; + } + + boost::thread_group _thread_group; +}; + +task::sptr task::make(const task_fcn_type &task_fcn){ + return task::sptr(new task_impl(task_fcn)); +} diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index b7bcfb7d5..c97116233 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -27,12 +27,12 @@ SET(test_sources error_test.cpp gain_group_test.cpp msg_test.cpp + property_test.cpp ranges_test.cpp sph_recv_test.cpp sph_send_test.cpp subdev_spec_test.cpp time_spec_test.cpp - tune_helper_test.cpp vrt_test.cpp wax_test.cpp ) diff --git a/host/tests/property_test.cpp b/host/tests/property_test.cpp new file mode 100644 index 000000000..04d3a831c --- /dev/null +++ b/host/tests/property_test.cpp @@ -0,0 +1,175 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include <boost/test/unit_test.hpp> +#include <uhd/property_tree.hpp> +#include <boost/bind.hpp> +#include <exception> +#include <iostream> + +struct coercer_type{ + int doit(int x){ + return x & ~0x3; + } +}; + +struct setter_type{ + void doit(int x){ + _x = x; + } + + int _x; +}; + +struct getter_type{ + int doit(void){ + return _x; + } + + int _x; +}; + +BOOST_AUTO_TEST_CASE(test_prop_simple){ + uhd::property_tree::sptr tree = uhd::property_tree::make(); + uhd::property<int> &prop = tree->create<int>("/"); + + BOOST_CHECK(prop.empty()); + prop.set(0); + BOOST_CHECK(not prop.empty()); + + prop.set(42); + BOOST_CHECK_EQUAL(prop.get(), 42); + prop.set(34); + BOOST_CHECK_EQUAL(prop.get(), 34); +} + +BOOST_AUTO_TEST_CASE(test_prop_with_subscriber){ + uhd::property_tree::sptr tree = uhd::property_tree::make(); + uhd::property<int> &prop = tree->create<int>("/"); + + setter_type setter; + prop.subscribe(boost::bind(&setter_type::doit, &setter, _1)); + + prop.set(42); + BOOST_CHECK_EQUAL(prop.get(), 42); + BOOST_CHECK_EQUAL(setter._x, 42); + + prop.set(34); + BOOST_CHECK_EQUAL(prop.get(), 34); + BOOST_CHECK_EQUAL(setter._x, 34); +} + +BOOST_AUTO_TEST_CASE(test_prop_with_publisher){ + uhd::property_tree::sptr tree = uhd::property_tree::make(); + uhd::property<int> &prop = tree->create<int>("/"); + + BOOST_CHECK(prop.empty()); + getter_type getter; + prop.publish(boost::bind(&getter_type::doit, &getter)); + BOOST_CHECK(not prop.empty()); + + getter._x = 42; + prop.set(0); //should not change + BOOST_CHECK_EQUAL(prop.get(), 42); + + getter._x = 34; + prop.set(0); //should not change + BOOST_CHECK_EQUAL(prop.get(), 34); +} + +BOOST_AUTO_TEST_CASE(test_prop_with_publisher_and_subscriber){ + uhd::property_tree::sptr tree = uhd::property_tree::make(); + uhd::property<int> &prop = tree->create<int>("/"); + + getter_type getter; + prop.publish(boost::bind(&getter_type::doit, &getter)); + + setter_type setter; + prop.subscribe(boost::bind(&setter_type::doit, &setter, _1)); + + getter._x = 42; + prop.set(0); + BOOST_CHECK_EQUAL(prop.get(), 42); + BOOST_CHECK_EQUAL(setter._x, 0); + + getter._x = 34; + prop.set(1); + BOOST_CHECK_EQUAL(prop.get(), 34); + BOOST_CHECK_EQUAL(setter._x, 1); +} + +BOOST_AUTO_TEST_CASE(test_prop_with_coercion){ + uhd::property_tree::sptr tree = uhd::property_tree::make(); + uhd::property<int> &prop = tree->create<int>("/"); + + setter_type setter; + prop.subscribe(boost::bind(&setter_type::doit, &setter, _1)); + + coercer_type coercer; + prop.coerce(boost::bind(&coercer_type::doit, &coercer, _1)); + + prop.set(42); + BOOST_CHECK_EQUAL(prop.get(), 40); + BOOST_CHECK_EQUAL(setter._x, 40); + + prop.set(34); + BOOST_CHECK_EQUAL(prop.get(), 32); + BOOST_CHECK_EQUAL(setter._x, 32); +} + +BOOST_AUTO_TEST_CASE(test_prop_tree){ + uhd::property_tree::sptr tree = uhd::property_tree::make(); + + tree->create<int>("/test/prop0"); + tree->create<int>("/test/prop1"); + + BOOST_CHECK(tree->exists("/test")); + BOOST_CHECK_THROW(tree->access<int>("/test"), std::exception); + BOOST_CHECK(tree->exists("/test/prop0")); + BOOST_CHECK(tree->exists("/test/prop1")); + + tree->access<int>("/test/prop0").set(42); + tree->access<int>("/test/prop1").set(34); + + BOOST_CHECK_EQUAL(tree->access<int>("/test/prop0").get(), 42); + BOOST_CHECK_EQUAL(tree->access<int>("/test/prop1").get(), 34); + + tree->remove("/test/prop0"); + BOOST_CHECK(not tree->exists("/test/prop0")); + BOOST_CHECK(tree->exists("/test/prop1")); + + tree->remove("/test"); + BOOST_CHECK(not tree->exists("/test/prop0")); + BOOST_CHECK(not tree->exists("/test/prop1")); + +} + +BOOST_AUTO_TEST_CASE(test_prop_subtree){ + uhd::property_tree::sptr tree = uhd::property_tree::make(); + tree->create<int>("/subdir1/subdir2"); + + uhd::property_tree::sptr subtree1 = tree->subtree("/"); + const std::vector<std::string> tree_dirs1 = tree->list("/"); + const std::vector<std::string> subtree1_dirs = subtree1->list(""); + BOOST_CHECK_EQUAL_COLLECTIONS(tree_dirs1.begin(), tree_dirs1.end(), subtree1_dirs.begin(), subtree1_dirs.end()); + + uhd::property_tree::sptr subtree2 = subtree1->subtree("subdir1"); + const std::vector<std::string> tree_dirs2 = tree->list("/subdir1"); + const std::vector<std::string> subtree2_dirs = subtree2->list(""); + BOOST_CHECK_EQUAL_COLLECTIONS(tree_dirs2.begin(), tree_dirs2.end(), subtree2_dirs.begin(), subtree2_dirs.end()); + +} diff --git a/host/tests/sph_recv_test.cpp b/host/tests/sph_recv_test.cpp index cd33452c6..1387e3b66 100644 --- a/host/tests/sph_recv_test.cpp +++ b/host/tests/sph_recv_test.cpp @@ -290,6 +290,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){ //generate a bunch of packets for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){ + ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA; ifpi.num_payload_words32 = 10 + i%10; dummy_recv_xport.push_back_packet(ifpi); ifpi.packet_count++; @@ -300,8 +301,6 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){ ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_EXTENSION; ifpi.num_payload_words32 = 1; dummy_recv_xport.push_back_packet(ifpi, uhd::rx_metadata_t::ERROR_CODE_OVERFLOW); - ifpi.packet_count++; - ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA; } } diff --git a/host/tests/tune_helper_test.cpp b/host/tests/tune_helper_test.cpp deleted file mode 100644 index 9147cd310..000000000 --- a/host/tests/tune_helper_test.cpp +++ /dev/null @@ -1,251 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include <boost/test/unit_test.hpp> -#include <uhd/usrp/tune_helper.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/usrp/dsp_props.hpp> -#include <uhd/usrp/dsp_utils.hpp> -#include <iostream> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Dummy properties objects - **********************************************************************/ -class dummy_subdev : public wax::obj{ -public: - dummy_subdev(double resolution): - _resolution(resolution) - { - /* NOP */ - } -private: - void get(const wax::obj &key, wax::obj &val){ - switch(key.as<subdev_prop_t>()){ - - case SUBDEV_PROP_FREQ: - val = _freq; - return; - - case SUBDEV_PROP_USE_LO_OFFSET: - val = false; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } - } - - void set(const wax::obj &key, const wax::obj &val){ - switch(key.as<subdev_prop_t>()){ - case SUBDEV_PROP_FREQ: - _freq = _resolution*int(val.as<double>()/_resolution); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } - } - - double _freq, _resolution; -}; - -class dummy_subdev_basic : public wax::obj{ -private: - void get(const wax::obj &key, wax::obj &val){ - switch(key.as<subdev_prop_t>()){ - - case SUBDEV_PROP_FREQ: - val = double(0.0); //always zero - return; - - case SUBDEV_PROP_USE_LO_OFFSET: - val = false; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } - } - - void set(const wax::obj &key, const wax::obj &){ - switch(key.as<subdev_prop_t>()){ - case SUBDEV_PROP_FREQ: - // do nothing - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } - } -}; - -class dummy_subdev_bw : public wax::obj{ -private: - void get(const wax::obj &key, wax::obj &val){ - switch(key.as<subdev_prop_t>()){ - - case SUBDEV_PROP_FREQ: - val = _freq; - return; - - case SUBDEV_PROP_USE_LO_OFFSET: - val = true; - return; - - case SUBDEV_PROP_BANDWIDTH: - val = _bandwidth; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } - } - - void set(const wax::obj &key, const wax::obj &val){ - switch(key.as<subdev_prop_t>()){ - case SUBDEV_PROP_FREQ: - _freq = val.as<double>(); - return; - - case SUBDEV_PROP_BANDWIDTH: - _bandwidth = val.as<double>(); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } - } - - double _freq, _bandwidth; -}; - -class dummy_dsp : public wax::obj{ -public: - dummy_dsp(double codec_rate): - _codec_rate(codec_rate) - { - /* NOP */ - } -private: - void get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_CODEC_RATE: - val = _codec_rate; - return; - - case DSP_PROP_HOST_RATE: - val = _host_rate; - return; - - case DSP_PROP_FREQ_SHIFT: - val = _freq_shift; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } - } - - void set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - switch(key.as<dsp_prop_t>()){ - case DSP_PROP_FREQ_SHIFT: - _freq_shift = val.as<double>(); - dsp_type1::calc_cordic_word_and_update(_freq_shift, _codec_rate); - return; - - case DSP_PROP_HOST_RATE: - _host_rate = val.as<double>(); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } - } - - double _codec_rate, _freq_shift, _host_rate; -}; - -/*********************************************************************** - * Test cases - **********************************************************************/ -static const double tolerance = 0.001; - -BOOST_AUTO_TEST_CASE(test_tune_helper_rx){ - dummy_subdev subdev(1e6); - dummy_dsp dsp(100e6); - - std::cout << "Testing tune helper RX automatic IF offset" << std::endl; - tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9); - std::cout << tr.to_pp_string() << std::endl; - BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.345e9, tolerance); - BOOST_CHECK_CLOSE(tr.actual_dsp_freq, -100e3, tolerance); - - double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); - BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance); -} - -BOOST_AUTO_TEST_CASE(test_tune_helper_tx){ - dummy_subdev subdev(1e6); - dummy_dsp dsp(100e6); - - std::cout << "Testing tune helper TX automatic IF offset" << std::endl; - tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9); - std::cout << tr.to_pp_string() << std::endl; - BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.345e9, tolerance); - BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 100e3, tolerance); - - double freq_derived = derive_freq_from_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); - BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance); -} - -BOOST_AUTO_TEST_CASE(test_tune_helper_rx_nyquist){ - dummy_subdev_basic subdev; - dummy_dsp dsp(100e6); - - std::cout << "Testing tune helper RX dummy basic board" << std::endl; - tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 55e6); - std::cout << tr.to_pp_string() << std::endl; - BOOST_CHECK_CLOSE(tr.actual_rf_freq, 0.0, tolerance); - BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 45e6, tolerance); - - double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); - BOOST_CHECK_CLOSE(freq_derived, -45e6, tolerance); -} - -BOOST_AUTO_TEST_CASE(test_tune_helper_rx_lo_off){ - dummy_subdev_bw subdev; - dummy_dsp dsp(100e6); - tune_result_t tr; - - std::cout << "Testing tune helper RX automatic LO offset B >> fs" << std::endl; - subdev[SUBDEV_PROP_BANDWIDTH] = double(40e6); - dsp[DSP_PROP_HOST_RATE] = double(4e6); - tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9); - std::cout << tr.to_pp_string() << std::endl; - BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.45e9+4e6/2, tolerance); - - std::cout << "Testing tune helper RX automatic LO offset B > fs" << std::endl; - subdev[SUBDEV_PROP_BANDWIDTH] = double(40e6); - dsp[DSP_PROP_HOST_RATE] = double(25e6); - tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9); - std::cout << tr.to_pp_string() << std::endl; - BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.45e9+(40e6-25e6)/2, tolerance); - - std::cout << "Testing tune helper RX automatic LO offset B < fs" << std::endl; - subdev[SUBDEV_PROP_BANDWIDTH] = double(20e6); - dsp[DSP_PROP_HOST_RATE] = double(25e6); - tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9); - std::cout << tr.to_pp_string() << std::endl; - BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.45e9, tolerance); -} diff --git a/host/usrp_e_utils/CMakeLists.txt b/host/usrp_e_utils/CMakeLists.txt index e7d6ae4b8..9162a2099 100644 --- a/host/usrp_e_utils/CMakeLists.txt +++ b/host/usrp_e_utils/CMakeLists.txt @@ -23,19 +23,15 @@ LIBUHD_REGISTER_COMPONENT("USRP-E Utils" ENABLE_USRP_E_UTILS OFF "LINUX" OFF) IF(ENABLE_USRP_E_UTILS) ENABLE_LANGUAGE(C) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e100) - INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e100/include) - INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/lib/ic_reg_maps) + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/e100) + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/e100/include) SET(usrp_e_utils_sources - usrp-e-utility.cpp usrp-e-loopback.c usrp-e-timed.c usrp-e-wb-test.cpp usrp-e-debug-pins.c usrp-e-gpio.c - usrp-e-i2c.c - usrp-e-spi.c ) #for each source: build an executable and install diff --git a/host/usrp_e_utils/clkgen_config.hpp b/host/usrp_e_utils/clkgen_config.hpp deleted file mode 100644 index f39f8bb19..000000000 --- a/host/usrp_e_utils/clkgen_config.hpp +++ /dev/null @@ -1,305 +0,0 @@ -// -// Copyright 2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef USRP_E_UTILS_CLKGEN_CONFIG_HPP -#define USRP_E_UTILS_CLKGEN_CONFIG_HPP - -#include <iostream> -#include <sstream> -#include <fstream> -#include <string> -#include <cstdlib> - -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> - -#include <linux/spi/spidev.h> - -namespace usrp_e_clkgen_config_utility{ - -// Programming data for clock gen chip -static const unsigned int config_data[] = { - 0x000024, - 0x023201, - 0x000081, - 0x000400, - 0x00104c, - 0x001101, - 0x001200, - 0x001300, - 0x001414, - 0x001500, - 0x001604, - 0x001704, - 0x001807, - 0x001900, - //0x001a00,//for debug - 0x001a32, - 0x001b12, - 0x001c44, - 0x001d00, - 0x001e00, - 0x00f062, - 0x00f162, - 0x00f262, - 0x00f362, - 0x00f462, - 0x00f562, - 0x00f662, - 0x00f762, - 0x00f862, - 0x00f962, - 0x00fa62, - 0x00fb62, - 0x00fc00, - 0x00fd00, - 0x019021, - 0x019100, - 0x019200, - 0x019321, - 0x019400, - 0x019500, - 0x019611, - 0x019700, - 0x019800, - 0x019900, - 0x019a00, - 0x019b00, - 0x01e003, - 0x01e102, - 0x023000, - 0x023201, - 0x0b0201, - 0x0b0300, - 0x001fff, - 0x0a0000, - 0x0a0100, - 0x0a0200, - 0x0a0302, - 0x0a0400, - 0x0a0504, - 0x0a060e, - 0x0a0700, - 0x0a0810, - 0x0a090e, - 0x0a0a00, - 0x0a0bf0, - 0x0a0c0b, - 0x0a0d01, - 0x0a0e90, - 0x0a0f01, - 0x0a1001, - 0x0a11e0, - 0x0a1201, - 0x0a1302, - 0x0a1430, - 0x0a1580, - 0x0a16ff, - 0x023201, - 0x0b0301, - 0x023201, -}; - - -const unsigned int CLKGEN_SELECT = 145; - - -enum gpio_direction {IN, OUT}; - -class gpio { - public: - - gpio(unsigned int gpio_num, gpio_direction pin_direction, bool close_action); - ~gpio(); - - bool get_value(); - void set_value(bool state); - - private: - - unsigned int gpio_num; - - std::stringstream base_path; - std::fstream value_file; - std::fstream direction_file; - bool close_action; // True set to input and release, false do nothing -}; - -class spidev { - public: - - spidev(std::string dev_name); - ~spidev(); - - void send(char *wbuf, char *rbuf, unsigned int nbytes); - - private: - - int fd; - -}; - -gpio::gpio(unsigned int _gpio_num, gpio_direction pin_direction, bool close_action) -:close_action(close_action) -{ - std::fstream export_file; - - gpio_num = _gpio_num; - - export_file.open("/sys/class/gpio/export", std::ios::out); - if (!export_file.is_open()) ///\todo Poor error handling - std::cout << "Failed to open gpio export file." << std::endl; - - export_file << gpio_num << std::endl; - - base_path << "/sys/class/gpio/gpio" << gpio_num << std::flush; - - std::string direction_file_name; - - direction_file_name = base_path.str() + "/direction"; - - direction_file.open(direction_file_name.c_str()); - if (!direction_file.is_open()) - std::cout << "Failed to open direction file." << std::endl; - if (pin_direction == OUT) - direction_file << "out" << std::endl; - else - direction_file << "in" << std::endl; - - std::string value_file_name; - - value_file_name = base_path.str() + "/value"; - - value_file.open(value_file_name.c_str(), std::ios_base::in | std::ios_base::out); - if (!value_file.is_open()) - std::cout << "Failed to open value file." << std::endl; -} - -bool gpio::get_value() -{ - - std::string val; - - std::getline(value_file, val); - value_file.seekg(0); - - if (val == "0") - return false; - else if (val == "1") - return true; - else - std::cout << "Data read from value file|" << val << "|" << std::endl; - - return false; -} - -void gpio::set_value(bool state) -{ - - if (state) - value_file << "1" << std::endl; - else - value_file << "0" << std::endl; -} - -gpio::~gpio() -{ - if (close_action) { - std::fstream unexport_file; - - direction_file << "in" << std::endl; - - unexport_file.open("/sys/class/gpio/unexport", std::ios::out); - if (!unexport_file.is_open()) ///\todo Poor error handling - std::cout << "Failed to open gpio export file." << std::endl; - - unexport_file << gpio_num << std::endl; - - } - -} - -spidev::spidev(std::string fname) -{ - int ret; - int mode = 0; - int speed = 12000; - int bits = 24; - - fd = open(fname.c_str(), O_RDWR); - - ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); - ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); - ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); -} - - -spidev::~spidev() -{ - close(fd); -} - -void spidev::send(char *buf, char *rbuf, unsigned int nbytes) -{ - int ret; - - struct spi_ioc_transfer tr; - tr.tx_buf = (unsigned long) buf; - tr.rx_buf = (unsigned long) rbuf; - tr.len = nbytes; - tr.delay_usecs = 0; - tr.speed_hz = 12000; - tr.bits_per_word = 24; - - ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); - -} - -static void send_config_to_clkgen(gpio &chip_select, const unsigned int data[], unsigned int data_size) -{ - spidev spi("/dev/spidev1.0"); - unsigned int rbuf; - - for (unsigned int i = 0; i < data_size; i++) { - - //std::cout << "sending " << std::hex << data[i] << std::endl; - chip_select.set_value(0); - spi.send((char *)&data[i], (char *)&rbuf, 4); - chip_select.set_value(1); - unsigned int addr = (data[i] >> 8) & 0xfff; - if (addr == 0x232 || addr == 0x000){ - std::cout << "." << std::flush; - sleep(1); - } - }; - std::cout << std::endl; -} - -}//namespace usrp_e_clkgen_config_utility - -//int main(int argc, char *argv[]) -static void clock_genconfig_main(void) -{ - using namespace usrp_e_clkgen_config_utility; - gpio clkgen_select(CLKGEN_SELECT, OUT, true); - - send_config_to_clkgen(clkgen_select, config_data, sizeof(config_data)/sizeof(config_data[0])); -} - -#endif /*USRP_E_UTILS_CLKGEN_CONFIG_HPP*/ diff --git a/host/usrp_e_utils/usrp-e-debug-pins.c b/host/usrp_e_utils/usrp-e-debug-pins.c index 94f898b67..570ae63d8 100644 --- a/host/usrp_e_utils/usrp-e-debug-pins.c +++ b/host/usrp_e_utils/usrp-e-debug-pins.c @@ -7,7 +7,7 @@ #include <sys/ioctl.h> #include <linux/usrp_e.h> -#include "usrp_e100_regs.hpp" +#include "e100_regs.hpp" // Usage: usrp_e_gpio <string> @@ -54,24 +54,24 @@ int main(int argc, char *argv[]) if (strcmp(argv[1], "0") == 0) { printf("Selected 0 based on %s\n", argv[1]); - write_reg(UE_REG_GPIO_TX_DDR, 0xFFFF); - write_reg(UE_REG_GPIO_RX_DDR, 0xFFFF); - write_reg(UE_REG_GPIO_TX_SEL, 0x0); - write_reg(UE_REG_GPIO_RX_SEL, 0x0); - write_reg(UE_REG_GPIO_TX_DBG, 0xFFFF); - write_reg(UE_REG_GPIO_RX_DBG, 0xFFFF); + write_reg(E100_REG_GPIO_TX_DDR, 0xFFFF); + write_reg(E100_REG_GPIO_RX_DDR, 0xFFFF); + write_reg(E100_REG_GPIO_TX_SEL, 0x0); + write_reg(E100_REG_GPIO_RX_SEL, 0x0); + write_reg(E100_REG_GPIO_TX_DBG, 0xFFFF); + write_reg(E100_REG_GPIO_RX_DBG, 0xFFFF); } else if (strcmp(argv[1], "1") == 0) { printf("Selected 1 based on %s\n", argv[1]); - write_reg(UE_REG_GPIO_TX_DDR, 0xFFFF); - write_reg(UE_REG_GPIO_RX_DDR, 0xFFFF); - write_reg(UE_REG_GPIO_TX_SEL, 0xFFFF); - write_reg(UE_REG_GPIO_RX_SEL, 0xFFFF); - write_reg(UE_REG_GPIO_TX_DBG, 0xFFFF); - write_reg(UE_REG_GPIO_RX_DBG, 0xFFFF); + write_reg(E100_REG_GPIO_TX_DDR, 0xFFFF); + write_reg(E100_REG_GPIO_RX_DDR, 0xFFFF); + write_reg(E100_REG_GPIO_TX_SEL, 0xFFFF); + write_reg(E100_REG_GPIO_RX_SEL, 0xFFFF); + write_reg(E100_REG_GPIO_TX_DBG, 0xFFFF); + write_reg(E100_REG_GPIO_RX_DBG, 0xFFFF); } else { printf("Selected off based on %s\n", argv[1]); - write_reg(UE_REG_GPIO_TX_DDR, 0x0); - write_reg(UE_REG_GPIO_RX_DDR, 0x0); + write_reg(E100_REG_GPIO_TX_DDR, 0x0); + write_reg(E100_REG_GPIO_RX_DDR, 0x0); } return 0; diff --git a/host/usrp_e_utils/usrp-e-gpio.c b/host/usrp_e_utils/usrp-e-gpio.c index 7e4bc4e13..4b788e945 100644 --- a/host/usrp_e_utils/usrp-e-gpio.c +++ b/host/usrp_e_utils/usrp-e-gpio.c @@ -7,7 +7,7 @@ #include <sys/ioctl.h> #include "linux/usrp_e.h" -#include "usrp_e100_regs.hpp" +#include "e100_regs.hpp" // Usage: usrp_e_gpio <string> @@ -46,38 +46,38 @@ int main(int argc, char *argv[]) fp = open("/dev/usrp_e0", O_RDWR); printf("fp = %d\n", fp); - write_reg(UE_REG_GPIO_TX_DDR, 0x0); - write_reg(UE_REG_GPIO_RX_DDR, 0xFFFF); + write_reg(E100_REG_GPIO_TX_DDR, 0x0); + write_reg(E100_REG_GPIO_RX_DDR, 0xFFFF); for (i=0; i < 16; i++) { - write_reg(UE_REG_GPIO_RX_IO, 1 << i); + write_reg(E100_REG_GPIO_RX_IO, 1 << i); sleep(1); if (test) { - data_in = read_reg(UE_REG_GPIO_TX_IO); + data_in = read_reg(E100_REG_GPIO_TX_IO); if (data_in != (1 << i)) printf("Read failed, wrote: %X read: %X\n", \ 1 << i, data_in); } } - write_reg(UE_REG_GPIO_RX_DDR, 0x0); - write_reg(UE_REG_GPIO_TX_DDR, 0xFFFF); + write_reg(E100_REG_GPIO_RX_DDR, 0x0); + write_reg(E100_REG_GPIO_TX_DDR, 0xFFFF); sleep(1); for (i=0; i < 16; i++) { - write_reg(UE_REG_GPIO_TX_IO, 1 << i); + write_reg(E100_REG_GPIO_TX_IO, 1 << i); sleep(1); if (test) { - data_in = read_reg(UE_REG_GPIO_RX_IO); + data_in = read_reg(E100_REG_GPIO_RX_IO); if (data_in != (1 << i)) printf("Read failed, wrote: %X read: %X\n", \ 1 << i, data_in); } } - write_reg(UE_REG_GPIO_RX_DDR, 0x0); - write_reg(UE_REG_GPIO_TX_DDR, 0x0); + write_reg(E100_REG_GPIO_RX_DDR, 0x0); + write_reg(E100_REG_GPIO_TX_DDR, 0x0); return 0; } diff --git a/host/usrp_e_utils/usrp-e-i2c.c b/host/usrp_e_utils/usrp-e-i2c.c deleted file mode 100644 index c6fd4c632..000000000 --- a/host/usrp_e_utils/usrp-e-i2c.c +++ /dev/null @@ -1,87 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <sys/ioctl.h> - -#include <linux/usrp_e.h> - -// Usage: usrp_e_i2c w address data0 data1 data 2 .... -// Usage: usrp_e_i2c r address count - -int main(int argc, char *argv[]) -{ - int fp, ret, i, tmp; - struct usrp_e_i2c *i2c_msg; - int direction, address, count; - - if (argc < 3) { - printf("Usage: usrp-e-i2c w address data0 data1 data2 ...\n"); - printf("Usage: usrp-e-i2c r address count\n"); - printf("All addresses and data in hex.\n"); - exit(-1); - } - - if (strcmp(argv[1], "r") == 0) { - direction = 0; - } else if (strcmp(argv[1], "w") == 0) { - direction = 1; - } else { - return -1; - } - - sscanf(argv[2], "%X", &address); - printf("Address = %X\n", address); - - fp = open("/dev/usrp_e0", O_RDWR); - printf("fp = %d\n", fp); - if (fp < 0) { - perror("Open failed"); - return -1; - } - -// sleep(1); - - if (direction) { - count = argc - 3; - } else { - sscanf(argv[3], "%X", &count); - } - printf("Count = %X\n", count); - - i2c_msg = malloc(sizeof(i2c_msg) + count * sizeof(char)); - - i2c_msg->addr = address; - i2c_msg->len = count; - - for (i = 0; i < count; i++) { - i2c_msg->data[i] = i; - } - - if (direction) { - // Write - - for (i=0; i<count; i++) { - sscanf(argv[3+i], "%X", &tmp); - i2c_msg->data[i] = tmp; - } - - ret = ioctl(fp, USRP_E_I2C_WRITE, i2c_msg); - printf("Return value from i2c_write ioctl: %d\n", ret); - } else { - // Read - - ret = ioctl(fp, USRP_E_I2C_READ, i2c_msg); - printf("Return value from i2c_read ioctl: %d\n", ret); - - printf("Ioctl: %d Data read :", ret); - for (i=0; i<count; i++) { - printf(" %X", i2c_msg->data[i]); - } - printf("\n"); - - } - return 0; -} diff --git a/host/usrp_e_utils/usrp-e-spi.c b/host/usrp_e_utils/usrp-e-spi.c deleted file mode 100644 index 5203f56a8..000000000 --- a/host/usrp_e_utils/usrp-e-spi.c +++ /dev/null @@ -1,54 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <sys/ioctl.h> - -#include <linux/usrp_e.h> - -// Usage: usrp_e_spi w|rb slave data - -int main(int argc, char *argv[]) -{ - int fp, slave, length, ret; - unsigned int data; - struct usrp_e_spi spi_dat; - - if (argc < 5) { - printf("Usage: usrp_e_spi w|rb slave transfer_length data\n"); - exit(-1); - } - - slave = atoi(argv[2]); - length = atoi(argv[3]); - data = atoll(argv[4]); - - printf("Data = %X\n", data); - - fp = open("/dev/usrp_e0", O_RDWR); - printf("fp = %d\n", fp); - if (fp < 0) { - perror("Open failed"); - return -1; - } - -// sleep(1); - - - spi_dat.slave = slave; - spi_dat.data = data; - spi_dat.length = length; - spi_dat.flags = UE_SPI_PUSH_FALL | UE_SPI_LATCH_RISE; - - if (*argv[1] == 'r') { - spi_dat.readback = 1; - ret = ioctl(fp, USRP_E_SPI, &spi_dat); - printf("Ioctl returns: %d, Data returned = %d\n", ret, spi_dat.data); - } else { - spi_dat.readback = 0; - ioctl(fp, USRP_E_SPI, &spi_dat); - } - - return 0; -} diff --git a/host/usrp_e_utils/usrp-e-utility.cpp b/host/usrp_e_utils/usrp-e-utility.cpp deleted file mode 100644 index 47a2c0900..000000000 --- a/host/usrp_e_utils/usrp-e-utility.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright 2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include <uhd/utils/safe_main.hpp> -#include <boost/program_options.hpp> -#include <boost/format.hpp> -#include <stdexcept> -#include <iostream> - -#include "fpga_downloader.cpp" -#include "clkgen_config.hpp" - -namespace po = boost::program_options; - -int UHD_SAFE_MAIN(int argc, char *argv[]){ - - //variables to be set by po - std::string fpga_path; - - //setup the program options - po::options_description desc("Allowed options"); - desc.add_options() - ("help", "help message") - ("fpga", po::value<std::string>(&fpga_path), "loads the specified FPGA file") - ("reclk", "runs the clock recovery") - ; - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - - //print the help message - if (vm.count("help")){ - std::cout << boost::format("UHD USRP-E Utility %s") % desc << std::endl; - return ~0; - } - - bool loaded_fpga_image = false; - if (vm.count("fpga") != 0){ - std::cout << "USRP-E Utility loading the FPGA..." << std::endl << std::endl; - usrp_e100_load_fpga(fpga_path); - loaded_fpga_image = true; - sleep(1); - } - - if (vm.count("reclk") != 0){ - std::cout << "USRP-E Utility running the clock recovery..." << std::flush; - //if an image was not loaded or specified, we load pass-through - if (fpga_path.empty()) throw std::runtime_error( - "Please specify the path to the pass-though FPGA image for your device.\n" - " usrp-e-utility --reclk --fpga=/usr/share/uhd/images/usrp_e1xx_pt_fpga.bin" - ); - clock_genconfig_main(); - } - - std::cout << "Done!" << std::endl; - - return 0; -} diff --git a/host/usrp_e_utils/usrp-e-wb-test.cpp b/host/usrp_e_utils/usrp-e-wb-test.cpp index 3d6a8d101..eab4caede 100644 --- a/host/usrp_e_utils/usrp-e-wb-test.cpp +++ b/host/usrp_e_utils/usrp-e-wb-test.cpp @@ -24,7 +24,7 @@ #include <fcntl.h> //open, close #include <linux/usrp_e.h> -#include "usrp_e100_regs.hpp" +#include "e100_regs.hpp" static const size_t num_test_iters = 10000000; @@ -88,21 +88,21 @@ int main(int, char *[]){ //make random values int random_test32 = ::random(); int random_test16 = ::random() & 0xffff; - int random_secs = ::random(); + //int random_secs = ::random(); //set a bunch of registers - poke16(UE_REG_MISC_TEST, random_test16); - poke32(UE_REG_SR_MISC_TEST32, random_test32); - poke32(UE_REG_TIME64_TICKS, 0); - poke32(UE_REG_TIME64_IMM, 1); //immediate - poke32(UE_REG_TIME64_SECS, random_secs); + poke16(E100_REG_MISC_TEST, random_test16); + poke32(E100_REG_SR_MISC_TEST32, random_test32); + //poke32(E100_REG_TIME64_TICKS, 0); + //poke32(E100_REG_TIME64_IMM, 1); //immediate + //poke32(E100_REG_TIME64_SECS, random_secs); //read a bunch of registers if ( - (peek16(UE_REG_MISC_TEST) == random_test16) and - (peek32(UE_REG_RB_MISC_TEST32) == random_test32) and - (peek32(UE_REG_RB_TIME_NOW_SECS) == random_secs) and -// (peek32(UE_REG_RB_TIME_NOW_TICKS) < 1000000) and + (peek16(E100_REG_MISC_TEST) == random_test16) and + (peek32(E100_REG_RB_MISC_TEST32) == random_test32) and +// (peek32(E100_REG_RB_TIME_NOW_SECS) == random_secs) and +// (peek32(E100_REG_RB_TIME_NOW_TICKS) < 1000000) and true) num_pass++; else num_fail++; } diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp index 3ea63c4bb..cb6d78255 100644 --- a/host/utils/uhd_usrp_probe.cpp +++ b/host/utils/uhd_usrp_probe.cpp @@ -18,13 +18,8 @@ #include <uhd/utils/safe_main.hpp> #include <uhd/device.hpp> #include <uhd/types/ranges.hpp> +#include <uhd/property_tree.hpp> #include <boost/algorithm/string.hpp> //for split -#include <uhd/usrp/device_props.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/usrp/codec_props.hpp> -#include <uhd/usrp/dsp_props.hpp> -#include <uhd/usrp/subdev_props.hpp> #include <uhd/usrp/dboard_id.hpp> #include <uhd/usrp/mboard_eeprom.hpp> #include <uhd/usrp/dboard_eeprom.hpp> @@ -56,17 +51,16 @@ static std::string make_border(const std::string &text){ return ss.str(); } -static std::string get_dsp_pp_string(const std::string &type, wax::obj dsp){ +static std::string get_dsp_pp_string(const std::string &type, property_tree::sptr tree, const property_tree::path_type &path){ std::stringstream ss; - ss << boost::format("%s DSP: %s") % type % dsp[usrp::DSP_PROP_NAME].as<std::string>() << std::endl; + ss << boost::format("%s DSP: %s") % type % path.leaf() << std::endl; //ss << std::endl; - ss << boost::format("Codec Rate: %f Msps") % (dsp[usrp::DSP_PROP_CODEC_RATE].as<double>()/1e6) << std::endl; - //ss << boost::format("Host Rate: %f Msps") % (dsp[usrp::DSP_PROP_HOST_RATE].as<double>()/1e6) << std::endl; - //ss << boost::format("Freq Shift: %f Mhz") % (dsp[usrp::DSP_PROP_FREQ_SHIFT].as<double>()/1e6) << std::endl; + meta_range_t freq_range = tree->access<meta_range_t>(path / "freq/range").get(); + ss << boost::format("Freq range: %.3f to %.3f Mhz") % (freq_range.start()/1e6) % (freq_range.stop()/1e6) << std::endl;; return ss.str(); } -static std::string prop_names_to_pp_string(const prop_names_t &prop_names){ +static std::string prop_names_to_pp_string(const std::vector<std::string> &prop_names){ std::stringstream ss; size_t count = 0; BOOST_FOREACH(const std::string &prop_name, prop_names){ ss << ((count++)? ", " : "") << prop_name; @@ -74,101 +68,117 @@ static std::string prop_names_to_pp_string(const prop_names_t &prop_names){ return ss.str(); } -static std::string get_subdev_pp_string(const std::string &type, wax::obj subdev){ +static std::string get_subdev_pp_string(const std::string &type, property_tree::sptr tree, const property_tree::path_type &path){ std::stringstream ss; - ss << boost::format("%s Subdev: %s") % type % subdev[usrp::SUBDEV_PROP_NAME].as<std::string>() << std::endl; + ss << boost::format("%s Subdev: %s") % type % path.leaf() << std::endl; //ss << std::endl; - prop_names_t ant_names(subdev[usrp::SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>()); - ss << boost::format("Antennas: %s") % prop_names_to_pp_string(ant_names) << std::endl; + ss << boost::format("Name: %s") % (tree->access<std::string>(path / "name").get()) << std::endl; + ss << boost::format("Antennas: %s") % prop_names_to_pp_string(tree->access<std::vector<std::string> >(path / "antenna/options").get()) << std::endl; + ss << boost::format("Sensors: %s") % prop_names_to_pp_string(tree->list(path / "sensors")) << std::endl; - freq_range_t freq_range(subdev[usrp::SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>()); + meta_range_t freq_range = tree->access<meta_range_t>(path / "freq/range").get(); ss << boost::format("Freq range: %.3f to %.3f Mhz") % (freq_range.start()/1e6) % (freq_range.stop()/1e6) << std::endl; - prop_names_t gain_names(subdev[usrp::SUBDEV_PROP_GAIN_NAMES].as<prop_names_t>()); + std::vector<std::string> gain_names = tree->list(path / "gains"); if (gain_names.size() == 0) ss << "Gain Elements: None" << std::endl; - BOOST_FOREACH(const std::string &gain_name, gain_names){ - gain_range_t gain_range(subdev[named_prop_t(usrp::SUBDEV_PROP_GAIN_RANGE, gain_name)].as<gain_range_t>()); - ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % gain_name % gain_range.start() % gain_range.stop() % gain_range.step() << std::endl; + BOOST_FOREACH(const std::string &name, gain_names){ + meta_range_t gain_range = tree->access<meta_range_t>(path / "gains" / name / "range").get(); + ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % name % gain_range.start() % gain_range.stop() % gain_range.step() << std::endl; } - ss << boost::format("Connection Type: %c") % char(subdev[usrp::SUBDEV_PROP_CONNECTION].as<usrp::subdev_conn_t>()) << std::endl; - ss << boost::format("Uses LO offset: %s") % (subdev[usrp::SUBDEV_PROP_USE_LO_OFFSET].as<bool>()? "Yes" : "No") << std::endl; + ss << boost::format("Connection Type: %s") % (tree->access<std::string>(path / "connection").get()) << std::endl; + ss << boost::format("Uses LO offset: %s") % ((tree->access<bool>(path / "use_lo_offset").get())? "Yes" : "No") << std::endl; return ss.str(); } -static std::string get_codec_pp_string(const std::string &type, wax::obj codec){ +static std::string get_codec_pp_string(const std::string &type, property_tree::sptr tree, const property_tree::path_type &path){ std::stringstream ss; - ss << boost::format("%s Codec: %s") % type % codec[usrp::CODEC_PROP_NAME].as<std::string>() << std::endl; + ss << boost::format("%s Codec: %s") % type % path.leaf() << std::endl; //ss << std::endl; - prop_names_t gain_names(codec[usrp::CODEC_PROP_GAIN_NAMES].as<prop_names_t>()); + + ss << boost::format("Name: %s") % (tree->access<std::string>(path / "name").get()) << std::endl; + std::vector<std::string> gain_names = tree->list(path / "gains"); if (gain_names.size() == 0) ss << "Gain Elements: None" << std::endl; - BOOST_FOREACH(const std::string &gain_name, gain_names){ - gain_range_t gain_range(codec[named_prop_t(usrp::CODEC_PROP_GAIN_RANGE, gain_name)].as<gain_range_t>()); - ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % gain_name % gain_range.start() % gain_range.stop() % gain_range.step() << std::endl; + BOOST_FOREACH(const std::string &name, gain_names){ + meta_range_t gain_range = tree->access<meta_range_t>(path / "gains" / name / "range").get(); + ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % name % gain_range.start() % gain_range.stop() % gain_range.step() << std::endl; } return ss.str(); } -static std::string get_dboard_pp_string(const std::string &type, wax::obj dboard){ +static std::string get_dboard_pp_string(const std::string &type, property_tree::sptr tree, const property_tree::path_type &path){ std::stringstream ss; - ss << boost::format("%s Dboard: %s") % type % dboard[usrp::DBOARD_PROP_NAME].as<std::string>() << std::endl; + ss << boost::format("%s Dboard: %s") % type % path.leaf() << std::endl; //ss << std::endl; - usrp::dboard_eeprom_t db_eeprom = dboard[usrp::DBOARD_PROP_DBOARD_EEPROM].as<usrp::dboard_eeprom_t>(); + const std::string prefix = (type == "RX")? "rx" : "tx"; + usrp::dboard_eeprom_t db_eeprom = tree->access<usrp::dboard_eeprom_t>(path / (prefix + "_eeprom")).get(); if (db_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("ID: %s") % db_eeprom.id.to_pp_string() << std::endl; if (not db_eeprom.serial.empty()) ss << boost::format("Serial: %s") % db_eeprom.serial << std::endl; if (type == "TX"){ - usrp::dboard_eeprom_t gdb_eeprom = dboard[usrp::DBOARD_PROP_GBOARD_EEPROM].as<usrp::dboard_eeprom_t>(); - if (gdb_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("GDB ID: %s") % gdb_eeprom.id.to_pp_string() << std::endl; - if (not gdb_eeprom.serial.empty()) ss << boost::format("GDB Serial: %s") % gdb_eeprom.serial << std::endl; + usrp::dboard_eeprom_t gdb_eeprom = tree->access<usrp::dboard_eeprom_t>(path / "gdb_eeprom").get(); + if (gdb_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("ID: %s") % gdb_eeprom.id.to_pp_string() << std::endl; + if (not gdb_eeprom.serial.empty()) ss << boost::format("Serial: %s") % gdb_eeprom.serial << std::endl; } - BOOST_FOREACH(const std::string &subdev_name, dboard[usrp::DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>()){ - ss << make_border(get_subdev_pp_string(type, dboard[named_prop_t(usrp::DBOARD_PROP_SUBDEV, subdev_name)])); + BOOST_FOREACH(const std::string &name, tree->list(path / (prefix + "_frontends"))){ + ss << make_border(get_subdev_pp_string(type, tree, path / (prefix + "_frontends") / name)); } - ss << make_border(get_codec_pp_string(type, dboard[usrp::DBOARD_PROP_CODEC])); + ss << make_border(get_codec_pp_string(type, tree, path.branch_path().branch_path() / (prefix + "_codecs") / path.leaf())); return ss.str(); } -static std::string get_mboard_pp_string(wax::obj mboard){ +static std::string get_mboard_pp_string(property_tree::sptr tree, const property_tree::path_type &path){ std::stringstream ss; - ss << boost::format("Mboard: %s") % mboard[usrp::MBOARD_PROP_NAME].as<std::string>() << std::endl; + ss << boost::format("Mboard: %s") % (tree->access<std::string>(path / "name").get()) << std::endl; //ss << std::endl; - usrp::mboard_eeprom_t mb_eeprom = mboard[usrp::MBOARD_PROP_EEPROM_MAP].as<usrp::mboard_eeprom_t>(); + usrp::mboard_eeprom_t mb_eeprom = tree->access<usrp::mboard_eeprom_t>(path / "eeprom").get(); BOOST_FOREACH(const std::string &key, mb_eeprom.keys()){ if (not mb_eeprom[key].empty()) ss << boost::format("%s: %s") % key % mb_eeprom[key] << std::endl; } - BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>()){ - ss << make_border(get_dsp_pp_string("RX", mboard[named_prop_t(usrp::MBOARD_PROP_RX_DSP, dsp_name)])); + ss << std::endl; + ss << "Time sources: " << prop_names_to_pp_string(tree->access<std::vector<std::string> >(path / "time_source" / "options").get()) << std::endl; + ss << "Clock sources: " << prop_names_to_pp_string(tree->access<std::vector<std::string> >(path / "clock_source" / "options").get()) << std::endl; + ss << "Sensors: " << prop_names_to_pp_string(tree->list(path / "sensors")) << std::endl; + BOOST_FOREACH(const std::string &name, tree->list(path / "rx_dsps")){ + ss << make_border(get_dsp_pp_string("RX", tree, path / "rx_dsps" / name)); } - BOOST_FOREACH(const std::string &db_name, mboard[usrp::MBOARD_PROP_RX_DBOARD_NAMES].as<prop_names_t>()){ - ss << make_border(get_dboard_pp_string("RX", mboard[named_prop_t(usrp::MBOARD_PROP_RX_DBOARD, db_name)])); + BOOST_FOREACH(const std::string &name, tree->list(path / "dboards")){ + ss << make_border(get_dboard_pp_string("RX", tree, path / "dboards" / name)); } - BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>()){ - ss << make_border(get_dsp_pp_string("TX", mboard[named_prop_t(usrp::MBOARD_PROP_TX_DSP, dsp_name)])); + BOOST_FOREACH(const std::string &name, tree->list(path / "tx_dsps")){ + ss << make_border(get_dsp_pp_string("TX", tree, path / "tx_dsps" / name)); } - BOOST_FOREACH(const std::string &db_name, mboard[usrp::MBOARD_PROP_TX_DBOARD_NAMES].as<prop_names_t>()){ - ss << make_border(get_dboard_pp_string("TX", mboard[named_prop_t(usrp::MBOARD_PROP_TX_DBOARD, db_name)])); + BOOST_FOREACH(const std::string &name, tree->list(path / "dboards")){ + ss << make_border(get_dboard_pp_string("TX", tree, path / "dboards" / name)); } return ss.str(); } -static std::string get_device_pp_string(device::sptr dev){ +static std::string get_device_pp_string(property_tree::sptr tree){ std::stringstream ss; - ss << boost::format("Device: %s") % (*dev)[usrp::DEVICE_PROP_NAME].as<std::string>() << std::endl; + ss << boost::format("Device: %s") % (tree->access<std::string>("/name").get()) << std::endl; //ss << std::endl; - BOOST_FOREACH(const std::string &mboard_name, (*dev)[usrp::DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>()){ - ss << make_border(get_mboard_pp_string((*dev)[named_prop_t(usrp::DEVICE_PROP_MBOARD, mboard_name)])); + BOOST_FOREACH(const std::string &name, tree->list("/mboards")){ + ss << make_border(get_mboard_pp_string(tree, "/mboards/" + name)); } return ss.str(); } +void print_tree(const uhd::property_tree::path_type &path, uhd::property_tree::sptr tree){ + std::cout << path << std::endl; + BOOST_FOREACH(const std::string &name, tree->list(path)){ + print_tree(path / name, tree); + } +} + int UHD_SAFE_MAIN(int argc, char *argv[]){ po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") ("args", po::value<std::string>()->default_value(""), "device address args") + ("tree", "specify to print a complete property tree") ; po::variables_map vm; @@ -182,8 +192,10 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ } device::sptr dev = device::make(vm["args"].as<std::string>()); + property_tree::sptr tree = (*dev)[0].as<property_tree::sptr>(); - std::cout << make_border(get_device_pp_string(dev)) << std::endl; + if (vm.count("tree") != 0) print_tree("/", tree); + else std::cout << make_border(get_device_pp_string(tree)) << std::endl; return 0; } diff --git a/host/utils/usrp1_init_eeprom.cpp b/host/utils/usrp1_init_eeprom.cpp index 39f091af4..5bc07daf6 100644 --- a/host/utils/usrp1_init_eeprom.cpp +++ b/host/utils/usrp1_init_eeprom.cpp @@ -17,7 +17,7 @@ #include <uhd/utils/safe_main.hpp> #include <uhd/device.hpp> -#include <uhd/usrp/device_props.hpp> +#include <uhd/property_tree.hpp> #include <boost/program_options.hpp> #include <boost/format.hpp> #include <iostream> @@ -65,8 +65,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << "Writing EEPROM data..." << std::endl; //uhd::device_addrs_t devs = uhd::device::find(found_addrs[i]); uhd::device::sptr dev = uhd::device::make(found_addrs[i]); - wax::obj mb = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD]; - mb[std::string("load_eeprom")] = vm["image"].as<std::string>(); + uhd::property_tree::sptr tree = (*dev)[0].as<uhd::property_tree::sptr>(); + tree->access<std::string>("/mboards/0/load_eeprom").set(vm["image"].as<std::string>()); } diff --git a/host/utils/usrp_burn_db_eeprom.cpp b/host/utils/usrp_burn_db_eeprom.cpp index 58417bd68..7ebbe7756 100644 --- a/host/utils/usrp_burn_db_eeprom.cpp +++ b/host/utils/usrp_burn_db_eeprom.cpp @@ -20,10 +20,9 @@ #include <uhd/device.hpp> #include <uhd/types/dict.hpp> #include <uhd/utils/assert_has.hpp> +#include <uhd/property_tree.hpp> #include <uhd/usrp/dboard_eeprom.hpp> -#include <uhd/usrp/device_props.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/usrp/dboard_props.hpp> +#include <boost/algorithm/string.hpp> #include <boost/program_options.hpp> #include <boost/format.hpp> #include <boost/assign.hpp> @@ -36,15 +35,6 @@ namespace po = boost::program_options; int UHD_SAFE_MAIN(int argc, char *argv[]){ //command line variables std::string args, slot, unit; - static const uhd::dict<std::string, mboard_prop_t> unit_to_db_prop = boost::assign::map_list_of - ("RX", MBOARD_PROP_RX_DBOARD) ("TX", MBOARD_PROP_TX_DBOARD) ("GDB", MBOARD_PROP_TX_DBOARD) - ; - static const uhd::dict<std::string, mboard_prop_t> unit_to_db_names_prop = boost::assign::map_list_of - ("RX", MBOARD_PROP_RX_DBOARD_NAMES) ("TX", MBOARD_PROP_TX_DBOARD_NAMES) ("GDB", MBOARD_PROP_TX_DBOARD_NAMES) - ; - static const uhd::dict<std::string, dboard_prop_t> unit_to_db_eeprom_prop = boost::assign::map_list_of - ("RX", DBOARD_PROP_DBOARD_EEPROM) ("TX", DBOARD_PROP_DBOARD_EEPROM) ("GDB", DBOARD_PROP_GBOARD_EEPROM) - ; po::options_description desc("Allowed options"); desc.add_options() @@ -70,34 +60,30 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ return ~0; } - //check inputs - if (not unit_to_db_prop.has_key(unit)){ - std::cout << "Error: specify RX or TX for unit" << std::endl; - return ~0; - } - //make the device and extract the dboard w/ property device::sptr dev = device::make(args); - uhd::prop_names_t dboard_names = (*dev)[DEVICE_PROP_MBOARD][unit_to_db_names_prop[unit]].as<uhd::prop_names_t>(); + uhd::property_tree::sptr tree = (*dev)[0].as<uhd::property_tree::sptr>(); + const uhd::property_tree::path_type db_root = "/mboards/0/dboards"; + std::vector<std::string> dboard_names = tree->list(db_root); if (dboard_names.size() == 1 and slot.empty()) slot = dboard_names.front(); uhd::assert_has(dboard_names, slot, "dboard slot name"); - wax::obj dboard = (*dev)[DEVICE_PROP_MBOARD][named_prop_t(unit_to_db_prop[unit], slot)]; - std::string prefix = unit + ":" + slot; - std::cout << boost::format("Reading EEPROM on %s dboard...") % prefix << std::endl; - dboard_eeprom_t db_eeprom = dboard[unit_to_db_eeprom_prop[unit]].as<dboard_eeprom_t>(); + std::cout << boost::format("Reading %s EEPROM on %s dboard...") % unit % slot << std::endl; + boost::to_lower(unit); + const uhd::property_tree::path_type db_path = db_root / slot / (unit + "_eeprom"); + dboard_eeprom_t db_eeprom = tree->access<dboard_eeprom_t>(db_path).get(); //------------- handle the dboard ID -----------------------------// if (vm.count("id")){ db_eeprom.id = dboard_id_t::from_string(vm["id"].as<std::string>()); - dboard[unit_to_db_eeprom_prop[unit]] = db_eeprom; + tree->access<dboard_eeprom_t>(db_path).set(db_eeprom); } std::cout << boost::format(" Current ID: %s") % db_eeprom.id.to_pp_string() << std::endl; //------------- handle the dboard serial--------------------------// if (vm.count("ser")){ db_eeprom.serial = vm["ser"].as<std::string>(); - dboard[unit_to_db_eeprom_prop[unit]] = db_eeprom; + tree->access<dboard_eeprom_t>(db_path).set(db_eeprom); } std::cout << boost::format(" Current serial: \"%s\"") % db_eeprom.serial << std::endl; diff --git a/host/utils/usrp_burn_mb_eeprom.cpp b/host/utils/usrp_burn_mb_eeprom.cpp index 20e1b58b1..9f2fa611a 100644 --- a/host/utils/usrp_burn_mb_eeprom.cpp +++ b/host/utils/usrp_burn_mb_eeprom.cpp @@ -17,8 +17,7 @@ #include <uhd/utils/safe_main.hpp> #include <uhd/device.hpp> -#include <uhd/usrp/device_props.hpp> -#include <uhd/usrp/mboard_props.hpp> +#include <uhd/property_tree.hpp> #include <uhd/usrp/mboard_eeprom.hpp> #include <boost/program_options.hpp> #include <boost/format.hpp> @@ -53,14 +52,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::cout << "Creating USRP device from address: " + args << std::endl; uhd::device::sptr dev = uhd::device::make(args); - //FIXME the default mboard for now (may be others) - wax::obj mboard = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD]; + uhd::property_tree::sptr tree = (*dev)[0].as<uhd::property_tree::sptr>(); std::cout << std::endl; if (true /*always readback*/){ std::cout << "Fetching current settings from EEPROM..." << std::endl; - uhd::usrp::mboard_eeprom_t mb_eeprom = \ - mboard[uhd::usrp::MBOARD_PROP_EEPROM_MAP].as<uhd::usrp::mboard_eeprom_t>(); + uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get(); if (not mb_eeprom.has_key(key)){ std::cerr << boost::format("Cannot find value for EEPROM[%s]") % key << std::endl; return ~0; @@ -71,7 +68,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ if (vm.count("val")){ uhd::usrp::mboard_eeprom_t mb_eeprom; mb_eeprom[key] = val; std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % key % val << std::endl; - mboard[uhd::usrp::MBOARD_PROP_EEPROM_MAP] = mb_eeprom; + tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom); std::cout << "Power-cycle the USRP device for the changes to take effect." << std::endl; std::cout << std::endl; } diff --git a/images/Makefile b/images/Makefile index 10e3eb7ba..04d828b60 100644 --- a/images/Makefile +++ b/images/Makefile @@ -227,7 +227,7 @@ endif ifdef HAS_XTCLSH _usrp_e100_fpga_dir = $(TOP_FPGA_DIR)/usrp2/top/E1x0 -_usrp_e100_fpga_bin = $(BUILT_IMAGES_DIR)/usrp_e100_fpga.bin +_usrp_e100_fpga_bin = $(BUILT_IMAGES_DIR)/usrp_e100_fpga_v2.bin IMAGES_LIST += $(_usrp_e100_fpga_bin) $(_usrp_e100_fpga_bin): $(GLOBAL_DEPS) |