Skip to content

Commit 6864d09

Browse files
committed
soc: work on PipeCon connection for S4NoC
1 parent 04fd101 commit 6864d09

File tree

12 files changed

+108
-84
lines changed

12 files changed

+108
-84
lines changed

README.md

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,13 @@
55
Collection of different communication methods for chip mulitprocessors.
66

77
This repo shall include all the multicore communication we have done in
8-
[T-CREST](https://github.com/t-crest) as a standalone repo to make the
9-
work more useful.
8+
[T-CREST](https://github.com/t-crest) as a standalone repo to make the work more useful.
109

1110
We use a simple rd/wr/address/data/rdy interface, which maps
12-
dirctly to the Patmos OCPcore interface (A command is acked in the next
11+
directly to the Patmos OCPcore interface (A command is acked in the next
1312
clock cycle or later, IO devices need to be ready to accept a command
1413
during the ack cycle).
1514

16-
The S4NOC has currently a slightly different interface (no rdy needed).
17-
1815
The repo also contains a Wishbone wrapper.
1916

2017
We plan to provide a bridge to AXI, as AXI is not so super nice.
@@ -68,18 +65,15 @@ class PipeConIO(private val addrWidth: Int) extends Bundle {
6865
}
6966
```
7067

71-
```PipeCon``` itself is an abstract class, just containing the interface:
68+
```PipeCon``` itself is an abstract class, just containing the interface:
7269

7370
```scala
7471
abstract class PipeCon(addrWidth: Int) extends Module {
75-
val io = IO(new Bundle {
76-
val cpuPort = new PipeConIO(addrWidth)
77-
})
78-
val cp = io.cpuPort
72+
val cpuPort = IO(new PipeConIO(addrWidth))
7973
}
8074
```
8175

82-
The main rules define PipeCon:
76+
The main rules that define PipeCon:
8377

8478
* There are two transactions: read and write
8579
* The transaction command is valid for a single clock cycle
@@ -195,17 +189,17 @@ To analyze memory issues (e.g., increase the heap size with Xmx) use a ```.sbtop
195189
## TODO
196190

197191
* [x] Use and document the PipeCon, direction from slave
198-
* [ ] Use a better name for the PipeCon interface (not io)
199-
* [ ] Wrapper for OCP (in Patmos)
192+
* [x] Use a better name for the PipeCon interface (not io)
193+
* [x] Wrapper for OCP (in Patmos)
200194
* [ ] Integrate a simple multicore device with T-CREST
201-
* A multicore "Hello World"
195+
* A multicore "Hello World" also for the handbook
202196
* [ ] Run S4NOC with T-CREST
203197
* [ ] Move (copy) the fair arbiter from the Chisel book into this repo
204198
* [ ] Write a test for the arbiter (or delegate it)
205199
* [ ] Use that arbiter for access to the serial port in T-CREST (using the ip-contributions version)
206200
* [ ] Do traffic generators like in the Dally book
207201
* [ ] Provide blocking in the CPU interface if not data available or TX FIFO full
208-
* [x] DONE
202+
* [x] DONE
209203
* [ ] There is one in the Chisel book, compare them, maybe make them the same
210204
* [ ] Get one-way memory back in here
211205
* [ ] AXI wrapper

src/main/scala/s4noc/S4NoCTop.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class S4NoCTop(conf: Config) extends Module {
2121
for (i <- 0 until conf.n) {
2222
val ci = Module(new PipeConS4NoC(conf.width, Entry(UInt(conf.width.W))))
2323
s4noc.io.networkPort(i) <> ci.rv
24-
io.cpuPorts(i) <> ci.io.cpuPort
24+
io.cpuPorts(i) <> ci.cpuPort
2525
}
2626

2727
val cntReg = RegInit(0.U(32.W))

src/main/scala/s4noc/iotypes.scala renamed to src/main/scala/s4noc/ports.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import chisel3._
44

55

66
/**
7-
* Channel directions
8-
*/
7+
* Channel directions
8+
*/
99
object Const {
1010
val NORTH = 0
1111
val EAST = 1

src/main/scala/soc/HardwareLock.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@ class HardwareLock() extends PipeCon(2) {
1818
val lockReg = RegInit(false.B)
1919
val ackReg = RegInit(false.B)
2020
val readReg = RegInit(0.U)
21-
ackReg := cp.wr || cp.rd
22-
cp.ack := ackReg
21+
ackReg := cpuPort.wr || cpuPort.rd
22+
cpuPort.ack := ackReg
2323

24-
when (cp.rd) {
24+
when (cpuPort.rd) {
2525
readReg := 0.U
2626
when (!lockReg) {
2727
lockReg := true.B
2828
readReg := 1.U
2929
}
3030
}
31-
when (cp.wr) {
31+
when (cpuPort.wr) {
3232
lockReg := false.B
3333
}
34-
cp.rdData := readReg
34+
cpuPort.rdData := readReg
3535
}

src/main/scala/soc/HelloDevice.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,24 @@ class HelloDevice(coreId: Int) extends PipeCon(3) {
1414
// TODO: following five lines are duplicated in PipeConRV, back to PipeCon class?
1515
val addrReg = RegInit(0.U(3.W))
1616
val ackReg = RegInit(false.B)
17-
when (cp.rd) {
18-
addrReg := cp.address
17+
when (cpuPort.rd) {
18+
addrReg := cpuPort.address
1919
}
20-
cp.ack := ackReg
20+
cpuPort.ack := ackReg
2121

2222
val nr = coreId.U(32.W)
2323
val reg = RegInit(0.U(32.W))
24-
when (cp.wr) {
25-
reg := cp.wrData
24+
when (cpuPort.wr) {
25+
reg := cpuPort.wrData
2626
}
27-
ackReg := cp.wr || cp.rd
28-
cp.rdData := Mux(addrReg === 4.U, nr, reg)
27+
ackReg := cpuPort.wr || cpuPort.rd
28+
cpuPort.rdData := Mux(addrReg === 4.U, nr, reg)
2929
}
3030

3131
class MultiCoreHello(nrCores: Int) extends MultiCoreDevice(nrCores, 3) {
3232

3333
for(i <- 0 until nrCores) {
3434
val d = Module(new HelloDevice(i))
35-
d.io.cpuPort <> ports(i)
35+
d.cpuPort <> ports(i)
3636
}
3737
}

src/main/scala/soc/PipeCon.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ import chisel3._
77
*
88
*/
99
abstract class PipeCon(addrWidth: Int) extends Module {
10-
val io = IO(new Bundle {
11-
val cpuPort = new PipeConIO(addrWidth)
12-
})
13-
val cp = io.cpuPort
10+
11+
val cpuPort = IO(new PipeConIO(addrWidth))
12+
1413
assert(addrWidth >= 2, "Address width needs some size for byte addresses")
1514
}
1615

src/main/scala/soc/PipeConRV.scala

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import s4noc.Entry
1313
* 8: write receiver, read sender
1414
* TODO: compare with Chisel book version
1515
* TODO: make it generic and do a subtype for s4noc
16+
* TODO: have some better tests
1617
*/
1718
class PipeConRV[T <: Data](private val addrWidth: Int, private val dt: T, s4noc: Boolean = false) extends PipeCon(addrWidth) {
1819

@@ -22,12 +23,21 @@ class PipeConRV[T <: Data](private val addrWidth: Int, private val dt: T, s4noc:
2223
val rx = rv.rx
2324

2425
val ackReg = RegInit(false.B)
25-
cp.ack := ackReg
26+
ackReg := false.B
27+
cpuPort.ack := ackReg
28+
// just look at lower bits
29+
val address = cpuPort.address(3, 0)
2630

2731
val status = rx.valid ## tx.ready
2832

29-
// Two additional registers, used by S4NOC for addressing of nodes
30-
val txDestReg = RegInit(0.U(8.W))
33+
// This is ugly: two different transmit registers for two different types
34+
// dt should be usable here...
35+
val txDataReg = RegInit(0.U.asTypeOf(dt))
36+
val e = Wire(Entry(UInt(32.W)))
37+
e.data := 0.U
38+
e.core := 0.U
39+
val txS4NocReg = RegInit(e)
40+
// Aditional register, used by S4NOC for addressing of nodes
3141
val rxSourceReg = RegInit(0.U(8.W))
3242
// TODO: detect Entry type
3343
// println("Type: " + dt.isInstanceOf[Entry[UInt(32.W)]])
@@ -36,42 +46,43 @@ class PipeConRV[T <: Data](private val addrWidth: Int, private val dt: T, s4noc:
3646
rx.ready := false.B
3747
tx.valid := false.B
3848
if (s4noc) {
39-
val e = Wire(new Entry(UInt(32.W)))
40-
e.data := cp.wrData
41-
e.core := txDestReg
42-
rv.tx.bits := e
43-
cp.rdData := rv.rx.bits.asTypeOf(Entry(UInt(32.W))).data
49+
cpuPort.rdData := rx.bits.asTypeOf(Entry(UInt(32.W))).data
50+
tx.bits := txS4NocReg
4451
} else {
45-
rv.tx.bits := cp.wrData
46-
cp.rdData := rv.rx.bits
52+
cpuPort.rdData := rx.bits
53+
tx.bits := txDataReg
4754
}
4855

4956
val idle :: readStatus :: readSource :: readWait :: writeWait :: Nil = Enum(5)
5057
val stateReg = RegInit(idle)
51-
val wrDataReg = Reg(UInt(32.W))
5258

5359
def idleReaction() = {
54-
when (cp.wr) {
55-
// printf("Write %d to %d\n", cp.wrData, cp.address)
56-
when (cp.address === 8.U) {
57-
txDestReg := cp.wrData
60+
when (cpuPort.wr) {
61+
// printf("Write %d to %d\n", cp.wrData, address)
62+
when (address === 8.U) {
63+
txS4NocReg.core := cpuPort.wrData
5864
ackReg := true.B
59-
} .otherwise {
65+
} .elsewhen (address === 4.U) {
66+
/* lets not have this single cycle write for now
6067
tx.valid := true.B
6168
when (tx.ready) {
6269
ackReg := true.B
6370
} .otherwise {
64-
wrDataReg := cp.wrData
71+
txReg.data := cpuPort.wrData
6572
stateReg := writeWait
6673
}
74+
*/
75+
txDataReg := cpuPort.wrData
76+
txS4NocReg.data := cpuPort.wrData
77+
stateReg := writeWait
6778
}
6879
}
69-
when (cp.rd) {
70-
// printf("Read from %d\n", cp.address)
71-
when (cp.address === 0.U) {
80+
when (cpuPort.rd) {
81+
// printf("Read from %d\n", address)
82+
when (address === 0.U) {
7283
stateReg := readStatus
7384
ackReg := true.B
74-
} .elsewhen (cp.address === 8.U) {
85+
} .elsewhen (address === 8.U) {
7586
stateReg := readSource
7687
ackReg := true.B
7788
} .otherwise {
@@ -80,19 +91,20 @@ class PipeConRV[T <: Data](private val addrWidth: Int, private val dt: T, s4noc:
8091
}
8192
}
8293

83-
ackReg := false.B
8494
switch(stateReg) {
8595
is (idle) {
8696
idleReaction()
8797
}
8898
is (readStatus) {
89-
cp.rdData := status
99+
cpuPort.rdData := status
90100
stateReg := idle
101+
ackReg := false.B
91102
idleReaction()
92103
}
93104
is (readSource) {
94-
cp.rdData := rxSourceReg
105+
cpuPort.rdData := rxSourceReg
95106
stateReg := idle
107+
ackReg := false.B
96108
idleReaction()
97109
}
98110
is (readWait) {
@@ -103,19 +115,14 @@ class PipeConRV[T <: Data](private val addrWidth: Int, private val dt: T, s4noc:
103115
rxSourceReg := rx.bits.asTypeOf(Entry(UInt(32.W))).core
104116
}
105117
// this is different from write - check
106-
cp.ack := true.B
118+
cpuPort.ack := true.B
119+
ackReg := false.B
107120
idleReaction()
108121
}
109122
}
110123

111124
is (writeWait) {
112125
tx.valid := true.B
113-
if (s4noc) {
114-
val e = tx.bits.asTypeOf(Entry(UInt(32.W)))
115-
e.data := wrDataReg
116-
} else {
117-
tx.bits := wrDataReg
118-
}
119126
when (tx.ready) {
120127
stateReg := idle
121128
ackReg := true.B

src/main/scala/wishbone/WBHardwareLock.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class WBHardwareLock() extends WishboneDevice(2) {
1111

1212
val wrapper = Module(new Wrapper(2))
1313
val hello = Module(new HardwareLock())
14-
wrapper.cpuIf.cpuPort <> hello.cp
14+
wrapper.cpuIf.cpuPort <> hello.cpuPort
1515
io.port <> wrapper.io.port
1616
}
1717

src/main/scala/wishbone/WrappedHello.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class WrappedHello() extends WishboneDevice(4) {
1111

1212
val wrapper = Module(new Wrapper(4))
1313
val hello = Module(new HelloDevice(42))
14-
wrapper.cpuIf.cpuPort <> hello.cp
14+
wrapper.cpuIf.cpuPort <> hello.cpuPort
1515
io.port <> wrapper.io.port
1616
}
1717

src/test/scala/soc/HelloTest.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class HelloTest extends AnyFlatSpec with ChiselScalatestTester {
1414

1515
def step() = d.clock.step()
1616

17-
val cp = d.io.cpuPort
17+
val cp = d.cpuPort
1818
cp.ack.expect(false.B)
1919

2020
// set some default values
@@ -130,7 +130,7 @@ class HelloTest extends AnyFlatSpec with ChiselScalatestTester {
130130
dut => {
131131
def step() = dut.clock.step()
132132

133-
val helper = new MemoryMappedIOHelper(dut.cp, dut.clock)
133+
val helper = new MemoryMappedIOHelper(dut.cpuPort, dut.clock)
134134

135135
helper.setTimeOut(10)
136136
helper.read(4)

0 commit comments

Comments
 (0)