Skip to content
Open
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
3 changes: 2 additions & 1 deletion doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ Some in-development items will have opened issues, as well. Feel free to create
- [Leading Digit Anticipate](./components/leading_digit_anticipate.md)
- Count
- [Count bit occurrence](./components/count.md)
- Count pattern occurrence
- [Count pattern occurrence](./components/count_pattern.md)

- Detection
- [Edge detection](./components/edge_detector.md)
- Sort
Expand Down
49 changes: 49 additions & 0 deletions doc/components/count_pattern.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Count

A CountPattern will count the number of occurrence of a fixed-width `pattern` within a given Logic `bus`.

It takes a Binary Logic `bus` and counts the occurrences of a fixed-width `pattern` and outputs it as `count`. `pattern` refers to the pattern to be counted in the bus. Ensure that the `pattern` width is smaller than the `bus` width. In addition, with `fromStart` which is set as `true` by default to count the pattern from the start of the `bus`. An `error` flag is added to indicate when `pattern` is not found in the `bus`.

## Implementation

To find the number of occurence `count` of a fixed-width `pattern` in a `bus`. The search direction is defined by `fromStart` argument. If `pattern` is not found in the `bus`, the `count` will be set to 0 and `error` will be set to 1. If `pattern` matches, it will be added to `count`.

Check failure on line 9 in doc/components/count_pattern.md

View workflow job for this annotation

GitHub Actions / Run Checks

Trailing spaces

doc/components/count_pattern.md:9:286 MD009/no-trailing-spaces Trailing spaces [Expected: 0 or 2; Actual: 1] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md009.md

## Count Pattern from Start (Scenario 1: Present Once)

For example, if `bus` is `00111110` and `pattern` is `110`, the output `count` will return `1` as the pattern occurred once in the bus from LSB.

```dart
final bus = Const(bin('00111110'), width: 8);
final pattern = Const(bin('110'), width: 3);
final countPattern = CountPattern(bus, pattern);
```

## Count Pattern from Start (Scenario 2: Present More Than Once)

For example, if `bus` is `00110110` and `pattern` is `01`, the output `count` will return `2` as the pattern occurred twice in the bus from LSB.

```dart
final bus = Const(bin('00110110'), width: 8);
final pattern = Const(bin('01'), width: 2);
final countPattern = CountPattern(bus, pattern);
```

## Count Pattern from Start (Scenario 3: Not Present)

For example, if `bus` is `00010000` and `pattern` is `110`, the output `count` will return `0` and an error will be generated as the pattern does not exist in the bus.

```dart
final bus = Const(bin('00010000'), width: 8);
final pattern = Const(bin('110'), width: 3);
final countPattern = CountPattern(bus, pattern);
```

## Count Pattern from End

Check failure on line 41 in doc/components/count_pattern.md

View workflow job for this annotation

GitHub Actions / Run Checks

Trailing spaces

doc/components/count_pattern.md:41:26 MD009/no-trailing-spaces Trailing spaces [Expected: 0 or 2; Actual: 1] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md009.md

For example, if `bus` is `00110111` and `pattern` is `110`, the output `count` will return `1` as the pattern occurred once from the end of the bus.

```dart
final bus = Const(bin('00110111'), width: 8);
final pattern = Const(bin('110'), width: 3);
final countPattern = CountPattern(bus, pattern, fromStart: false);
```

Check failure on line 49 in doc/components/count_pattern.md

View workflow job for this annotation

GitHub Actions / Run Checks

Files should end with a single newline character

