`timescale 1 ns / 1 ps module ShinTopSpiTb( ); reg clock; reg reset; reg clk8x; wire [3:0] dDat_w; wire [3:0] uDat_w; wire spi_sck; wire spi_mosi; wire [4:0] spi_miso; reg [14:0] spi_csn; wire qspi_sck; wire [3:0] qspi_mosi; wire [40-1:0] qspi_miso; wire isResp; ShinTop s_ShinTop_Mst( .clock(clock), .reset(reset), .io_clk8x(clk8x), .io_dDatIn(1'b0), .io_dDatOut(dDat_w[0]), .io_uDatIn(uDat_w[0]), .io_uDatOut(), .io_iqspi_sck(qspi_sck), .io_iqspi_mosi(qspi_mosi), .io_iqspi_miso(qspi_miso[3:0]), .io_iqspi_isDirIn(), .io_iqspi_csn(spi_csn[0]), .io_ospi_sck (spi_sck), .io_ospi_mosi(spi_mosi), .io_ospi_miso(spi_miso[0]), .io_ospi_csn (spi_csn[5]), .io_oqspi_sck(qspi_sck), .io_oqspi_mosi(qspi_mosi), .io_oqspi_miso(qspi_miso[4*5+3:4*5]), .io_oqspi_isDirIn(), .io_oqspi_csn(spi_csn[10]), .io_rsp_valid(isResp), .io_rsp_bits_isError(), .io_rsp_bits_length() ); ShinTop s_ShinTop_slv0( .clock(clock), .reset(reset), .io_clk8x(clk8x), .io_dDatIn(dDat_w[0]), .io_dDatOut(dDat_w[1]), .io_uDatIn(uDat_w[1]), .io_uDatOut(uDat_w[0]), .io_iqspi_sck(qspi_sck), .io_iqspi_mosi(qspi_mosi), .io_iqspi_miso(qspi_miso[4*1+3:4*1]), .io_iqspi_isDirIn(), .io_iqspi_csn(spi_csn[1]), .io_ospi_sck (spi_sck), .io_ospi_mosi(spi_mosi), .io_ospi_miso(spi_miso[1]), .io_ospi_csn (spi_csn[6]), .io_oqspi_sck(qspi_sck), .io_oqspi_mosi(qspi_mosi), .io_oqspi_miso(qspi_miso[4*6+3:4*6]), .io_oqspi_isDirIn(), .io_oqspi_csn(spi_csn[11]), .io_rsp_valid(), .io_rsp_bits_isError(), .io_rsp_bits_length() ); ShinTop s_ShinTop_slv1( .clock(clock), .reset(reset), .io_clk8x(clk8x), .io_dDatIn(dDat_w[1]), .io_dDatOut(dDat_w[2]), .io_uDatIn(uDat_w[2]), .io_uDatOut(uDat_w[1]), .io_iqspi_sck(qspi_sck), .io_iqspi_mosi(qspi_mosi), .io_iqspi_miso(qspi_miso[4*2+3:4*2]), .io_iqspi_isDirIn(), .io_iqspi_csn(spi_csn[2]), .io_ospi_sck (spi_sck), .io_ospi_mosi(spi_mosi), .io_ospi_miso(spi_miso[2]), .io_ospi_csn (spi_csn[7]), .io_oqspi_sck(qspi_sck), .io_oqspi_mosi(qspi_mosi), .io_oqspi_miso(qspi_miso[4*7+3:4*7]), .io_oqspi_isDirIn(), .io_oqspi_csn(spi_csn[12]), .io_rsp_valid(), .io_rsp_bits_isError(), .io_rsp_bits_length() ); ShinTop s_ShinTop_slv2( .clock(clock), .reset(reset), .io_clk8x(clk8x), .io_dDatIn(dDat_w[2]), .io_dDatOut(dDat_w[3]), .io_uDatIn(uDat_w[3]), .io_uDatOut(uDat_w[2]), .io_iqspi_sck(qspi_sck), .io_iqspi_mosi(qspi_mosi), .io_iqspi_miso(qspi_miso[4*3+3:4*3]), .io_iqspi_isDirIn(), .io_iqspi_csn(spi_csn[3]), .io_ospi_sck (spi_sck), .io_ospi_mosi(spi_mosi), .io_ospi_miso(spi_miso[3]), .io_ospi_csn (spi_csn[8]), .io_oqspi_sck(qspi_sck), .io_oqspi_mosi(qspi_mosi), .io_oqspi_miso(qspi_miso[4*8+3:4*8]), .io_oqspi_isDirIn(), .io_oqspi_csn(spi_csn[13]), .io_rsp_valid(), .io_rsp_bits_isError(), .io_rsp_bits_length() ); ShinTop s_ShinTop_slv3( .clock(clock), .reset(reset), .io_clk8x(clk8x), .io_dDatIn(dDat_w[3]), .io_dDatOut(), .io_uDatIn(1'b0), .io_uDatOut(uDat_w[3]), .io_iqspi_sck(qspi_sck), .io_iqspi_mosi(qspi_mosi), .io_iqspi_miso(qspi_miso[4*4+3:4*4]), .io_iqspi_isDirIn(), .io_iqspi_csn(spi_csn[4]), .io_ospi_sck (spi_sck), .io_ospi_mosi(spi_mosi), .io_ospi_miso(spi_miso[4]), .io_ospi_csn (spi_csn[9]), .io_oqspi_sck(qspi_sck), .io_oqspi_mosi(qspi_mosi), .io_oqspi_miso(qspi_miso[4*9+3:4*9]), .io_oqspi_isDirIn(), .io_oqspi_csn(spi_csn[14]), .io_rsp_valid(), .io_rsp_bits_isError(), .io_rsp_bits_length() ); initial begin clock = 0; clk8x = 0; reset = 0; spi_csn = ~15'b0; #100 reset <= 1; #240 reset <= 0; #10000000 $display("Time Out !!!"); $stop; end initial begin forever begin #20 clk8x <= ~clk8x; end end initial begin forever begin #80 clock <= ~clock; end end initial begin $dumpfile("./tb/build/wave.vcd"); //生成的vcd文件名称 $dumpvars(0, ShinTopSpiTb);//tb模块名称 end `define SCKFRE #640 reg sck = 0; initial begin forever begin `SCKFRE sck <= ~sck; end end assign spi_sck = sck; assign qspi_sck = sck; reg [7:0] txBuf[0:2047]; reg [7:0] rxBuf[0:2047]; reg [7:0] exChangeReg; assign spi_mosi = exChangeReg[7]; assign qspi_mosi = exChangeReg[7:4]; wire [3:0] qspi_mux_miso = ( qspi_miso[4*0+3:4*0] & ~{4{spi_csn[ 0]}}) | ( qspi_miso[4*1+3:4*1] & ~{4{spi_csn[ 1]}}) | ( qspi_miso[4*2+3:4*2] & ~{4{spi_csn[ 2]}}) | ( qspi_miso[4*3+3:4*3] & ~{4{spi_csn[ 3]}}) | ( qspi_miso[4*4+3:4*4] & ~{4{spi_csn[ 4]}}) | ( qspi_miso[4*5+3:4*5] & ~{4{spi_csn[10]}}) | ( qspi_miso[4*6+3:4*6] & ~{4{spi_csn[11]}}) | ( qspi_miso[4*7+3:4*7] & ~{4{spi_csn[12]}}) | ( qspi_miso[4*8+3:4*8] & ~{4{spi_csn[13]}}) | ( qspi_miso[4*9+3:4*9] & ~{4{spi_csn[14]}}); wire spi_mux_miso = ( spi_miso[0] & ~spi_csn[5] ) | ( spi_miso[1] & ~spi_csn[6] ) | ( spi_miso[2] & ~spi_csn[7] ) | ( spi_miso[3] & ~spi_csn[8] ) | ( spi_miso[4] & ~spi_csn[9] ); reg isReq = 0; reg isBusy = 0; reg [11:0] length; reg [7:0] idx; reg [11:0] transCnt; reg [11:0] byteCnt; reg [2:0] bitCnt; always @(posedge clock) begin if( isReq & sck == 0 ) begin isBusy <= #5 1'b1; transCnt <= #5 0; byteCnt <= #5 ~12'b0; bitCnt <= #5 ~3'b0; spi_csn[idx] <= #5 1'b0; exChangeReg <= txBuf[0]; end end wire isQspi = (idx >= 0 && idx <= 4) || idx >= 10; wire [11:0] nextByteCnt = byteCnt +1; always @(posedge sck) begin if( isBusy ) begin if( transCnt <= length ) begin if( isQspi ) begin bitCnt <= ~bitCnt; end else begin bitCnt <= bitCnt + 1; end if( &bitCnt ) begin byteCnt <= byteCnt +1; transCnt <= transCnt + 1; rxBuf[byteCnt] <= isQspi ? {exChangeReg[3:0], qspi_mux_miso} : {exChangeReg[6:0], spi_mux_miso}; if( txBuf[2] === 1 & nextByteCnt >= 4) begin $display("spi read out @ %x", exChangeReg); end if( txBuf[2] === 1 & nextByteCnt >= 3) begin exChangeReg <= isQspi ? {exChangeReg[3:0], qspi_mux_miso} : {exChangeReg[6:0], spi_mux_miso}; end else begin exChangeReg <= txBuf[nextByteCnt]; end end else begin if( isQspi ) begin exChangeReg <= {exChangeReg[3:0], qspi_mux_miso}; end else begin exChangeReg <= {exChangeReg[6:0], spi_mux_miso}; end end end else begin isBusy <= #5 1'b0; spi_csn[idx] <= #5 1'b1; end end end task spi_trans( input [15:0] saddress, input [7:0] scmd, input [12:0] slength,input [7:0] sidx ); begin txBuf[0] <= saddress[7:0]; txBuf[1] <= saddress[15:8]; txBuf[2] <= scmd; length <= slength + 3; idx <= sidx; #5 @(negedge sck) isReq <= 1; @(posedge sck) #5 isReq <= 0; @( negedge isBusy) #1000 begin end end endtask `define SPI_WRITE 8'h0 `define SPI_READ 8'h1 initial begin #1000 //设置主站从站 txBuf[0+3] = 8'h01; spi_trans( (16'h00), (`SPI_WRITE), (1), (0) ); #1000 txBuf[0+3] = 8'h02; spi_trans( (16'h0), (`SPI_WRITE), (1), (1) ); #1000 spi_trans( (16'h0), (`SPI_WRITE), (1), (2) ); #1000 spi_trans( (16'h0), (`SPI_WRITE), (1), (3) ); #1000 spi_trans( (16'h0), (`SPI_WRITE), (1), (4) ); //嗅探 #10000 begin //设置SM1在写入0x3地址触发enq txBuf[0+3] = 8'h03; txBuf[1+3] = 8'h00; spi_trans( (16'h0202), (`SPI_WRITE), (2), (0) ); //无子报文 txBuf[0+3] = 8'h00; txBuf[1+3] = 8'h01;//heeader length 0 嗅探包1 txBuf[2+3] = 8'h00; txBuf[3+3] = 8'h00; spi_trans( (16'h1000), (`SPI_WRITE), (4), (0) ); //写入SM1 //发布请求 txBuf[0+3] = 8'h04; txBuf[1+3] = 8'h00; spi_trans( (16'h21), (`SPI_WRITE), (2), (0) );//写入长度 txBuf[0+3] = 8'h01; spi_trans( (16'h20), (`SPI_WRITE), (1), (0) );//发送SM0 接收SM0, 请求发送 @(posedge isResp) #5 begin end end // 顺序索引 #50000 #50000 #50000 $display("index @ %d", s_ShinTop_Mst.interface__io_cReg_timeStamp); begin //设置SM1在写入0xd地址触发enq txBuf[0+3] = 8'h0d; txBuf[1+3] = 8'h00; spi_trans( (16'h0202), (`SPI_WRITE), (2), (0) ); txBuf[0+3] = 8'h00; txBuf[1+3] = 8'ha0;//heeader length 10 txBuf[2+3] = 8'h00; txBuf[3+3] = 8'h00; //子报文 //设置顺序地址 txBuf[4+3] = 8'h0; //设备索引 txBuf[5+3] = 8'h0; //设备索引、类型 txBuf[6+3] = $random; //地址 txBuf[7+3] = $random; //地址 txBuf[8+3] = 8'hd0; //命令d 负载长度2 txBuf[9+3] = 8'd02; //负载长度2 txBuf[10+3] = 8'h0; //工作计数0 txBuf[11+3] = 8'h0; //工作计数0 txBuf[12+3] = 8'h0; //负载 txBuf[13+3] = 8'h0; //负载 spi_trans( (16'h1000), (`SPI_WRITE), (14), (0) ); //写入SM1 //发布请求 txBuf[0+3] = 8'h0e; txBuf[1+3] = 8'h00; spi_trans( (16'h21), (`SPI_WRITE), (2), (0) );//写入长度 txBuf[0+3] = 8'h01; spi_trans( (16'h20), (`SPI_WRITE), (1), (0) );//发送SM0 接收SM0, 请求发送 @(posedge isResp) #5 begin end end //测试 spi_trans( (16'hc0), (`SPI_READ), (6), (3) );//发送SM0 接收SM0, 请求发送 //读写 #50000 #50000 #50000 #50000 $display("read&write @ %d", s_ShinTop_Mst.interface__io_cReg_timeStamp); begin //设置SM1在写入516地址触发enq txBuf[0+3] = 8'h03; txBuf[1+3] = 8'h02; spi_trans( (16'h0202), (`SPI_WRITE), (2), (0) ); txBuf[0+3] = 8'h20; txBuf[1+3] = 8'h00;//heeader length 512 txBuf[2+3] = 8'h00; txBuf[3+3] = 8'h00; //子报文 txBuf[4+3] = 8'h0; txBuf[5+3] = 8'h8; //index = 2 txBuf[6+3] = 8'h08; //地址 //SM0 txBuf[7+3] = 8'h30; //地址 //偏置 txBuf[8+3] = 8'h20; //命令2 长度56 txBuf[9+3] = 8'd56; //长度 txBuf[10+3] = $random; txBuf[11+3] = $random; for( integer j = 0; j < 64-8; j = j + 1 ) begin @(posedge clock) #3 txBuf[12+3+j] = $random; end //------------------------- //子报文 txBuf[68+3] = 8'h0; txBuf[69+3] = 8'h4; //index = 1 txBuf[70+3] = 8'h08; //地址 //SM0 txBuf[71+3] = 8'h40; //地址 //偏置 txBuf[72+3] = 8'h10; //命令1 长度56 txBuf[73+3] = 8'd56; //长度 txBuf[74+3] = $random; txBuf[75+3] = $random; for( integer j = 0; j < 64-8; j = j + 1 ) begin @(posedge clock) #3 txBuf[76+3+j] = $random; end //------------------------- //子报文 txBuf[132+3] = 8'h0; txBuf[133+3] = 8'hc; //index = 3 txBuf[134+3] = 8'h10; //地址 //SM1 txBuf[135+3] = 8'h40; //地址 //偏置 txBuf[136+3] = 8'h00; //命令0 长度56 txBuf[137+3] = 8'd56; //长度 txBuf[138+3] = $random; txBuf[139+3] = $random; for( integer j = 0; j < 64-8; j = j + 1 ) begin @(posedge clock) #3 txBuf[140+3+j] = $random; end //------------------------- for( integer i = 0 ; i < 5; i = i + 1) begin //子报文 txBuf[196+3+i*64+0] = $random; txBuf[196+3+i*64+1] = 8'h0; //index = random txBuf[196+3+i*64+2] = $random; txBuf[196+3+i*64+3] = $random; txBuf[196+3+i*64+4] = 8'h00; //命令0 长度56 txBuf[196+3+i*64+5] = 8'd56; //长度 txBuf[196+3+i*64+6] = $random; txBuf[196+3+i*64+7] = $random; for( integer j = 0; j < 64-8; j = j + 1 ) begin @(posedge clock) #3 txBuf[196+3+i*64+8+j] = $random; end end spi_trans( (16'h1000), (`SPI_WRITE), (516), (0) ); //写入SM1 //发布请求 txBuf[0+3] = 8'h04; txBuf[1+3] = 8'h02; spi_trans( (16'h21), (`SPI_WRITE), (2), (0) );//写入长度 txBuf[0+3] = 8'h01; spi_trans( (16'h20), (`SPI_WRITE), (1), (0) );//发送SM0 接收SM0, 请求发送 @(posedge isResp) #5 begin end end // 同步 #90000 #90000 #90000 #90000 #90000 #90000 #90000 #90000 #90000 #90000 #90000 #90000 #90000 #90000 $display("sync @ %d", s_ShinTop_Mst.interface__io_cReg_timeStamp); begin //设置SM1在写入0x3地址触发enq txBuf[0+3] = 8'h17; txBuf[1+3] = 8'h00; spi_trans( (16'h0202), (`SPI_WRITE), (2), (0) ); txBuf[0+3] = 8'h01; txBuf[1+3] = 8'h40;//heeader length 20 txBuf[2+3] = 8'h00; txBuf[3+3] = 8'h00; //子报文 //设置同步 txBuf[4+3] = 8'h0; //设备索引 txBuf[5+3] = 8'h0; //设备索引、类型 txBuf[6+3] = $random; //地址 txBuf[7+3] = $random; //地址 txBuf[8+3] = 8'he0; //命令d 负载长度2 txBuf[9+3] = 8'h0c; //负载长度c txBuf[10+3] = 8'h0; //工作计数0 txBuf[11+3] = 8'h0; //工作计数0 txBuf[12+3] = 0;//timeStamp[7:0]; //负载 txBuf[13+3] = 0;//timeStamp[15:8]; //负载 txBuf[14+3] = 0;//timeStamp[23:16]; //负载 txBuf[15+3] = 0;//timeStamp[31:24]; //负载 txBuf[16+3] = 0;//timeStamp[39:32]; //负载 txBuf[17+3] = 0;//timeStamp[47:40]; //负载 txBuf[18+3] = 0;//timeStamp[55:48]; //负载 txBuf[19+3] = 0;//timeStamp[63:56]; //负载 txBuf[20+3] = 0;//s_ShinTop_Mst.masterParser.deltaTimeStamp[ 7: 0]; //负载 txBuf[21+3] = 0;//s_ShinTop_Mst.masterParser.deltaTimeStamp[15: 8]; //负载 txBuf[22+3] = 0;//s_ShinTop_Mst.masterParser.deltaTimeStamp[23:16]; //负载 txBuf[23+3] = 0;//s_ShinTop_Mst.masterParser.deltaTimeStamp[31:24]; //负载 spi_trans( (16'h1000), (`SPI_WRITE), (24), (0) ); //写入SM1 //写入替换时间戳替换地址 txBuf[0+3] = 8'h0c; txBuf[1+3] = 8'hc0; spi_trans( (16'h24), (`SPI_WRITE), (2), (0) ); //写入替换时间戳替换地址寄存器 //发布请求 txBuf[0+3] = 8'h18; txBuf[1+3] = 8'h00; spi_trans( (16'h21), (`SPI_WRITE), (2), (0) );//写入长度 txBuf[0+3] = 8'h01; spi_trans( (16'h20), (`SPI_WRITE), (1), (0) );//发送SM0 接收SM0, 请求发送 @(posedge isResp) #5 begin end //清除替换时间戳替换地址 txBuf[0+3] = 8'h00; txBuf[1+3] = 8'h00; spi_trans( (16'h25), (`SPI_WRITE), (2), (0) ); //清除替换时间戳替换地址寄存器 //设定sync信号 //设置SM1在写入51地址触发enq txBuf[0+3] = 8'd51; txBuf[1+3] = 8'h00; spi_trans( (16'h0202), (`SPI_WRITE), (2), (0) ); //header txBuf[0+3] = 8'h03; txBuf[1+3] = 8'h00;//heeader length 48 txBuf[2+3] = 8'h00; txBuf[3+3] = 8'h00; //子报文 //设置同步相关寄存器 txBuf[4+3] = 8'h0; //设备索引 txBuf[5+3] = 8'h08; //设备索引、类型 //2号设备 txBuf[6+3] = 8'h01; //地址 txBuf[7+3] = 8'h20; //地址 0x120 txBuf[8+3] = 8'h10; //命令1 写入寄存器 负载长度2 txBuf[9+3] = 8'h28; //负载长度0x28 txBuf[10+3] = 8'h0; //工作计数0 txBuf[11+3] = 8'h0; //工作计数0 // txBuf[12+3] = 8'h0f; //负载0x120 0x0f 全部脉冲,全部使能 // txBuf[13+3] = 0; //负载0x121 // txBuf[14+3] = 10; //负载0x122 sync0脉冲宽度 10 // txBuf[15+3] = 0; //负载0x123 // txBuf[16+3] = 0; //负载0x124 sync1脉冲宽度 0 // txBuf[17+3] = 0; //负载0x125 // txBuf[18+3] = 1; //负载0x126 sync2脉冲宽度 1 // txBuf[19+3] = 0; //负载0x127 // txBuf[20+3] = 8'hff; //负载0x128 sync3脉冲宽度 最大 // txBuf[21+3] = 8'hff; //负载0x129 txBuf[12+3] = 8'hff; //负载0x120 0xff 全部电平,全部使能 txBuf[13+3] = 0; //负载0x121 txBuf[14+3] = 0; //负载0x122 sync0脉冲宽度 txBuf[15+3] = 0; //负载0x123 txBuf[16+3] = 0; //负载0x124 sync1脉冲宽度 txBuf[17+3] = 0; //负载0x125 txBuf[18+3] = 0; //负载0x126 sync2脉冲宽度 txBuf[19+3] = 0; //负载0x127 txBuf[20+3] = 0; //负载0x128 sync3脉冲宽度 txBuf[21+3] = 0; //负载0x129 txBuf[22+3] = 0; //负载0x12a empty txBuf[23+3] = 0; //负载0x12b txBuf[24+3] = 0; //负载0x12c txBuf[25+3] = 0; //负载0x12d txBuf[26+3] = 0; //负载0x12e txBuf[27+3] = 0; //负载0x12f //同步点 txBuf[28+3] = 8'h90; //负载0x130 同步点 txBuf[29+3] = 8'h88; //负载0x131 txBuf[30+3] = 0; //负载0x132 txBuf[31+3] = 0; //负载0x133 txBuf[32+3] = 0; //负载0x134 txBuf[33+3] = 0; //负载0x135 txBuf[34+3] = 0; //负载0x136 txBuf[35+3] = 0; //负载0x137 //周期 txBuf[36+3] = 8'hff; //负载0x138 txBuf[37+3] = 8'hf; //负载0x139 txBuf[38+3] = 0; //负载0x13a txBuf[39+3] = 0; //负载0x13b //0ffset sync1 txBuf[40+3] = 8'ha; //负载0x13c txBuf[41+3] = 0; //负载0x13d txBuf[42+3] = 0; //负载0x13e txBuf[43+3] = 0; //负载0x13f //0ffset sync2 txBuf[44+3] = 8'h0; //负载0x140 txBuf[45+3] = 0; //负载0x141 txBuf[46+3] = 0; //负载0x142 txBuf[47+3] = 0; //负载0x143 //0ffset sync3 txBuf[48+3] = 8'h0; //负载0x144 txBuf[49+3] = 8'h01; //负载0x145 txBuf[50+3] = 0; //负载0x146 txBuf[51+3] = 0; //负载0x147 spi_trans( (16'h1000), (`SPI_WRITE), (52), (0) ); //写入SM1 //发布请求 txBuf[0+3] = 8'd52; txBuf[1+3] = 8'h00; spi_trans( (16'h21), (`SPI_WRITE), (2), (0) );//写入长度 txBuf[0+3] = 8'h01; spi_trans( (16'h20), (`SPI_WRITE), (1), (0) );//发送SM0 接收SM0, 请求发送 @(posedge isResp) #5 begin end end //清脉冲 //设置SM1在写入19地址触发enq txBuf[0+3] = 0; //负载0x122 sync0脉冲宽度 txBuf[1+3] = 0; //负载0x123 txBuf[2+3] = 0; //负载0x124 sync1脉冲宽度 txBuf[3+3] = 0; //负载0x125 txBuf[4+3] = 0; //负载0x126 sync2脉冲宽度 txBuf[5+3] = 0; //负载0x127 txBuf[6+3] = 0; //负载0x128 sync3脉冲宽度 txBuf[7+3] = 0; //负载0x129 spi_trans( (16'h0122), (`SPI_WRITE), (8), (2) ); //slv2 end endmodule