-
Notifications
You must be signed in to change notification settings - Fork 33
SPI multiple subs functionality. #189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,6 +33,7 @@ class SpiMain extends Module { | |
| required Logic reset, | ||
| required Logic start, | ||
| required Logic busIn, | ||
| Logic? css, | ||
| super.name = 'spiMain'}) { | ||
| busIn = addInput('busIn', busIn, width: busIn.width); | ||
|
|
||
|
|
@@ -42,6 +43,10 @@ class SpiMain extends Module { | |
|
|
||
| start = addInput('start', start); | ||
|
|
||
| if (css != null) { | ||
| css = addInput('css', css, width: intf.multiChipSelects); | ||
| } | ||
|
|
||
| addOutput('busOut', width: busIn.width); | ||
|
|
||
| addOutput('done'); | ||
|
|
@@ -50,11 +55,15 @@ class SpiMain extends Module { | |
| ..pairConnectIO(this, intf, PairRole.provider); | ||
|
|
||
| final isRunning = Logic(name: 'isRunning'); | ||
| final active = Logic(name: 'enable'); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. did you mean to call this "active"? |
||
|
|
||
| // Active will be high when start is pulsed high or isRunning is high. | ||
| active <= start | isRunning; | ||
|
|
||
| // Counter to track of the number of bits shifted out. | ||
| final count = Counter.simple( | ||
| clk: ~clk, | ||
| enable: start | isRunning, | ||
| enable: active, | ||
| reset: reset, | ||
| asyncReset: true, | ||
| resetValue: busIn.width - 1, | ||
|
|
@@ -87,11 +96,21 @@ class SpiMain extends Module { | |
| // NOTE: dataStage0 corresponds to the last bit shifted in. | ||
| busOut <= shiftReg.stages.rswizzle(); | ||
|
|
||
| // SCLK runs off clk when isRunning is true or start is pulsed high. | ||
| intf.sclk <= ~clk & (isRunning | start); | ||
|
|
||
| // CS is active low. It will go low when isRunning or start is pulsed high. | ||
| intf.csb <= ~(isRunning | start); | ||
| // SCLK runs off clk when active. | ||
| intf.sclk <= ~clk & active; | ||
|
|
||
| // CS is active low. It will go low when active for single sub. | ||
| // if multiple sub, css will be used to control each csb. | ||
|
|
||
| if (css != null) { | ||
| for (var i = 0; i < intf.multiChipSelects; i++) { | ||
| intf.csb[i] <= ~(~css[i] & active); | ||
| } | ||
| } else { | ||
| for (var i = 0; i < intf.multiChipSelects; i++) { | ||
| intf.csb[i] <= ~active; | ||
| } | ||
| } | ||
|
|
||
| // MOSI is connected shift register dataOut. | ||
| intf.mosi <= | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,7 @@ class SpiSub extends Module { | |
| {required SpiInterface intf, | ||
| Logic? busIn, | ||
| Logic? reset, | ||
| bool triStateOutput = false, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. document triStateOutput |
||
| super.name = 'spiSub'}) { | ||
| // SPI Interface | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we add validation that the interface always has 1 CS? |
||
| intf = SpiInterface.clone(intf) | ||
|
|
@@ -50,10 +51,10 @@ class SpiSub extends Module { | |
|
|
||
| addOutput('done'); | ||
|
|
||
| // Counter to track of the number of bits shifted out. | ||
| // Counter to track the number of bits shifted out. | ||
| final count = Counter.simple( | ||
| clk: intf.sclk, | ||
| enable: ~intf.csb, | ||
| enable: ~intf.csb[0], | ||
| reset: reset, | ||
| asyncReset: true, | ||
| resetValue: intf.dataLength - 1, | ||
|
|
@@ -70,7 +71,7 @@ class SpiSub extends Module { | |
| // NOTE: Reset values are set to busIn values. | ||
| final shiftReg = ShiftRegister( | ||
| intf.mosi, | ||
| enable: ~intf.csb, | ||
| enable: ~intf.csb[0], | ||
| clk: intf.sclk, | ||
| depth: intf.dataLength, | ||
| reset: reset, | ||
|
|
@@ -82,12 +83,18 @@ class SpiSub extends Module { | |
| // NOTE: dataStage0 corresponds to the last bit shifted in. | ||
| busOut <= shiftReg.stages.rswizzle(); | ||
|
|
||
| // MISO is connected to shift register dataOut. | ||
| intf.miso <= | ||
| flop(~intf.sclk, shiftReg.dataOut, | ||
| en: ~intf.csb, | ||
| reset: reset, | ||
| asyncReset: true, | ||
| resetValue: busIn?[-1]); | ||
| // flop data from shift register dataOut. | ||
| final flopDataOut = FlipFlop(~intf.sclk, shiftReg.dataOut, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: why not keep it as a |
||
| en: ~intf.csb[0], | ||
| reset: reset, | ||
| asyncReset: true, | ||
| resetValue: busIn?[-1]); | ||
|
|
||
| // Connect flopDataOut to MISO via tri-state buffer if enabled. | ||
| if (triStateOutput) { | ||
| intf.miso <= TriStateBuffer(flopDataOut.q, enable: ~intf.csb[0]).out; | ||
| } else { | ||
| intf.miso <= flopDataOut.q; | ||
| } | ||
| } | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does the SPI checker need updating as well? |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,26 +14,31 @@ class SpiInterface extends PairInterface { | |
| /// The data length for serial transmissions on this interface. | ||
| final int dataLength; | ||
|
|
||
| /// The number of Chip Select signals in this interface. | ||
| final int multiChipSelects; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why no |
||
|
|
||
| /// Serial clock (SCLK). Clock signal from main to sub(s). | ||
| Logic get sclk => port('SCLK'); | ||
|
|
||
| /// Main Out Sub In (MOSI). Serial data from main to sub(s). | ||
| Logic get mosi => port('MOSI'); | ||
|
|
||
| /// Main In Sub Out (MISO). Serial data from sub(s) to main. | ||
| Logic get miso => port('MISO'); | ||
| LogicNet get miso => port('MISO') as LogicNet; | ||
|
|
||
| /// Chip select (active low). Chip select signal from main to sub. | ||
| Logic get csb => port('CSB'); | ||
| List<Logic> get csb => List.generate(multiChipSelects, (i) => port('CSB$i')); | ||
|
|
||
| /// Creates a new [SpiInterface]. | ||
| SpiInterface({this.dataLength = 1}) | ||
| SpiInterface({this.dataLength = 1, this.multiChipSelects = 1}) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. validation: do you want to check that these inputs are valid? both of these should be |
||
| : super( | ||
| portsFromConsumer: [Port('MISO')], | ||
| portsFromProvider: [Port('MOSI'), Port('CSB'), Port('SCLK')]); | ||
| portsFromConsumer: [LogicNet.port('MISO')], | ||
| portsFromProvider: [Port('MOSI'), Port('SCLK')] + | ||
| List.generate(multiChipSelects, (i) => Port('CSB$i'))); | ||
|
|
||
| /// Clones this [SpiInterface]. | ||
| SpiInterface.clone(SpiInterface super.otherInterface) | ||
| : dataLength = otherInterface.dataLength, | ||
| multiChipSelects = otherInterface.multiChipSelects, | ||
| super.clone(); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,7 +38,7 @@ class SpiMainDriver extends PendingClockedDriver<SpiPacket> { | |
| unawaited(super.run(phase)); | ||
|
|
||
| Simulator.injectAction(() { | ||
| intf.csb.put(1); | ||
| intf.csb[0].put(1); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is incomplete on the BFM side, right? we need ways to drive different CSB's, not just always 0 |
||
| intf.mosi.put(0); | ||
| }); | ||
|
|
||
|
|
@@ -48,7 +48,7 @@ class SpiMainDriver extends PendingClockedDriver<SpiPacket> { | |
| } else { | ||
| await clk.nextNegedge; | ||
| Simulator.injectAction(() { | ||
| intf.csb.put(1); | ||
| intf.csb[0].put(1); | ||
| _clkenable.inject(0); | ||
| intf.mosi.put(0); | ||
| }); | ||
|
|
@@ -61,7 +61,7 @@ class SpiMainDriver extends PendingClockedDriver<SpiPacket> { | |
|
|
||
| /// Drives a packet onto the interface. | ||
| Future<void> _drivePacket(SpiPacket packet) async { | ||
| intf.csb.inject(0); | ||
| intf.csb[0].inject(0); | ||
|
|
||
| // Loop through the bits of the packet | ||
| for (var i = 1; i <= packet.data.width; i++) { | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we add validation that the interface always has 1 CS? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add documentation for what
cssis