Skip to content
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

Serial Peripheral Interface #148

Draft
wants to merge 33 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3305672
first spi and spi test commit
robtorx Sep 24, 2024
d6a0386
spi_test initial draft
robtorx Sep 24, 2024
ca33ba4
spi bfm initial draft
robtorx Sep 27, 2024
d5d9afe
debugging hang up
robtorx Sep 27, 2024
4eec552
temp fix for debug
robtorx Sep 27, 2024
d891897
basic functionality tested, accurate waveforms produced
robtorx Sep 27, 2024
a226460
BFM functioning, main and sub files renamed, needs read packet functi…
robtorx Oct 4, 2024
60511db
fixed simple protocol test, first draft of main hardware module
robtorx Oct 5, 2024
f47cc37
spi main updated, sub intial draft added
robtorx Oct 8, 2024
5ee62d3
updated shift register with async reset and individual stage resetValue
robtorx Oct 10, 2024
3063f15
fixed an exceeds line length
robtorx Oct 10, 2024
c4f626b
fixed clk tie off in async tests
robtorx Oct 10, 2024
b84efbd
Merge branch 'shiftReg' into spi
robtorx Oct 10, 2024
b4c4e52
initial spi components complete, initial testing
robtorx Oct 11, 2024
4e99353
main and sub tests almost complete. Both gasket tests in progress
robtorx Oct 23, 2024
242bdbb
main gasket tests good, sub has cycle delay, pair in progress
robtorx Oct 25, 2024
3cf5cfc
pair gaskets working, bfms wip
robtorx Dec 20, 2024
4e9e633
all basic tests passinggit add . reversed in main to sub bfm needed s…
robtorx Dec 20, 2024
0b961c6
draft push
robtorx Dec 31, 2024
a15faf0
consolidate onto spi.dart
robtorx Jan 10, 2025
979d933
cleanup
robtorx Jan 21, 2025
97e4577
adding done signal
robtorx Jan 22, 2025
2dc16c0
Merge remote-tracking branch 'origin/main' into spi
robtorx Jan 22, 2025
a69ab16
spi sub msb first fixed
robtorx Jan 23, 2025
026f2ba
shift reg asyncreset updated from sequential
robtorx Jan 23, 2025
cf25fc2
added asyncReset flag to counter
robtorx Jan 23, 2025
76c6d0f
spi sub done signal added
robtorx Jan 23, 2025
b499664
counter asyncReset tests added
robtorx Jan 24, 2025
8275358
more cleanup
robtorx Jan 24, 2025
acaeddc
spi checker added
robtorx Jan 25, 2025
aa8e0aa
final documentation add, small changes to gasket testing
robtorx Jan 27, 2025
ecd7c09
public doc change
robtorx Jan 27, 2025
29abd76
removed todos
robtorx Jan 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/components/shift_register.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ The `ShiftRegister` in ROHD-HCL is a configurable shift register including:
- support for any width data
- a configurable `depth` (which corresponds to the latency)
- an optional `enable`
- an optional `reset`
- if `reset` is provided, an optional `resetValue`
- an optional `reset` (synchronous or asynchronous)
- if `reset` is provided, an optional `resetValue` for all stages or each stage indvidually
- access to each of the `stages` output from each flop
2 changes: 2 additions & 0 deletions lib/rohd_hcl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export 'src/exceptions.dart';
export 'src/extrema.dart';
export 'src/fifo.dart';
export 'src/find.dart';
export 'src/gaskets/spi/spi_main.dart';
robtorx marked this conversation as resolved.
Show resolved Hide resolved
export 'src/gaskets/spi/spi_sub.dart';
export 'src/interfaces/interfaces.dart';
export 'src/memory/memories.dart';
export 'src/models/models.dart';
Expand Down
99 changes: 99 additions & 0 deletions lib/src/gaskets/spi/spi_main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright (C) 2024 Intel Corporation
robtorx marked this conversation as resolved.
Show resolved Hide resolved
// SPDX-License-Identifier: BSD-3-Clause
//
// spi_main.dart
// Implementation of SPI Main component.
//
// 2024 October 1
// Author: Roberto Torres <roberto.torres@intel.com>

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';

