Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions ip/bin/aegis_genip.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ ArgParser buildParser() {
abbr: 'c',
help: 'Adds a clock domain for tile configuration',
)
..addFlag(
'jtag',
abbr: 'j',
help: 'Adds a JTAG TAP controller for configuration and debug',
)
..addOption(
'output',
abbr: 'o',
Expand Down Expand Up @@ -115,6 +120,7 @@ Future<void> main(List<String> arguments) async {
padIn: Logic(width: 2 * width + 2 * height),
serialIn: Logic(width: serdesCount),
configClk: results.flag('config-clk') ? Logic() : null,
enableJtag: results.flag('jtag'),
configReadPort: DataPortInterface(
int.parse(results.option('config-data-width') ?? '8'),
int.parse(results.option('config-address-width') ?? '8'),
Expand Down Expand Up @@ -227,6 +233,7 @@ Future<void> main(List<String> arguments) async {
bramDataWidth: 8,
bramAddrWidth: 7,
bramColumnInterval: bramInterval,
hasJtag: results.flag('jtag'),
);
File(
'$outputDir/${fpga.name}_cells.v',
Expand All @@ -252,6 +259,7 @@ Future<void> main(List<String> arguments) async {
bramColumnInterval: bramInterval,
dspColumnInterval: dspInterval,
hasConfigClk: results.flag('config-clk'),
hasJtag: results.flag('jtag'),
);
File(
'$outputDir/${fpga.name}-openroad.tcl',
Expand Down
1 change: 1 addition & 0 deletions ip/lib/src/components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export 'components/digital/fabric_config_loader.dart';
export 'components/digital/fpga.dart';
export 'components/digital/io_fabric.dart';
export 'components/digital/io_tile.dart';
export 'components/digital/jtag_tap.dart';
export 'components/digital/lut4.dart';
export 'components/digital/serdes_tile.dart';
export 'components/digital/tile.dart';
67 changes: 54 additions & 13 deletions ip/lib/src/components/digital/fpga.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'dsp_basic_tile.dart';
import 'fabric.dart';
import 'fabric_config_loader.dart';
import 'io_fabric.dart';
import 'jtag_tap.dart';
import 'io_tile.dart';
import 'serdes_tile.dart';
import 'tile.dart';
Expand All @@ -24,6 +25,7 @@ class AegisFPGA extends Module {
final int bramAddrWidth;
final int dspColumnInterval;
final int clockTileCount;
final bool enableJtag;

/// Total I/O pads (2*width + 2*height).
int get totalPads => 2 * width + 2 * height;
Expand All @@ -41,6 +43,7 @@ class AegisFPGA extends Module {
this.bramAddrWidth = 7,
this.dspColumnInterval = 0,
this.clockTileCount = 1,
this.enableJtag = false,
required Logic padIn,
required Logic serialIn,
Logic? configClk,
Expand Down Expand Up @@ -68,6 +71,32 @@ class AegisFPGA extends Module {
configClk = addInput('configClk', configClk);
}

// JTAG ports (optional)
JtagTap? jtag;
if (enableJtag) {
final tck = addInput('tck', Logic());
final tms = addInput('tms', Logic());
final tdi = addInput('tdi', Logic());
final trst = addInput('trst', Logic());
final userTdo = addInput('userTdo', Logic());
addOutput('tdo');

// User data register interface - exposed to fabric for debug
addOutput('userTdi');
addOutput('userShift');
addOutput('userUpdate');
addOutput('userCapture');
addOutput('userReset');

jtag = JtagTap(tck, tms, tdi, trst, userTdo: userTdo);
output('tdo') <= jtag.tdo;
output('userTdi') <= jtag.userTdi;
output('userShift') <= jtag.userShift;
output('userUpdate') <= jtag.userUpdate;
output('userCapture') <= jtag.userCapture;
output('userReset') <= jtag.userReset;
}

configReadPort = configReadPort.clone()
..connectIO(
this,
Expand Down Expand Up @@ -97,24 +126,35 @@ class AegisFPGA extends Module {
configReadPort,
);

configDone <= loader.done;
// When JTAG is enabled, a mux selects which source drives the config
// chain. The TAP's enableConfig output controls the switch.
final cfgIn = Logic(name: 'cfgIn');
final cfgLoad = Logic(name: 'cfgLoad');
final cfgReset = Logic(name: 'cfgReset');

if (jtag != null) {
cfgIn <= mux(jtag.enableConfig, jtag.cfgIn, loader.cfgIn);
cfgLoad <= mux(jtag.enableConfig, jtag.cfgLoad, loader.cfgLoad);
cfgReset <= reset | (jtag.enableConfig & jtag.cfgReset);
configDone <= loader.done;
} else {
cfgIn <= loader.cfgIn;
cfgLoad <= loader.cfgLoad;
cfgReset <= reset;
configDone <= loader.done;
}

// Clock tiles - config chain: clock tiles -> IO fabric -> LUT fabric
final clockTiles = <ClockTile>[];
var cfgChain = loader.cfgIn;
var cfgChainSig = cfgIn;

for (int i = 0; i < clockTileCount; i++) {
final tileCfgIn = Logic(name: 'clkCfgIn_$i');
tileCfgIn <= cfgChain;
tileCfgIn <= cfgChainSig;

final ct = ClockTile(
clk,
~loader.done | reset,
tileCfgIn,
loader.cfgLoad,
);
final ct = ClockTile(clk, cfgReset, tileCfgIn, cfgLoad);
clockTiles.add(ct);
cfgChain = ct.cfgOut;
cfgChainSig = ct.cfgOut;
}

// Collect clock outputs
Expand All @@ -134,7 +174,7 @@ class AegisFPGA extends Module {
// IO fabric receives config chain after clock tiles
final ioFabric = IOFabric(
clk,
~loader.done | reset,
cfgReset,
width: width,
height: height,
tracks: tracks,
Expand All @@ -143,8 +183,8 @@ class AegisFPGA extends Module {
bramDataWidth: bramDataWidth,
bramAddrWidth: bramAddrWidth,
dspColumnInterval: dspColumnInterval,
cfgIn: cfgChain,
cfgLoad: loader.cfgLoad,
cfgIn: cfgChainSig,
cfgLoad: cfgLoad,
padIn: padIn,
serialIn: serialIn,
);
Expand Down Expand Up @@ -218,6 +258,7 @@ class AegisFPGA extends Module {
),
'serdes': SerDesTile.descriptor(count: serdesCount),
'clock': ClockTile.descriptor(count: clockTileCount),
if (enableJtag) 'jtag': JtagTap.descriptor(idcode: 0x00000001),
'config': {
'total_bits': totalBits,
'chain_order': [
Expand Down
Loading
Loading