Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
B-ASIC - Better ASIC Toolbox
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Computer Engineering
B-ASIC - Better ASIC Toolbox
Commits
76a2df00
Commit
76a2df00
authored
2 years ago
by
Oscar Gustafsson
Browse files
Options
Downloads
Patches
Plain Diff
Add tests for architecture
parent
afb4d8cb
Branches
Branches containing commit
No related tags found
1 merge request
!414
Add tests for architecture
Pipeline
#98761
passed
2 years ago
Stage: test
Stage: deploy
Changes
2
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
b_asic/architecture.py
+13
-1
13 additions, 1 deletion
b_asic/architecture.py
test/test_architecture.py
+55
-21
55 additions, 21 deletions
test/test_architecture.py
with
68 additions
and
22 deletions
b_asic/architecture.py
+
13
−
1
View file @
76a2df00
...
@@ -34,7 +34,7 @@ from b_asic.codegen.vhdl.common import is_valid_vhdl_identifier
...
@@ -34,7 +34,7 @@ from b_asic.codegen.vhdl.common import is_valid_vhdl_identifier
from
b_asic.operation
import
Operation
from
b_asic.operation
import
Operation
from
b_asic.port
import
InputPort
,
OutputPort
from
b_asic.port
import
InputPort
,
OutputPort
from
b_asic.process
import
MemoryProcess
,
MemoryVariable
,
OperatorProcess
,
Process
from
b_asic.process
import
MemoryProcess
,
MemoryVariable
,
OperatorProcess
,
Process
from
b_asic.resources
import
ProcessCollection
from
b_asic.resources
import
ProcessCollection
,
_sanitize_port_option
def
_interconnect_dict
()
->
int
:
def
_interconnect_dict
()
->
int
:
...
@@ -435,6 +435,8 @@ class Memory(Resource):
...
@@ -435,6 +435,8 @@ class Memory(Resource):
Number of read ports for memory.
Number of read ports for memory.
write_ports : int, optional
write_ports : int, optional
Number of write ports for memory.
Number of write ports for memory.
total_ports : int, optional
Total number of read and write ports for memory.
assign : bool, default False
assign : bool, default False
Perform assignment when creating the Memory (using the default properties).
Perform assignment when creating the Memory (using the default properties).
"""
"""
...
@@ -448,6 +450,7 @@ class Memory(Resource):
...
@@ -448,6 +450,7 @@ class Memory(Resource):
entity_name
:
Optional
[
str
]
=
None
,
entity_name
:
Optional
[
str
]
=
None
,
read_ports
:
Optional
[
int
]
=
None
,
read_ports
:
Optional
[
int
]
=
None
,
write_ports
:
Optional
[
int
]
=
None
,
write_ports
:
Optional
[
int
]
=
None
,
total_ports
:
Optional
[
int
]
=
None
,
assign
:
bool
=
False
,
assign
:
bool
=
False
,
):
):
super
().
__init__
(
process_collection
=
process_collection
,
entity_name
=
entity_name
)
super
().
__init__
(
process_collection
=
process_collection
,
entity_name
=
entity_name
)
...
@@ -462,6 +465,10 @@ class Memory(Resource):
...
@@ -462,6 +465,10 @@ class Memory(Resource):
raise
ValueError
(
raise
ValueError
(
f
"
memory_type must be
'
RAM
'
or
'
register
'
, not
{
memory_type
!r}
"
f
"
memory_type must be
'
RAM
'
or
'
register
'
, not
{
memory_type
!r}
"
)
)
if
read_ports
is
not
None
or
write_ports
is
not
None
or
total_ports
is
not
None
:
read_ports
,
write_ports
,
total_ports
=
_sanitize_port_option
(
read_ports
,
write_ports
,
total_ports
)
read_ports_bound
=
self
.
_collection
.
read_ports_bound
()
read_ports_bound
=
self
.
_collection
.
read_ports_bound
()
if
read_ports
is
None
:
if
read_ports
is
None
:
self
.
_output_count
=
read_ports_bound
self
.
_output_count
=
read_ports_bound
...
@@ -476,6 +483,11 @@ class Memory(Resource):
...
@@ -476,6 +483,11 @@ class Memory(Resource):
if
write_ports
<
write_ports_bound
:
if
write_ports
<
write_ports_bound
:
raise
ValueError
(
f
"
At least
{
write_ports_bound
}
write ports required
"
)
raise
ValueError
(
f
"
At least
{
write_ports_bound
}
write ports required
"
)
self
.
_input_count
=
write_ports
self
.
_input_count
=
write_ports
total_ports_bound
=
self
.
_collection
.
total_ports_bound
()
if
total_ports
is
not
None
and
total_ports
<
total_ports_bound
:
raise
ValueError
(
f
"
At least
{
total_ports_bound
}
total ports required
"
)
self
.
_memory_type
=
memory_type
self
.
_memory_type
=
memory_type
if
assign
:
if
assign
:
self
.
assign
()
self
.
assign
()
...
...
This diff is collapsed.
Click to expand it.
test/test_architecture.py
+
55
−
21
View file @
76a2df00
import
re
from
itertools
import
chain
from
itertools
import
chain
from
typing
import
List
from
typing
import
List
...
@@ -43,26 +44,6 @@ def test_add_remove_process_from_resource(schedule_direct_form_iir_lp_filter: Sc
...
@@ -43,26 +44,6 @@ def test_add_remove_process_from_resource(schedule_direct_form_iir_lp_filter: Sc
memory
.
add_process
(
PlainMemoryVariable
(
0
,
0
,
{
0
:
2
},
"
PlainMV
"
))
memory
.
add_process
(
PlainMemoryVariable
(
0
,
0
,
{
0
:
2
},
"
PlainMV
"
))
def
test_extract_processing_elements
(
schedule_direct_form_iir_lp_filter
:
Schedule
):
# Extract operations from schedule
operations
=
schedule_direct_form_iir_lp_filter
.
get_operations
()
# Split into new process collections on overlapping execution time
adders
=
operations
.
get_by_type_name
(
Addition
.
type_name
()).
split_on_execution_time
()
const_mults
=
operations
.
get_by_type_name
(
ConstantMultiplication
.
type_name
()
).
split_on_execution_time
()
# List of ProcessingElements
processing_elements
:
List
[
ProcessingElement
]
=
[]
for
adder_collection
in
adders
:
processing_elements
.
append
(
ProcessingElement
(
adder_collection
))
for
const_mult_collection
in
const_mults
:
processing_elements
.
append
(
ProcessingElement
(
const_mult_collection
))
assert
len
(
processing_elements
)
==
len
(
adders
)
+
len
(
const_mults
)
def
test_memory_exceptions
(
schedule_direct_form_iir_lp_filter
:
Schedule
):
def
test_memory_exceptions
(
schedule_direct_form_iir_lp_filter
:
Schedule
):
mvs
=
schedule_direct_form_iir_lp_filter
.
get_memory_variables
()
mvs
=
schedule_direct_form_iir_lp_filter
.
get_memory_variables
()
operations
=
schedule_direct_form_iir_lp_filter
.
get_operations
()
operations
=
schedule_direct_form_iir_lp_filter
.
get_operations
()
...
@@ -82,6 +63,11 @@ def test_architecture(schedule_direct_form_iir_lp_filter: Schedule):
...
@@ -82,6 +63,11 @@ def test_architecture(schedule_direct_form_iir_lp_filter: Schedule):
mvs
=
schedule_direct_form_iir_lp_filter
.
get_memory_variables
()
mvs
=
schedule_direct_form_iir_lp_filter
.
get_memory_variables
()
operations
=
schedule_direct_form_iir_lp_filter
.
get_operations
()
operations
=
schedule_direct_form_iir_lp_filter
.
get_operations
()
with
pytest
.
raises
(
TypeError
,
match
=
"
Different Operation types in ProcessCollection
"
):
ProcessingElement
(
operations
)
# Split operations further into chunks
# Split operations further into chunks
adders
=
operations
.
get_by_type_name
(
Addition
.
type_name
()).
split_on_execution_time
()
adders
=
operations
.
get_by_type_name
(
Addition
.
type_name
()).
split_on_execution_time
()
assert
len
(
adders
)
==
1
assert
len
(
adders
)
==
1
...
@@ -96,7 +82,10 @@ def test_architecture(schedule_direct_form_iir_lp_filter: Schedule):
...
@@ -96,7 +82,10 @@ def test_architecture(schedule_direct_form_iir_lp_filter: Schedule):
# Create necessary processing elements
# Create necessary processing elements
adder
=
ProcessingElement
(
adders
[
0
],
entity_name
=
"
adder
"
)
adder
=
ProcessingElement
(
adders
[
0
],
entity_name
=
"
adder
"
)
multiplier
=
ProcessingElement
(
const_mults
[
0
],
entity_name
=
"
multiplier
"
)
multiplier
=
ProcessingElement
(
const_mults
[
0
])
assert
multiplier
.
entity_name
==
"
Undefined entity name
"
multiplier
.
set_entity_name
(
"
multiplier
"
)
assert
multiplier
.
entity_name
==
"
multiplier
"
input_pe
=
ProcessingElement
(
inputs
[
0
],
entity_name
=
"
input
"
)
input_pe
=
ProcessingElement
(
inputs
[
0
],
entity_name
=
"
input
"
)
output_pe
=
ProcessingElement
(
outputs
[
0
],
entity_name
=
"
output
"
)
output_pe
=
ProcessingElement
(
outputs
[
0
],
entity_name
=
"
output
"
)
processing_elements
:
List
[
ProcessingElement
]
=
[
processing_elements
:
List
[
ProcessingElement
]
=
[
...
@@ -140,6 +129,7 @@ def test_architecture(schedule_direct_form_iir_lp_filter: Schedule):
...
@@ -140,6 +129,7 @@ def test_architecture(schedule_direct_form_iir_lp_filter: Schedule):
with
pytest
.
raises
(
ValueError
,
match
=
'
32 is not a valid VHDL identifier
'
):
with
pytest
.
raises
(
ValueError
,
match
=
'
32 is not a valid VHDL identifier
'
):
adder
.
set_entity_name
(
"
32
"
)
adder
.
set_entity_name
(
"
32
"
)
assert
adder
.
entity_name
==
"
adder
"
assert
adder
.
entity_name
==
"
adder
"
assert
repr
(
adder
)
==
"
adder
"
# Create architecture from
# Create architecture from
architecture
=
Architecture
(
architecture
=
Architecture
(
...
@@ -227,3 +217,47 @@ def test_move_process(schedule_direct_form_iir_lp_filter: Schedule):
...
@@ -227,3 +217,47 @@ def test_move_process(schedule_direct_form_iir_lp_filter: Schedule):
architecture
.
move_process
(
'
cmul4.0
'
,
memories
[
0
],
processing_elements
[
0
])
architecture
.
move_process
(
'
cmul4.0
'
,
memories
[
0
],
processing_elements
[
0
])
with
pytest
.
raises
(
KeyError
,
match
=
"
invalid_name not in
"
):
with
pytest
.
raises
(
KeyError
,
match
=
"
invalid_name not in
"
):
architecture
.
move_process
(
'
invalid_name
'
,
memories
[
0
],
processing_elements
[
1
])
architecture
.
move_process
(
'
invalid_name
'
,
memories
[
0
],
processing_elements
[
1
])
def
test_resource_errors
(
precedence_sfg_delays
):
precedence_sfg_delays
.
set_latency_of_type
(
Addition
.
type_name
(),
1
)
precedence_sfg_delays
.
set_latency_of_type
(
ConstantMultiplication
.
type_name
(),
3
)
precedence_sfg_delays
.
set_execution_time_of_type
(
Addition
.
type_name
(),
1
)
precedence_sfg_delays
.
set_execution_time_of_type
(
ConstantMultiplication
.
type_name
(),
1
)
schedule
=
Schedule
(
precedence_sfg_delays
)
operations
=
schedule
.
get_operations
()
additions
=
operations
.
get_by_type_name
(
Addition
.
type_name
())
with
pytest
.
raises
(
ValueError
,
match
=
'
Cannot map ProcessCollection to single ProcessingElement
'
):
ProcessingElement
(
additions
)
mv
=
schedule
.
get_memory_variables
()
with
pytest
.
raises
(
ValueError
,
match
=
(
"
If total_ports is unset, both read_ports and write_ports must be provided.
"
),
):
Memory
(
mv
,
read_ports
=
1
)
with
pytest
.
raises
(
ValueError
,
match
=
re
.
escape
(
"
Total ports (2) less then read ports (6)
"
)
):
Memory
(
mv
,
read_ports
=
6
,
total_ports
=
2
)
with
pytest
.
raises
(
ValueError
,
match
=
re
.
escape
(
"
Total ports (6) less then write ports (7)
"
)
):
Memory
(
mv
,
read_ports
=
6
,
write_ports
=
7
,
total_ports
=
6
)
with
pytest
.
raises
(
ValueError
,
match
=
"
At least 6 read ports required
"
):
Memory
(
mv
,
read_ports
=
1
,
write_ports
=
1
)
with
pytest
.
raises
(
ValueError
,
match
=
"
At least 5 write ports required
"
):
Memory
(
mv
,
read_ports
=
6
,
write_ports
=
1
)
with
pytest
.
raises
(
ValueError
,
match
=
"
At least 9 total ports required
"
):
Memory
(
mv
,
read_ports
=
6
,
write_ports
=
5
,
total_ports
=
6
)
with
pytest
.
raises
(
ValueError
,
match
=
"
memory_type must be
'
RAM
'
or
'
register
'
, not
'
foo
'"
):
Memory
(
mv
,
read_ports
=
6
,
write_ports
=
5
,
total_ports
=
6
,
memory_type
=
"
foo
"
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment