//exp/microboone/study2011/adc_interface_110204/ feb17,2011 //EP3SL1501152C4 //test 12bit octal adc: //remove adc inputs to simplify testing(nov20). //system clocks: //fsample = 2Mhz //fadc = 8fsample = 16Mhz (> 10Mhz and 50-50 dutycycle) //fsram = 64fsample = 128Mhz (for 64 channels/sram) //fclk = fadc = 16Mhz (clock to all modules with fsync) //fsync = fsample/frame = 625hz (frame=3200 samples/adc in 1.6msec) // (1600 words for 2samples/word) //lvds_receivers for octal 12bit adc ad9222: // 9 rx_channels by 6 dserialization // rx_inclock = fclk = 96Mhz // rx datarate = 12fclk = 192Mhz // rx_outclock = 32Mhz //for 64 input channels, 2mhz samples, and 1.6msec frame: //(64words)x(2mhz)x(1.6msec) = 205Kwords = (2doublewords)x(64mhz)x(1.6msec) module adc_interface_3 (clk16,clk128, syncin,runin,run0, clkl,clkr,rxreset, in0,in1,in2,in3,in4,in5,in6,in7, alignedleft,alignedright,lockedleft,lockedright, wdsync,blksync,phase,wrch,wrdat1,wrdat2,wrwd,wrblk,trigpointer, trigin, low,blocksize, test, align, testsample, testframe, testchannel, testph, testbase, data ); input clk16; //16Mhz system clock input clk128; //128Mhz clock from pll input runin; //system run state input syncin; //system sync input rxreset; input clkl; //96Mhz clk to left rx0 t0 rx3 input clkr; //96Mhz clk to right rx4 to rx7 input [8:0] in0; //lvds outputs from octal adc0 input [8:0] in1; //lvds outputs from octal adc1 input [8:0] in2; //lvds outputs from octal adc2 input [8:0] in3; //lvds outputs from octal adc3 input [8:0] in4; //lvds outputs from octal adc4 input [8:0] in5; //lvds outputs from octal adc5 input [8:0] in6; //lvds outputs from octal adc6 input [8:0] in7; //lvds outputs from octal adc7 output alignedleft; output alignedright; output lockedleft; output lockedright; output run0; //run state; output wdsync; //word boundry to sram output blksync; //block boundry to sram output phase; //wren to sram output [15:0] wrdat1; //fst adc-sample to sram output [15:0] wrdat2; //nxt adc-sample to sram output [2:0] wrblk; //block address to sram output [5:0] wrch; //channel address to sram output [10:0] wrwd; //word address to sram output [15:0] trigpointer; input trigin; input align; //align rx frames from control input low; //low level input [11:0] blocksize; //block size from control //test logic: input [1:0] test; //select testdata not adcdata input [11:0] testsample; input [15:0] testframe; input [5:0] testchannel; input [11:0] testph; input [11:0] testbase; input [15:0] data; //8 octal 12bit adc's clocked at 16Mwords/sec: wire alignedleft; wire alignedright; wire lockedleft; wire lockedright; adc32x12 adcl ( .rx_inclock (clkl), .clk16 (clk16), .in0 (in0), .in1 (in1), .in2 (in2), .in3 (in3), .rxreset (rxreset), .align (align), .alvalid (alignedleft), .rx_locked (lockedleft), .out0 (out0), .out1 (out1), .out2 (out2), .out3 (out3) ); adc32x12 adcr ( .rx_inclock (clkr), .clk16 (clk16), .in0 (in4), .in1 (in5), .in2 (in6), .in3 (in7), .rxreset (rxreset), .align (align), .alvalid (alignedright), .rx_locked (lockedright), .out0 (out4), .out1 (out5), .out2 (out6), .out3 (out7) ); //64 12bit words from 8 octal adc's at 16MHz: //12 bit words are in 8 octal groups of 8. wire [95:0] out0; wire [95:0] out1; wire [95:0] out2; wire [95:0] out3; wire [95:0] out4; wire [95:0] out5; wire [95:0] out6; wire [95:0] out7; //64 12bit words from the test data generator: wire [95:0] x0; wire [95:0] x1; wire [95:0] x2; wire [95:0] x3; wire [95:0] x4; wire [95:0] x5; wire [95:0] x6; wire [95:0] x7; reg run0; //system run reg sync; //system sync reg sync1,sync2; reg [2:0] div; //the divide by 8 reg [11:0] sample0; //the sample number counter reg [2:0] block0; //the block number counter reg [2:0] block1; reg [2:0] block; wire co; //inc's the sample# wire inc; //inc's the block# wire boundry0; datagenerator datagenerator ( .test (test), .testsample (testsample), .testframe (testframe), .testchannel (testchannel), .testph (testph), .testbase (testbase), .data (data), .clk16 (clk16), .run0 (run0), .boundry0 (boundry0), .sample0 (sample0), .div0 (div), .x0 (x0), .x1 (x1), .x2 (x2), .x3 (x3), .x4 (x4), .x5 (x5), .x6 (x6), .x7 (x7), .pulse () ); //multiplex adc data or test data: wire [95:0] mux0,mux1,mux2,mux3,mux4,mux5,mux6,mux7; assign mux0 = (test==0) ? out0 : x0; assign mux1 = (test==0) ? out1 : x1; assign mux2 = (test==0) ? out2 : x2; assign mux3 = (test==0) ? out3 : x3; assign mux4 = (test==0) ? out4 : x4; assign mux5 = (test==0) ? out5 : x5; assign mux6 = (test==0) ? out6 : x6; assign mux7 = (test==0) ? out7 : x7; //time base: //div by 8 defines the sample width by decimation. //sync or inc resets the sample number inc's the block#. //the block size parameter can be used to define inc period. //if sync is sent once to start the process, inc is used. //otherwise peiodic sync defines the blocksize (size>blksize). //size = 8clks/sample x #samples/block. //for 1.6msec blocks, //block inc is every 25,600 clk16's, //for 3200 2Mhz samples (1600 words). assign co = (div==3'b111); assign inc = run0 & (co & (sample0==blocksize)); always @ (posedge clk16) begin sync1 <= syncin; sync2 <= sync1; if (sync1 & !sync2) sync <= 1'b1; else sync <= 1'b0; if (!runin) run0 <= 1'b0; else if (runin & sync) run0 <= 1'b1; if (sync | inc) div <= 3'b000; else div <= div + 3'b001; if (sync | inc) sample0 <= 12'h000; else if (co) sample0 <= sample0 + 12'h001; else sample0 <= sample0; if (!run0) block0 <= 3'h0; else if (sync | inc) block0 <= block0 + 3'h1; else block0 <= block0; if (co & (sample0==1)) block1 <= block0; if (co) block <= block1; end //block boundry: assign boundry0 = run0 & (sync | inc); reg [1:0] delay; wire boundry; assign boundry = co & (delay==2'b11); always @ (posedge clk16) begin if (!run0) delay <= 2'b00; else if (boundry0) delay <= 2'b01; else if (co & (delay==2'b01)) delay <= 2'b10; else if (co & (delay==2'b10)) delay <= 2'b11; else if (co & (delay==2'b11)) delay <= 2'b00; end //trigger: //level0 trigger points to the time sample and block#. //trig and pointer held to the end of block; reg trg1,trg2; reg [15:0] pointer0,pointer1,pointer2,pointer; always @ (posedge clk16) begin trg1 <= trigin; trg2 <= trg1; if (!run0) pointer0 <= 16'd0; else if (trg1 & !trg2) pointer0 <= {1'b1,block0[2:0],sample0}; else if (sync | inc) pointer0 <= 16'h0000; else pointer0 <= pointer0; if (co) pointer1 <= pointer0; if (co) pointer2 <= pointer1; if (co) pointer <= pointer2; end //decimate 16Mhz adc sample rate to 2Mhz: wire en0; assign en0 = sync | inc | co; reg [95:0] nxt0b; reg [95:0] nxt1b; reg [95:0] nxt2b; reg [95:0] nxt3b; reg [95:0] nxt4b; reg [95:0] nxt5b; reg [95:0] nxt6b; reg [95:0] nxt7b; always @ (posedge clk16) begin if (en0) nxt0b <= mux0; if (en0) nxt1b <= mux1; if (en0) nxt2b <= mux2; if (en0) nxt3b <= mux3; if (en0) nxt4b <= mux4; if (en0) nxt5b <= mux5; if (en0) nxt6b <= mux6; if (en0) nxt7b <= mux7; end //data from the nxtb registers: reg [10:0] sample1; reg [95:0] nxt0a; reg [95:0] nxt1a; reg [95:0] nxt2a; reg [95:0] nxt3a; reg [95:0] nxt4a; reg [95:0] nxt5a; reg [95:0] nxt6a; reg [95:0] nxt7a; wire en1; assign en1 = co; always @ (posedge clk16) begin if (en1) nxt0a <= nxt0b; if (en1) nxt1a <= nxt1b; if (en1) nxt2a <= nxt2b; if (en1) nxt3a <= nxt3b; if (en1) nxt4a <= nxt4b; if (en1) nxt5a <= nxt5b; if (en1) nxt6a <= nxt6b; if (en1) nxt7a <= nxt7b; if (en1) sample1[10:0] <= sample0[11:1]; end //pair successive samples to reduce the wordrate by 2: //leading sample in bits[11:0], //following sample in bits[23:12]. reg [10:0] wordn; reg [191:0] dat0d; reg [191:0] dat1d; reg [191:0] dat2d; reg [191:0] dat3d; reg [191:0] dat4d; reg [191:0] dat5d; reg [191:0] dat6d; reg [191:0] dat7d; //pair sequential samples wire en3; assign en3 = co & !sample0[0]; always @ (posedge clk16) begin if (en3) wordn <= sample1; if (en3) dat0d[23:0] <= {nxt0b[11:0],nxt0a[11:0]}; if (en3) dat0d[47:24] <= {nxt0b[23:12],nxt0a[23:12]}; if (en3) dat0d[71:48] <= {nxt0b[35:24],nxt0a[35:24]}; if (en3) dat0d[95:72] <= {nxt0b[47:36],nxt0a[47:36]}; if (en3) dat0d[119:96] <= {nxt0b[59:48],nxt0a[59:48]}; if (en3) dat0d[143:120] <= {nxt0b[71:60],nxt0a[71:60]}; if (en3) dat0d[167:144] <= {nxt0b[83:72],nxt0a[83:72]}; if (en3) dat0d[191:168] <= {nxt0b[95:84],nxt0a[95:84]}; if (en3) dat1d[23:0] <= {nxt1b[11:0],nxt1a[11:0]}; if (en3) dat1d[47:24] <= {nxt1b[23:12],nxt1a[23:12]}; if (en3) dat1d[71:48] <= {nxt1b[35:24],nxt1a[35:24]}; if (en3) dat1d[95:72] <= {nxt1b[47:36],nxt1a[47:36]}; if (en3) dat1d[119:96] <= {nxt1b[59:48],nxt1a[59:48]}; if (en3) dat1d[143:120] <= {nxt1b[71:60],nxt1a[71:60]}; if (en3) dat1d[167:144] <= {nxt1b[83:72],nxt1a[83:72]}; if (en3) dat1d[191:168] <= {nxt1b[95:84],nxt1a[95:84]}; if (en3) dat2d[23:0] <= {nxt2b[11:0],nxt2a[11:0]}; if (en3) dat2d[47:24] <= {nxt2b[23:12],nxt2a[23:12]}; if (en3) dat2d[71:48] <= {nxt2b[35:24],nxt2a[35:24]}; if (en3) dat2d[95:72] <= {nxt2b[47:36],nxt2a[47:36]}; if (en3) dat2d[119:96] <= {nxt2b[59:48],nxt2a[59:48]}; if (en3) dat2d[143:120] <= {nxt2b[71:60],nxt2a[71:60]}; if (en3) dat2d[167:144] <= {nxt2b[83:72],nxt2a[83:72]}; if (en3) dat2d[191:168] <= {nxt2b[95:84],nxt2a[95:84]}; if (en3) dat3d[23:0] <= {nxt3b[11:0],nxt3a[11:0]}; if (en3) dat3d[47:24] <= {nxt3b[23:12],nxt3a[23:12]}; if (en3) dat3d[71:48] <= {nxt3b[35:24],nxt3a[35:24]}; if (en3) dat3d[95:72] <= {nxt3b[47:36],nxt3a[47:36]}; if (en3) dat3d[119:96] <= {nxt3b[59:48],nxt3a[59:48]}; if (en3) dat3d[143:120] <= {nxt3b[71:60],nxt3a[71:60]}; if (en3) dat3d[167:144] <= {nxt3b[83:72],nxt3a[83:72]}; if (en3) dat3d[191:168] <= {nxt3b[95:84],nxt3a[95:84]}; if (en3) dat4d[23:0] <= {nxt4b[11:0],nxt4a[11:0]}; if (en3) dat4d[47:24] <= {nxt4b[23:12],nxt4a[23:12]}; if (en3) dat4d[71:48] <= {nxt4b[35:24],nxt4a[35:24]}; if (en3) dat4d[95:72] <= {nxt4b[47:36],nxt4a[47:36]}; if (en3) dat4d[119:96] <= {nxt4b[59:48],nxt4a[59:48]}; if (en3) dat4d[143:120] <= {nxt4b[71:60],nxt4a[71:60]}; if (en3) dat4d[167:144] <= {nxt4b[83:72],nxt4a[83:72]}; if (en3) dat4d[191:168] <= {nxt4b[95:84],nxt4a[95:84]}; if (en3) dat5d[23:0] <= {nxt5b[11:0],nxt5a[11:0]}; if (en3) dat5d[47:24] <= {nxt5b[23:12],nxt5a[23:12]}; if (en3) dat5d[71:48] <= {nxt5b[35:24],nxt5a[35:24]}; if (en3) dat5d[95:72] <= {nxt5b[47:36],nxt5a[47:36]}; if (en3) dat5d[119:96] <= {nxt5b[59:48],nxt5a[59:48]}; if (en3) dat5d[143:120] <= {nxt5b[71:60],nxt5a[71:60]}; if (en3) dat5d[167:144] <= {nxt5b[83:72],nxt5a[83:72]}; if (en3) dat5d[191:168] <= {nxt5b[95:84],nxt5a[95:84]}; if (en3) dat6d[23:0] <= {nxt6b[11:0],nxt6a[11:0]}; if (en3) dat6d[47:24] <= {nxt6b[23:12],nxt6a[23:12]}; if (en3) dat6d[71:48] <= {nxt6b[35:24],nxt6a[35:24]}; if (en3) dat6d[95:72] <= {nxt6b[47:36],nxt6a[47:36]}; if (en3) dat6d[119:96] <= {nxt6b[59:48],nxt6a[59:48]}; if (en3) dat6d[143:120] <= {nxt6b[71:60],nxt6a[71:60]}; if (en3) dat6d[167:144] <= {nxt6b[83:72],nxt6a[83:72]}; if (en3) dat6d[191:168] <= {nxt6b[95:84],nxt6a[95:84]}; if (en3) dat7d[23:0] <= {nxt7b[11:0],nxt7a[11:0]}; if (en3) dat7d[47:24] <= {nxt7b[23:12],nxt7a[23:12]}; if (en3) dat7d[71:48] <= {nxt7b[35:24],nxt7a[35:24]}; if (en3) dat7d[95:72] <= {nxt7b[47:36],nxt7a[47:36]}; if (en3) dat7d[119:96] <= {nxt7b[59:48],nxt7a[59:48]}; if (en3) dat7d[143:120] <= {nxt7b[71:60],nxt7a[71:60]}; if (en3) dat7d[167:144] <= {nxt7b[83:72],nxt7a[83:72]}; if (en3) dat7d[191:168] <= {nxt7b[95:84],nxt7a[95:84]}; end //multiplex 64 words at 64Mwords/sec: reg [2:0] sync128; //defines sample# boundry reg ph; //inc channel# every other clk128 reg [5:0] ch; //channel address to the multiplexer wire wdb; //word boundry assign wdb = (sync128==7); wire blkb; //block boundry assign blkb = wdb & boundry; always @ (posedge clk128) begin if (!en3) sync128 <= 3'b000; else if (en3) sync128 <= sync128 + 3'b001; if (wdb) ph <= 1'b0; else ph <= !ph; if (wdb) ch <= 6'd0; else if (ph) ch <= ch + 6'h01; else ch <= ch; end //64 24bit words multiplexed by channel#: wire [23:0] result; //mux output mux64x24 adcmux ( .sel(ch[5:0]), .result(result), .data0x(dat0d[23:0]), .data1x(dat0d[47:24]), .data2x(dat0d[71:48]), .data3x(dat0d[95:72]), .data4x(dat0d[119:96]), .data5x(dat0d[143:120]), .data6x(dat0d[167:144]), .data7x(dat0d[191:168]), .data8x(dat1d[23:0]), .data9x(dat1d[47:24]), .data10x(dat1d[71:48]), .data11x(dat1d[95:72]), .data12x(dat1d[119:96]), .data13x(dat1d[143:120]), .data14x(dat1d[167:144]), .data15x(dat1d[191:168]), .data16x(dat2d[23:0]), .data17x(dat2d[47:24]), .data18x(dat2d[71:48]), .data19x(dat2d[95:72]), .data20x(dat2d[119:96]), .data21x(dat2d[143:120]), .data22x(dat2d[167:144]), .data23x(dat2d[191:168]), .data24x(dat3d[23:0]), .data25x(dat3d[47:24]), .data26x(dat3d[71:48]), .data27x(dat3d[95:72]), .data28x(dat3d[119:96]), .data29x(dat3d[143:120]), .data30x(dat3d[167:144]), .data31x(dat3d[191:168]), .data32x(dat4d[23:0]), .data33x(dat4d[47:24]), .data34x(dat4d[71:48]), .data35x(dat4d[95:72]), .data36x(dat4d[119:96]), .data37x(dat4d[143:120]), .data38x(dat4d[167:144]), .data39x(dat4d[191:168]), .data40x(dat5d[23:0]), .data41x(dat5d[47:24]), .data42x(dat5d[71:48]), .data43x(dat5d[95:72]), .data44x(dat5d[119:96]), .data45x(dat5d[143:120]), .data46x(dat5d[167:144]), .data47x(dat5d[191:168]), .data48x(dat6d[23:0]), .data49x(dat6d[47:24]), .data50x(dat6d[71:48]), .data51x(dat6d[95:72]), .data52x(dat6d[119:96]), .data53x(dat6d[143:120]), .data54x(dat6d[167:144]), .data55x(dat6d[191:168]), .data56x(dat7d[23:0]), .data57x(dat7d[47:24]), .data58x(dat7d[71:48]), .data59x(dat7d[95:72]), .data60x(dat7d[119:96]), .data61x(dat7d[143:120]), .data62x(dat7d[167:144]), .data63x(dat7d[191:168]) ); //output data to the sram at 64 Mwords/sec: reg [15:0] wrdat1; //fst sample of pair reg [15:0] wrdat2; //nxt sample of pair reg phase; //wren every other clk128 reg [2:0] wrblk; //block address reg [5:0] wrch; //channel address reg [10:0] wrwd; //word address reg wdsync; //word boundry at ch[63] reg blksync;//block boundry at end of block reg [15:0] trigpointer; //time sample, held for blksync always @ (posedge clk128) begin wdsync <= wdb; blksync <= blkb; wrdat1 <= {low,low,low,low,result[11:0]}; wrdat2 <= {low,low,low,low,result[23:12]}; wrblk <= block; wrch <= ch[5:0]; wrwd <= wordn; phase <= ph; trigpointer <= pointer; end endmodule