/// Main component for Serial Peripheral Interface (SPI).
class SpiMain extends Module {
/// Output bus from Main.
Logic get busOut => output('busOut');

/// Done signal from Main.
Logic get done => output('done');

/// Creates a SPI Main component that interfaces with [SpiInterface].
///
/// The SPI Main component will drive a clock signal on [SpiInterface.sclk],
/// chip select on [SpiInterface.csb], shift data out on [SpiInterface.mosi],
/// and shift data in from [SpiInterface.miso]. Data to shift out is provided
/// on [busIn]. Data shifted in from [SpiInterface.miso] will be available on
/// [busOut]. After data is available on [busIn], pulsing [reset] will load
/// the data, and pulsing [start] will begin transmitting data until all bits
/// from [busIn] are shifted out. After transmissions is complete [done]
/// signal will go high.
SpiMain(SpiInterface intf,
{required Logic clk,
required Logic reset,
required Logic start,
required Logic busIn,
super.name = 'spiMain'}) {
busIn = addInput('busIn', busIn, width: busIn.width);

clk = addInput('clk', clk);

reset = addInput('reset', reset);

start = addInput('start', start);

addOutput('busOut', width: busIn.width);

addOutput('done');

intf = SpiInterface.clone(intf)
..pairConnectIO(this, intf, PairRole.provider);

final isRunning = Logic(name: 'isRunning');

final count = Counter.simple(
clk: ~clk,
enable: start | isRunning,
reset: reset,
minValue: 1,
maxValue: busIn.width);

// Done signal will be high when the counter is at the max value.
done <= count.equalsMax;

// isRunning will be high when start is pulsed high or counter is not done.
isRunning <=
flop(
clk,
start | ~done,
reset: reset,
asyncReset: true,
);

// Shift register in from MISO.
// NOTE: Reset values are set to busIn values.
final shiftReg = ShiftRegister(
intf.miso,
clk: intf.sclk,
depth: intf.dataLength,
reset: reset,
asyncReset: true,
resetValue: busIn.elements,
);

// busOut bits are connected to the corresponding shift register data stage.
// 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);
robtorx marked this conversation as resolved.
Show resolved Hide resolved

// MOSI is connected shift register dataOut.
intf.mosi <=
flop(~intf.sclk, shiftReg.dataOut,
reset: reset, asyncReset: true, resetValue: busIn[-1]);
}
}
73 changes: 73 additions & 0 deletions lib/src/gaskets/spi/spi_sub.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// spi_sub.dart
// Implementation of SPI Sub component.
//
// 2024 October 4
// Author: Roberto Torres <roberto.torres@intel.com>

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';

/// Sub component for Serial Peripheral Interface (SPI).
class SpiSub extends Module {
/// Output bus from Sub.
Logic get busOut => output('busOut');

/// Creates a SPI Sub component that interfaces with [SpiInterface].
///
/// The SPI Sub component will enable via chip select from [SpiInterface.csb].
/// Clock signal will be received on [SpiInterface.sclk], data will shift in
/// from [SpiInterface.mosi], and shift data out from [SpiInterface.miso].
/// Data to shift out is provided from [busIn]. Data shifted in from
/// [SpiInterface.mosi] will be available on [busOut]. After data is available
/// on [busIn], pulsing [reset] will load the data, and a bit of data will be
/// transmitted per clock pulse.
SpiSub(
{required SpiInterface intf,
Logic? busIn,
Logic? reset,
super.name = 'spiSub'}) {
// SPI Interface
intf = SpiInterface.clone(intf)
..pairConnectIO(this, intf, PairRole.consumer);

// Bus Input to sub, if provided.
if (busIn != null) {
busIn = addInput('busIn', busIn, width: intf.dataLength);
}

// Reset signal for sub, if provided.
if (reset != null) {
reset = addInput('reset', reset);
}

// Bus Output from Sub
addOutput('busOut', width: intf.dataLength);

// Shift Register in from MOSI.
// NOTE: Reset values are set to busIn values.
final shiftReg = ShiftRegister(
intf.mosi,
enable: ~intf.csb,
clk: intf.sclk,
depth: intf.dataLength,
reset: reset,
asyncReset: true,
resetValue: busIn?.elements,
);

robtorx marked this conversation as resolved.
Show resolved Hide resolved
// busOut bits are connected to the corresponding shift register data stage.
// 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]);
}
}
1 change: 1 addition & 0 deletions lib/src/interfaces/interfaces.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
// SPDX-License-Identifier: BSD-3-Clause

