diff --git a/Makefile b/Makefile index f59d898..9b2ffdc 100644 --- a/Makefile +++ b/Makefile @@ -41,11 +41,11 @@ shin: sbt "test:runMain test.testShinModule" testShin: - iverilog -Wall \ + iverilog -Wall \ -o ./tb/build/shinTest.iverilog \ -y ./generated/shin \ -I ./generated/shin \ - ./tb/shinTest/ShinTopTb.v + ./tb/shinTest/ShinTopSpiTb.v vvp -N ./tb/build/shinTest.iverilog -lxt2 vcdShin: diff --git a/src/main/scala/backBoard/shin/Interface.scala b/src/main/scala/backBoard/shin/Interface.scala index d8e0852..9073f3a 100644 --- a/src/main/scala/backBoard/shin/Interface.scala +++ b/src/main/scala/backBoard/shin/Interface.scala @@ -246,20 +246,16 @@ trait InterfaceCheckSM{ this: InterfaceBase => val dataw: UInt val isEnR: Bool - - mReg.txSM := RegEnable( dataw(2,1), 0.U, isEnW & addrSel === "h20".U ) - mReg.rxSM := RegEnable( dataw(4,3), 0.U, isEnW & addrSel === "h20".U ) - for( i <- 0 until 8 ){ cReg.smEnqAddr(i) := Cat( - RegEnable( dataw, 0.U, isEnW & addrSel === "h20".U ), - RegEnable( dataw, 0.U, isEnW & addrSel === "h20".U ) + RegEnable( dataw, 0.U, isEnW & addrSel === ("h200".U + (i*2).U) ), + RegEnable( dataw, 0.U, isEnW & addrSel === ("h201".U + (i*2).U) ) ) cReg.smDeqAddr(i) := Cat( - RegEnable( dataw, 0.U, isEnW & addrSel === "h20".U ), - RegEnable( dataw, 0.U, isEnW & addrSel === "h20".U ) + RegEnable( dataw, 0.U, isEnW & addrSel === ("h300".U + (i*2).U) ), + RegEnable( dataw, 0.U, isEnW & addrSel === ("h301".U + (i*2).U) ) ) } diff --git a/src/main/scala/backBoard/shin/SpiInterface.scala b/src/main/scala/backBoard/shin/SpiInterface.scala index cd4b74f..2241bc9 100644 --- a/src/main/scala/backBoard/shin/SpiInterface.scala +++ b/src/main/scala/backBoard/shin/SpiInterface.scala @@ -70,8 +70,8 @@ class SpiInterface extends Module{ // spiRegUp.io.enw := isSckPosedgeNext(1) & ~shiftCSn(1+1) & bitSel === 0.U & spiCmd === 1.U - io.isEnR := isSckPosedgeNext(0) & isSpiRead - io.isEnW := isSckPosedgeNext(1) & ~shiftCSn(1+1) & bitSel === 0.U & isSpiWrite + io.isEnR := isSckPosedgeNext(0) & bitSel === 0.U & byteSel >= 3.U & isSpiRead + io.isEnW := isSckPosedgeNext(1) & ~shiftCSn(1+1) & bitSel === 0.U & isSpiWrite & byteSel >= 4.U io.dataw := exReg when( shiftCSn(2) & ~shiftCSn(1) ){ @@ -90,7 +90,9 @@ class SpiInterface extends Module{ when( byteSel === 0.U || byteSel === 1.U) { //CS为低,且SCK上跳的第0byte addrSel := Cat( addrSel(14,0), shiftMOSI(1) ) } .otherwise{ // byteSel > 1.U - addrSel := addrSel + 1.U + when( isSckPosedgeNext(1) & byteSel >= 3.U & bitSel === 0.U ){ + addrSel := addrSel + 1.U + } } } diff --git a/tb/shinTest/ShinTopTb.v b/tb/shinTest/ShinTopBareTb.v similarity index 100% rename from tb/shinTest/ShinTopTb.v rename to tb/shinTest/ShinTopBareTb.v diff --git a/tb/shinTest/ShinTopSpiTb.v b/tb/shinTest/ShinTopSpiTb.v new file mode 100644 index 0000000..fb9fb78 --- /dev/null +++ b/tb/shinTest/ShinTopSpiTb.v @@ -0,0 +1,531 @@ +`timescale 1 ns / 1 ps + + +module ShinTopSpiTb( + +); + + reg clock; + reg reset; + reg clk8x; + + wire [3:0] dDat_w; + wire [3:0] uDat_w; + + reg [4:0] spi_sck; + reg [4:0] spi_mosi; + wire [4:0] spi_miso; + reg [4:0] spi_csn; + + + +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_ospi_sck (spi_sck[0]), + .io_ospi_mosi(spi_mosi[0]), + .io_ospi_miso(spi_miso[0]), + .io_ospi_csn (spi_csn[0]), + + .io_rsp_valid(), + .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_ospi_sck (spi_sck[1]), + .io_ospi_mosi(spi_mosi[1]), + .io_ospi_miso(spi_miso[1]), + .io_ospi_csn (spi_csn[1]), + + .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_ospi_sck (spi_sck[2]), + .io_ospi_mosi(spi_mosi[2]), + .io_ospi_miso(spi_miso[2]), + .io_ospi_csn (spi_csn[2]), + + .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_ospi_sck (spi_sck[3]), + .io_ospi_mosi(spi_mosi[3]), + .io_ospi_miso(spi_miso[3]), + .io_ospi_csn (spi_csn[3]), + + .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_ospi_sck (spi_sck[4]), + .io_ospi_mosi(spi_mosi[4]), + .io_ospi_miso(spi_miso[4]), + .io_ospi_csn (spi_csn[4]), + + .io_rsp_valid(), + .io_rsp_bits_isError(), + .io_rsp_bits_length() +); + + + + + + + + + +initial begin + clock = 0; + clk8x = 0; + reset = 0; + + spi_sck = 5'b0; + spi_mosi = 5'b0; + spi_csn = 5'b11111; + + #100 + reset <= 1; + + #240 + reset <= 0; + +#3000000 + $display("Time Out !!!"); + $stop; +end + +initial begin + forever begin #10 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 + + + + + + + + + + + + + + + + + + + + + + + + + + initial begin + for( integer i = 0; i < 5; i = i + 1 ) begin + forever begin + #1000 spi_sck[i] <= spi_csn[i] == 1'b0 ? ~spi_sck[i] : 1'b0; + end + end + end + + + + reg [7:0] txBuf[0:2047]; + reg [7:0] rxBuf[0:2047]; + + +task spi_trans( input [15:0] address, input [7:0] cmd, input [10:0] length, input [7:0] idx ); + reg [10:0] transCnt; + reg [7:0] exChangeReg; + begin + #10 + spi_csn[idx] <= 1'b0; + transCnt <= 0; + + exChangeReg <= address[7:0]; + repeat(8) begin + @(posedge spi_sck[idx]) #5 + exChangeReg <= {exChangeReg[6:0], spi_miso[idx]}; + spi_mosi[idx] <= exChangeReg[7]; + end + exChangeReg <= address[15:8]; + repeat(8) begin + @(posedge spi_sck[idx]) #5 + exChangeReg <= {exChangeReg[6:0], spi_miso[idx]}; + spi_mosi[idx] <= exChangeReg[7]; + end + exChangeReg <= cmd; + repeat(8) begin + @(posedge spi_sck[idx]) #5 + exChangeReg <= {exChangeReg[6:0], spi_miso[idx]}; + spi_mosi[idx] <= exChangeReg[7]; + end + + + while( transCnt < length ) begin + exChangeReg <= txBuf[transCnt]; + transCnt <= transCnt + 1; + repeat(8) begin + @(posedge spi_sck[idx]) #5 + exChangeReg <= {exChangeReg[6:0], spi_miso[idx]}; + spi_mosi[idx] <= exChangeReg[7]; + end + rxBuf[transCnt] <= exChangeReg; + + end + + @(negedge spi_sck[idx]) #5 + spi_csn[idx] <= 1'b1; + end +endtask + + +`define SPI_WRITE 8'h0 +`define SPI_READ 8'h1 + + +initial begin + + #1000 + //设置主站从站 + txBuf[0] = 8'h01; + spi_trans( (16'h0), (`SPI_WRITE), (1), (0) ); + + #1000 + txBuf[0] = 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] = 8'h03; + txBuf[1] = 8'h00; + spi_trans( (16'h0202), (`SPI_WRITE), (2), (0) ); + + //无子报文 + txBuf[0] = 8'h00; + txBuf[1] = 8'h01;//heeader length 0 嗅探包1 + txBuf[2] = 8'h00; + txBuf[3] = 8'h00; + spi_trans( (16'h1000), (`SPI_WRITE), (4), (0) ); //写入SM1 + + + + //发布请求 + txBuf[0] = 8'h04; + txBuf[1] = 8'h00; + spi_trans( (16'h21), (`SPI_WRITE), (2), (0) );//写入长度 + + txBuf[0] = 8'h01; + spi_trans( (16'h20), (`SPI_WRITE), (1), (0) );//发送SM0 接收SM0, 请求发送 + end + + + + + + + + // 顺序索引 + #50000 + #50000 + #50000 + + + begin + + + //设置SM1在写入0xd地址触发enq + txBuf[0] = 8'h0d; + txBuf[1] = 8'h00; + spi_trans( (16'h0202), (`SPI_WRITE), (2), (0) ); + + txBuf[0] = 8'h00; + txBuf[1] = 8'ha0;//heeader length 10 + txBuf[2] = 8'h00; + txBuf[3] = 8'h00; + + //子报文 + //设置顺序地址 + txBuf[4] = 8'h0; //设备索引 + txBuf[5] = 8'h0; //设备索引、类型 + txBuf[6] = $random; //地址 + txBuf[7] = $random; //地址 + txBuf[8] = 8'hd0; //命令d 负载长度2 + txBuf[9] = 8'd02; //负载长度2 + txBuf[10] = 8'h0; //工作计数0 + txBuf[11] = 8'h0; //工作计数0 + + txBuf[12] = 8'h0; //负载 + txBuf[13] = 8'h0; //负载 + spi_trans( (16'h1000), (`SPI_WRITE), (14), (0) ); //写入SM1 + + + + //发布请求 + txBuf[0] = 8'h0e; + txBuf[1] = 8'h00; + spi_trans( (16'h21), (`SPI_WRITE), (2), (0) );//写入长度 + + txBuf[0] = 8'h01; + spi_trans( (16'h20), (`SPI_WRITE), (1), (0) );//发送SM0 接收SM0, 请求发送 + + end + + + //读写 + #50000 + #50000 + #50000 + #50000 + + begin + + + + + //设置SM1在写入516地址触发enq + txBuf[0] = 8'h03; + txBuf[1] = 8'h02; + spi_trans( (16'h0202), (`SPI_WRITE), (2), (0) ); + + + txBuf[0] = 8'h20; + txBuf[1] = 8'h00;//heeader length 512 + txBuf[2] = 8'h00; + txBuf[3] = 8'h00; + + //子报文 + txBuf[4] = 8'h0; + txBuf[5] = 8'h8; //index = 2 + txBuf[6] = 8'h08; //地址 //SM0 + txBuf[7] = 8'h30; //地址 //偏置 + txBuf[8] = 8'h20; //命令2 长度56 + txBuf[9] = 8'd56; //长度 + txBuf[10] = $random; + txBuf[11] = $random; + + for( integer j = 0; j < 64-8; j = j + 1 ) begin + @(posedge clock) #3 + txBuf[12+j] = $random; + end + + //------------------------- + + //子报文 + txBuf[68] = 8'h0; + txBuf[69] = 8'h4; //index = 1 + txBuf[70] = 8'h08; //地址 //SM0 + txBuf[71] = 8'h40; //地址 //偏置 + txBuf[72] = 8'h10; //命令1 长度56 + txBuf[73] = 8'd56; //长度 + txBuf[74] = $random; + txBuf[75] = $random; + + for( integer j = 0; j < 64-8; j = j + 1 ) begin + @(posedge clock) #3 + txBuf[76+j] = $random; + end + + //------------------------- + + //子报文 + txBuf[132] = 8'h0; + txBuf[133] = 8'hc; //index = 3 + txBuf[134] = 8'h09; //地址 //SM1 + txBuf[135] = 8'h40; //地址 //偏置 + txBuf[136] = 8'h00; //命令0 长度56 + txBuf[137] = 8'd56; //长度 + txBuf[138] = $random; + txBuf[139] = $random; + + for( integer j = 0; j < 64-8; j = j + 1 ) begin + @(posedge clock) #3 + txBuf[140+j] = $random; + end + + //------------------------- + + for( integer i = 0 ; i < 5; i = i + 1) begin + //子报文 + txBuf[196+i*64+0] = $random; + txBuf[196+i*64+1] = 8'h0; //index = random + txBuf[196+i*64+2] = $random; + txBuf[196+i*64+3] = $random; + txBuf[196+i*64+4] = 8'h00; //命令0 长度56 + txBuf[196+i*64+5] = 8'd56; //长度 + txBuf[196+i*64+6] = $random; + txBuf[196+i*64+7] = $random; + + for( integer j = 0; j < 64-8; j = j + 1 ) begin + @(posedge clock) #3 + txBuf[196+i*64+8+j] = $random; + end + end + spi_trans( (16'h1000), (`SPI_WRITE), (516), (0) ); //写入SM1 + + + + //发布请求 + txBuf[0] = 8'h04; + txBuf[1] = 8'h02; + spi_trans( (16'h21), (`SPI_WRITE), (2), (0) );//写入长度 + + txBuf[0] = 8'h01; + spi_trans( (16'h20), (`SPI_WRITE), (1), (0) );//发送SM0 接收SM0, 请求发送 + + end + + + + // 同步 + #90000 + #90000 + #90000 + #90000 + #90000 + #90000 + #90000 + #90000 + #90000 + #90000 + #90000 + #90000 + #90000 + #90000 + + + begin + + + + //设置SM1在写入0x3地址触发enq + txBuf[0] = 8'h17; + txBuf[1] = 8'h00; + spi_trans( (16'h0202), (`SPI_WRITE), (2), (0) ); + + txBuf[0] = 8'h01; + txBuf[1] = 8'h40;//heeader length 20 + txBuf[2] = 8'h00; + txBuf[3] = 8'h00; + + //子报文 + //设置同步 + txBuf[4] = 8'h0; //设备索引 + txBuf[5] = 8'h0; //设备索引、类型 + txBuf[6] = $random; //地址 + txBuf[7] = $random; //地址 + txBuf[8] = 8'he0; //命令d 负载长度2 + txBuf[9] = 8'h0c; //负载长度c + txBuf[10] = 8'h0; //工作计数0 + txBuf[11] = 8'h0; //工作计数0 + + txBuf[12] = 0;//timeStamp[7:0]; //负载 + txBuf[13] = 0;//timeStamp[15:8]; //负载 + txBuf[14] = 0;//timeStamp[23:16]; //负载 + txBuf[15] = 0;//timeStamp[31:24]; //负载 + txBuf[16] = 0;//timeStamp[39:32]; //负载 + txBuf[17] = 0;//timeStamp[47:40]; //负载 + txBuf[18] = 0;//timeStamp[55:48]; //负载 + txBuf[19] = 0;//timeStamp[63:56]; //负载 + + txBuf[20] = 0;//s_ShinTop_Mst.masterParser.deltaTimeStamp[ 7: 0]; //负载 + txBuf[21] = 0;//s_ShinTop_Mst.masterParser.deltaTimeStamp[15: 8]; //负载 + txBuf[22] = 0;//s_ShinTop_Mst.masterParser.deltaTimeStamp[23:16]; //负载 + txBuf[23] = 0;//s_ShinTop_Mst.masterParser.deltaTimeStamp[31:24]; //负载 + + spi_trans( (16'h1000), (`SPI_WRITE), (24), (0) ); //写入SM1 + + + //发布请求 + txBuf[0] = 8'h18; + txBuf[1] = 8'h00; + spi_trans( (16'h21), (`SPI_WRITE), (2), (0) );//写入长度 + + txBuf[0] = 8'h01; + spi_trans( (16'h20), (`SPI_WRITE), (1), (0) );//发送SM0 接收SM0, 请求发送 + + + end + + +end + + +endmodule +