spi跨时钟域
This commit is contained in:
233
src/main/scala/backBoard/shin/NSpiInterface.scala
Normal file
233
src/main/scala/backBoard/shin/NSpiInterface.scala
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
package BACK
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
abstract class SyncSpiInterfaceBase extends Module with RequireAsyncReset{
|
||||||
|
val io = IO(new RegAccessInterfaceIO)
|
||||||
|
val qspi = IO(new QSPIInterfaceIO)
|
||||||
|
}
|
||||||
|
|
||||||
|
trait SyncSpiAsync{ this: SyncSpiInterfaceBase =>
|
||||||
|
|
||||||
|
val bitSel = withClockAndReset(~qspi.sck.asClock, qspi.csn){RegInit(0.U(3.W)) }
|
||||||
|
val byteSel = withClockAndReset(~qspi.sck.asClock, qspi.csn){RegInit(0.U(12.W))}
|
||||||
|
val exRego = withClockAndReset(~qspi.sck.asClock, qspi.csn){RegInit(0.U(8.W))}
|
||||||
|
val exRegi = withClockAndReset(~qspi.sck.asClock, qspi.csn){RegInit(0.U(8.W))}
|
||||||
|
|
||||||
|
qspi.miso := exRego(7, 4)
|
||||||
|
qspi.isDirIn := ~isSpiRead
|
||||||
|
|
||||||
|
when( true.B ){
|
||||||
|
bitSel := ~bitSel
|
||||||
|
}
|
||||||
|
|
||||||
|
when( bitSel.andR ){
|
||||||
|
byteSel := byteSel + 1.U
|
||||||
|
}
|
||||||
|
|
||||||
|
when( bitSel === 0.U ){
|
||||||
|
exRegi := Cat( 0.U, qspi.mosi )
|
||||||
|
}.otherwise{
|
||||||
|
exRegi := Cat( exRegi(3,0), qspi.mosi )
|
||||||
|
}
|
||||||
|
|
||||||
|
when( bitSel === 0.U ){
|
||||||
|
when((byteSel === 1.U || byteSel === 2.U || byteSel === 3.U ) ){
|
||||||
|
exRego := 0.U //地址1,cmd
|
||||||
|
} .elsewhen( isSpiRead ){
|
||||||
|
when( ~isPing_async ){ //取巧
|
||||||
|
exRego := datar_sync(0)
|
||||||
|
} .otherwise{
|
||||||
|
exRego := datar_sync(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} .otherwise{
|
||||||
|
exRego := exRego << 4
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val addrw_async = for( _ <- 0 until 2 ) yield { withClockAndReset(~qspi.sck.asClock, qspi.csn){ RegInit(0.U(16.W)) } }
|
||||||
|
val addrr_async = for( _ <- 0 until 2 ) yield { withClockAndReset(~qspi.sck.asClock, qspi.csn){ RegInit(0.U(16.W)) } }
|
||||||
|
val dataw_async = for( _ <- 0 until 2 ) yield { withClockAndReset(~qspi.sck.asClock, qspi.csn){ RegInit(0.U(8.W)) } }
|
||||||
|
val isEnR_async = for( _ <- 0 until 2 ) yield { withClockAndReset(~qspi.sck.asClock, qspi.csn){ RegInit(false.B) } }
|
||||||
|
val isEnW_async = for( _ <- 0 until 2 ) yield { withClockAndReset(~qspi.sck.asClock, qspi.csn){ RegInit(false.B) } }
|
||||||
|
|
||||||
|
val spiLen = withClockAndReset(~qspi.sck.asClock, qspi.csn){ RegInit(2.U(12.W)) }
|
||||||
|
val spiCnt = withClockAndReset(~qspi.sck.asClock, qspi.csn){ RegInit(0.U(12.W)) }
|
||||||
|
val isSpiWrite = withClockAndReset(~qspi.sck.asClock, qspi.csn){ RegInit(false.B) }
|
||||||
|
val isSpiRead = withClockAndReset(~qspi.sck.asClock, qspi.csn){ RegInit(false.B) }
|
||||||
|
val isPing_async = withClockAndReset(~qspi.sck.asClock, qspi.csn){ RegInit(false.B) }
|
||||||
|
|
||||||
|
when( isEnR_async(0) | isEnW_async(0) | isEnR_async(1) | isEnW_async(1) ){
|
||||||
|
spiCnt := spiCnt + 1.U
|
||||||
|
}
|
||||||
|
|
||||||
|
when( byteSel === 4.U & bitSel === 0.U ){
|
||||||
|
spiLen := Cat( exRegi, 0.U(8.W) )
|
||||||
|
} .elsewhen( byteSel === 4.U & bitSel.andR ){
|
||||||
|
spiLen := Cat( spiLen(11, 8), exRegi, 0.U(4.W) )
|
||||||
|
} .elsewhen( byteSel === 5.U & bitSel === 0.U ){
|
||||||
|
spiLen := Cat( spiLen(11, 4), exRegi )
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
trait SyncSpiSync{ this: SyncSpiInterfaceBase =>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class SyncQSpiInterface extends SyncSpiInterfaceBase
|
||||||
|
with SyncSpiAsync
|
||||||
|
with SyncSpiSync{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
when( bitSel === 0.U ){
|
||||||
|
when( byteSel === 1.U ){
|
||||||
|
addrw_async(0) := exRegi
|
||||||
|
addrw_async(1) := exRegi
|
||||||
|
} .elsewhen( byteSel === 2.U ) {
|
||||||
|
addrw_async(0) := Cat(addrw_async(7,0), exRegi)
|
||||||
|
addrw_async(1) := Cat(addrw_async(7,0), exRegi)
|
||||||
|
} .elsewhen( byteSel >= 5.U ){
|
||||||
|
when( ~isPing_async ){
|
||||||
|
addrw_async(0) := addrw_async(0) + 2.U
|
||||||
|
} .otherwise{
|
||||||
|
addrw_async(1) := addrw_async(1) + 2.U
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when( bitSel === 0.U ){
|
||||||
|
when( byteSel === 1.U ){
|
||||||
|
addrr_async(0) := exRegi
|
||||||
|
addrr_async(1) := exRegi
|
||||||
|
} .elsewhen( byteSel === 2.U ) {
|
||||||
|
addrr_async(0) := Cat(addrr_async(7,0), exRegi)
|
||||||
|
addrr_async(1) := Cat(addrr_async(7,0), exRegi)
|
||||||
|
}
|
||||||
|
} .otherwise{
|
||||||
|
when( byteSel >= 2.U ){
|
||||||
|
when( ~isPing_async ){
|
||||||
|
addrr_async(0) := addrr_async(0) + 2.U
|
||||||
|
} .otherwise{
|
||||||
|
addrr_async(1) := addrr_async(1) + 2.U
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
when( byteSel === 2.U & bitSel === 0.U ){ //CS为低,且SCK上跳的第0byte
|
||||||
|
when( qspi.mosi.extract(3) ){
|
||||||
|
isSpiRead := true.B
|
||||||
|
} .otherwise{
|
||||||
|
isSpiWrite := true.B
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when( bitSel === 0.U ){
|
||||||
|
when( byteSel > 3.U & isSpiWrite ){
|
||||||
|
when( ~isPing_async ){
|
||||||
|
dataw_async(0) := exRegi
|
||||||
|
} .otherwise{
|
||||||
|
dataw_async(1) := exRegi
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when( byteSel >= 2.U & bitSel.andR & (spiCnt < spiLen) & isSpiRead ){
|
||||||
|
when( ~isPing_async ){
|
||||||
|
isEnR_async(0) := true.B
|
||||||
|
} .otherwise{
|
||||||
|
isEnR_async(1) := true.B
|
||||||
|
}
|
||||||
|
} .elsewhen( bitSel === 0.U ){
|
||||||
|
isEnR_async(0) := false.B
|
||||||
|
isEnR_async(1) := false.B
|
||||||
|
}
|
||||||
|
|
||||||
|
when( byteSel >= 5.U & bitSel === 0.U & (spiCnt < spiLen) & isSpiWrite ){
|
||||||
|
when( ~isPing_async ){
|
||||||
|
isEnW_async(0) := true.B
|
||||||
|
} .otherwise{
|
||||||
|
isEnW_async(1) := true.B
|
||||||
|
}
|
||||||
|
} .elsewhen( bitSel.andR ){
|
||||||
|
isEnW_async(0) := false.B
|
||||||
|
isEnW_async(1) := false.B
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
when( isEnR_async(0) | isEnW_async(0) ){
|
||||||
|
assert( ~isPing_async )
|
||||||
|
isPing_async := true.B
|
||||||
|
} .elsewhen( isEnR_async(1) | isEnW_async(1) ){
|
||||||
|
assert( isPing_async )
|
||||||
|
isPing_async := false.B
|
||||||
|
}
|
||||||
|
|
||||||
|
val isPong_sync = RegInit(false.B)
|
||||||
|
|
||||||
|
val isEnW_sync = for( _ <- 0 until 2 ) yield { ShiftRegisters( isEnW_async(i), 3, false.B, true.B ) }
|
||||||
|
val isEnR_sync = for( _ <- 0 until 2 ) yield { ShiftRegisters( isEnR_async(i), 3, false.B, true.B ) }
|
||||||
|
|
||||||
|
val datar_sync = for( _ <- 0 until 2 ) yield { RegInit(0.U(8.W)) }
|
||||||
|
|
||||||
|
val isEnW = for( _ <- 0 until 2 ) yield { ~isEnW_sync(i)(2) & isEnW_sync(i)(1) }
|
||||||
|
val isEnR = for( _ <- 0 until 2 ) yield { ~isEnR_sync(i)(2) & isEnR_sync(i)(1) }
|
||||||
|
|
||||||
|
io.isEnW :=
|
||||||
|
( ~isPong_sync & isEnW(0) ) |
|
||||||
|
( isPong_sync & isEnW(1) )
|
||||||
|
|
||||||
|
io.isEnR :=
|
||||||
|
( ~isPong_sync & isEnR(0) ) |
|
||||||
|
( isPong_sync & isEnR(1) )
|
||||||
|
|
||||||
|
|
||||||
|
io.addrw := Mux1H(Seq(
|
||||||
|
~isPong_sync -> addrw_async(0),
|
||||||
|
isPong_sync -> addrw_async(1),
|
||||||
|
))
|
||||||
|
|
||||||
|
io.addrr := Mux1H(Seq(
|
||||||
|
~isPong_sync -> addrr_async(0),
|
||||||
|
isPong_sync -> addrr_async(1),
|
||||||
|
))
|
||||||
|
|
||||||
|
io.dataw := Mux1H(Seq(
|
||||||
|
~isPong_sync -> dataw_async(0),
|
||||||
|
isPong_sync -> dataw_async(1),
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
when( io.isEnR ){
|
||||||
|
when( RegNext(~isPong_sync, false.B) ){
|
||||||
|
datar_sync(0) := io.datar
|
||||||
|
} .otherwise{
|
||||||
|
datar_sync(1) := io.datar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when( io.isEnR | io.isEnW ){
|
||||||
|
isPong_sync := ~isPong_sync
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user