export 'apb.dart';
export 'spi.dart';
41 changes: 41 additions & 0 deletions lib/src/interfaces/spi.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// spi.dart
// Definitions for Serial Peripheral Interface (SPI).
//
// 2024 September 23
// Author: Roberto Torres <roberto.torres@intel.com>

import 'package:rohd/rohd.dart';

/// A standard Serial Peripheral Interface.
class SpiInterface extends PairInterface {
/// The data length for serial transmissions on this interface.
final int dataLength;

/// Serial clock (SCLK). Clock signal from main to sub(s).
Logic get sclk => port('SCLK');
// TODO(rt): add CPOL/CPHA support
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before merging, better to turn these TODOs into issues on the ROHD-HCL repo (you can mention them in the PR)


/// 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');

/// Chip select (active low). Chip select signal from main to sub.
Logic get csb => port('CSB');
// TODO(rt): add multiple CSB support

/// Creates a new [SpiInterface].
SpiInterface({this.dataLength = 1})
: super(
portsFromConsumer: [Port('MISO')],
portsFromProvider: [Port('MOSI'), Port('CSB'), Port('SCLK')]);

/// Clones this [SpiInterface].
SpiInterface.clone(SpiInterface super.otherInterface)
: dataLength = otherInterface.dataLength,
super.clone();
}
1 change: 1 addition & 0 deletions lib/src/models/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export 'apb_bfm/apb_bfm.dart';
export 'memory_model.dart';
export 'ready_valid_bfm/ready_valid_bfm.dart';
export 'sparse_memory_storage.dart';
export 'spi_bfm/spi_bfm.dart';
16 changes: 16 additions & 0 deletions lib/src/models/spi_bfm/spi_bfm.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// spi_bfm.dart
// BFM for SPI interface
//
// 2024 September 23
// Author: Roberto Torres <roberto.torres@intel.com>

export 'spi_main_agent.dart';
export 'spi_main_driver.dart';
export 'spi_monitor.dart';
export 'spi_packet.dart';
export 'spi_sub_agent.dart';
export 'spi_sub_driver.dart';
export 'spi_tracker.dart';
55 changes: 55 additions & 0 deletions lib/src/models/spi_bfm/spi_main_agent.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// spi_main_agent.dart
// An agent for the main side of the SPI interface.
//
// 2024 September 23
// Author: Roberto Torres <roberto.torres@intel.com>

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:rohd_vf/rohd_vf.dart';

/// An agent for the main side of the [SpiInterface].
class SpiMainAgent extends Agent {
/// The interface to drive.
final SpiInterface intf;

/// The sequencer
late final Sequencer<SpiPacket> sequencer;

/// The driver that sends packets.
late final SpiMainDriver driver;

/// The monitor that watches the interface.
late final SpiMonitor monitor;

/// The number of cycles before dropping an objection.
final int dropDelayCycles;

/// Creates a new [SpiMainAgent].
SpiMainAgent({
required this.intf,
required Component parent,
required Logic clk,
String name = 'spiMain',
this.dropDelayCycles = 30,
}) : super(name, parent) {
sequencer = Sequencer<SpiPacket>('sequencer', this);

driver = SpiMainDriver(
parent: this,
intf: intf,
clk: clk,
sequencer: sequencer,
dropDelayCycles: dropDelayCycles,
);

monitor = SpiMonitor(
parent: this,
direction: SpiDirection.sub,
intf: intf,
);
}
}
Loading