doc/components/count_pattern.md:49:4 MD047/single-trailing-newline Files should end with a single newline character https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md047.md
1 change: 1 addition & 0 deletions lib/rohd_hcl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export 'src/binary_gray.dart';
export 'src/clock_gating.dart';
export 'src/component_config/component_config.dart';
export 'src/count.dart';
export 'src/count_pattern.dart';
export 'src/edge_detector.dart';
export 'src/encodings/encodings.dart';
export 'src/error_checking/error_checking.dart';
Expand Down
81 changes: 81 additions & 0 deletions lib/src/count_pattern.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (C) 2025 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// count_pattern.dart
// Implementation of Count Pattern Functionality.
//
// 2025 June 24
// Author: Ramli, Nurul Izziany <[email protected]>
//

import 'dart:math';

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

/// [CountPattern] functionality.
///
/// Takes in a [Logic] `bus` to count occurrences of a fixed-width pattern.
/// Outputs pin `count` contains the number of occurrences of the
/// pattern in the bus.

class CountPattern extends Module {
/// [_output] is output of CountPattern.
/// Use count for accessing from outside Module.
late Logic _output;

/// [count] is a getter for output of CountPattern.
Logic get count => _output;

/// If [generateError] is `true`, an error output will be generated
/// when the pattern is not found in the bus.
final bool generateError;

/// [error] is a getter for error in CountPattern and is generated when
/// [generateError] is `true`.
/// When pattern is not found, it will result in error `1`.
Logic? get error => tryOutput('error');

/// Count the number of occurence of a fixed-width pattern in a bus.
///
/// Takes in [bus] of type [Logic].
/// [pattern] is the pattern to be counted in the bus.
Copy link
Contributor

Choose a reason for hiding this comment

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

it may be worth explicitly stating that if the pattern width is greater than the width of the bus, the count will always be 0

/// If [fromStart] is `true`, the count starts from the beginning of the bus.
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the meaning of counting from the start or the end? Shouldn't the resulting count be the same?

/// If [fromStart] is `false`, the count starts from the end of the bus.
CountPattern(Logic bus, Logic pattern,
{bool fromStart = true, this.generateError = false})
: super(definitionName: 'CountPattern_W${bus.width}_P${pattern.width}') {
bus = addInput('bus', bus, width: bus.width);
pattern = addInput('pattern', pattern, width: pattern.width);

// Initialize count to zero
Logic count = Const(0, width: max(1, log2Ceil(bus.width + 1)));

for (var i = 0; i <= bus.width - pattern.width; i = i + 1) {
int minBit;
int maxBit;
if (fromStart) {
// Read from start of the bus
minBit = i;
maxBit = i + pattern.width;
} else {
// Read from end of the bus
minBit = bus.width - i - pattern.width;
maxBit = bus.width - i;
}

// Check if pattern matches, add to count
final valCheck = bus.getRange(minBit, maxBit).eq(pattern);
count += valCheck.zeroExtend(count.width);
}

_output = addOutput('count', width: count.width);
Copy link
Contributor

Choose a reason for hiding this comment

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

what's the purpose of the internal _output vairable? Why not just assign this.count <= count or something?

_output <= count;

if (generateError) {
// If pattern is not found (count equals to 0), return error
addOutput('error');
Copy link
Contributor

Choose a reason for hiding this comment

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

why is it an error if count is 0?

error! <= count.eq(0);
}
}
}
126 changes: 126 additions & 0 deletions test/count_pattern_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright (C) 2025 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// count_pattern_test.dart
// Tests for Count Pattern
//
// 2025 July 6
// Author: Louiz Ang Zhi Lin <[email protected]>
// Co-author: Ramli, Nurul Izziany <[email protected]>
//
import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:test/test.dart';

