-
Notifications
You must be signed in to change notification settings - Fork 32
Add Count Pattern Occurrence #247
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
c73c2cc
321f4b1
8c23d5d
b62cc28
0b53b61
c0e2421
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 |
|---|---|---|
| @@ -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
|
||
|
|
||
| ## 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
|
||
|
|
||
| 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
|
||
| 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. | ||
| /// If [fromStart] is `true`, the count starts from the beginning of the bus. | ||
|
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. 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); | ||
|
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. what's the purpose of the internal |
||
| _output <= count; | ||
|
|
||
| if (generateError) { | ||
| // If pattern is not found (count equals to 0), return error | ||
| addOutput('error'); | ||
|
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 is it an error if count is 0? |
||
| error! <= count.eq(0); | ||
| } | ||
| } | ||
| } | ||
| 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)); | ||
| }); | ||
| }); | ||
| } |
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.
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