void main() {
group('From start, count pattern when pattern is', () {
test('present once', () {
final bus = Const(bin('00111110'), width: 8);
final pattern = Const(bin('110'), width: 3);
final countPattern = CountPattern(bus, pattern, generateError: true);
expect(countPattern.error!.value.toInt(), equals(0));
expect(countPattern.count.value.toInt(), equals(1));
});
test('present more than once', () {
final bus = Const(bin('00110110'), width: 8);
final pattern = Const(bin('01'), width: 2);
final countPattern = CountPattern(bus, pattern, generateError: true);
expect(countPattern.error!.value.toInt(), equals(0));
expect(countPattern.count.value.toInt(), equals(2));
});
test('not present', () {
final bus = Const(bin('00010000'), width: 8);
final pattern = Const(bin('110'), width: 3);
final countPattern = CountPattern(bus, pattern, generateError: true);
expect(countPattern.error!.value.toInt(), equals(1));
expect(countPattern.count.value.toInt(), equals(0));
});
});
group('From end, count pattern when pattern is', () {
test('present', () {
final bus = Const(bin('00110111'), width: 8);
final pattern = Const(bin('110'), width: 3);
final countPattern =
CountPattern(bus, pattern, fromStart: false, generateError: true);
expect(countPattern.error!.value.toInt(), equals(0));
expect(countPattern.count.value.toInt(), equals(1));
});
test('present more than once', () {
final bus = Const(bin('11011011'), width: 8);
final pattern = Const(bin('10'), width: 2);
final countPattern =
CountPattern(bus, pattern, fromStart: false, generateError: true);
expect(countPattern.error!.value.toInt(), equals(0));
expect(countPattern.count.value.toInt(), equals(2));
});
test('not present', () {
final bus = Const(bin('101010101'), width: 8);
final pattern = Const(bin('111'), width: 3);
final countPattern =
CountPattern(bus, pattern, fromStart: false, generateError: true);
expect(countPattern.error!.value.toInt(), equals(1));
expect(countPattern.count.value.toInt(), equals(0));
});
});
group('Dynamic input, from start, count pattern when pattern is', () {
test('present once', () {
final bus = Logic(width: 8);
final pattern = Logic(width: 2);
final countPattern = CountPattern(bus, pattern, generateError: true);
bus.put(bin('00111110'));
pattern.put(bin('01'));
expect(countPattern.error!.value.toInt(), equals(0));
expect(countPattern.count.value.toInt(), equals(1));
});
test('present more than once', () {
final bus = Logic(width: 8);
final pattern = Logic(width: 2);
final countPattern = CountPattern(bus, pattern, generateError: true);
bus.put(bin('11011111'));
pattern.put(bin('11'));
expect(countPattern.error!.value.toInt(), equals(0));
expect(countPattern.count.value.toInt(), equals(5));
});
test('not present', () {
final bus = Logic(width: 8);
final pattern = Logic(width: 2);
final countPattern = CountPattern(bus, pattern, generateError: true);
bus.put(bin('11110111'));
pattern.put(bin('00'));
expect(countPattern.error!.value.toInt(), equals(1));
expect(countPattern.count.value.toInt(), equals(0));
});
});
group('Dynamic input, from end, count pattern when pattern is', () {
test('present once', () {
final bus = Logic(width: 8);
final pattern = Logic(width: 2);
final countPattern =
CountPattern(bus, pattern, fromStart: false, generateError: true);
bus.put(bin('10000001'));
pattern.put(bin('01'));
expect(countPattern.error!.value.toInt(), equals(0));
expect(countPattern.count.value.toInt(), equals(1));
});
test('present more than once', () {
final bus = Logic(width: 8);
final pattern = Logic(width: 2);
final countPattern =
CountPattern(bus, pattern, fromStart: false, generateError: true);
bus.put(bin('11011101'));
pattern.put(bin('10'));
expect(countPattern.error!.value.toInt(), equals(0));
expect(countPattern.count.value.toInt(), equals(2));
});
test('not present', () {
final bus = Logic(width: 8);
final pattern = Logic(width: 2);
final countPattern =
CountPattern(bus, pattern, fromStart: false, generateError: true);
bus.put(bin('11110111'));
pattern.put(bin('00'));
expect(countPattern.error!.value.toInt(), equals(1));
expect(countPattern.count.value.toInt(), equals(0));
});
});
}
Loading