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
Merge requests
!244
WIP: VHDL code generation for register and memory based storages
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
WIP: VHDL code generation for register and memory based storages
resource-hdl
into
master
Overview
0
Commits
4
Pipelines
4
Changes
14
Merged
Mikael Henriksson
requested to merge
resource-hdl
into
master
2 years ago
Overview
0
Commits
4
Pipelines
4
Changes
3
Expand
0
0
Merge request reports
Compare
version 2
version 3
c1cf0960
2 years ago
version 2
044b26e2
2 years ago
version 1
9e368dcb
2 years ago
master (base)
and
latest version
latest version
fa554922
4 commits,
2 years ago
version 3
c1cf0960
4 commits,
2 years ago
version 2
044b26e2
4 commits,
2 years ago
version 1
9e368dcb
4 commits,
2 years ago
Show latest version
3 files
+
12
−
34
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
Files
3
Search (e.g. *.vue) (Ctrl+P)
b_asic/codegen/vhdl/architecture.py
0 → 100644
+
333
−
0
Options
"""
Module for code generation of VHDL architectures.
"""
from
io
import
TextIOWrapper
from
typing
import
Dict
,
Optional
,
Set
,
cast
from
b_asic.codegen
import
vhdl
from
b_asic.codegen.vhdl
import
VHDL_TAB
from
b_asic.process
import
MemoryVariable
,
PlainMemoryVariable
from
b_asic.resources
import
(
ProcessCollection
,
_ForwardBackwardEntry
,
_ForwardBackwardTable
,
)
def
write_memory_based_storage
(
f
:
TextIOWrapper
,
assignment
:
Set
[
ProcessCollection
],
entity_name
:
str
,
word_length
:
int
,
read_ports
:
int
,
write_ports
:
int
,
total_ports
:
int
,
):
"""
Generate the VHDL architecture for a memory based architecture from a process collection of memory variables.
Parameters
----------
assignment : dict
A possible cell assignment to use when generating the memory based storage.
The cell assignment is a dictionary int to ProcessCollection where the integer
corresponds to the cell to assign all MemoryVariables in corresponding process
collection.
If unset, each MemoryVariable will be assigned to a unique cell.
f : TextIOWrapper
File object (or other TextIOWrapper object) to write the architecture onto.
word_length : int
Word length of the memory variable objects.
read_ports : int
Number of read ports.
write_ports : int
Number of write ports.
total_ports : int
Total concurrent memory accesses possible.
"""
# Code settings
mem_depth
=
len
(
assignment
)
architecture_name
=
"
rtl
"
schedule_time
=
next
(
iter
(
assignment
)).
_schedule_time
# Write architecture header
f
.
write
(
f
'
architecture
{
architecture_name
}
of
{
entity_name
}
is
\n\n
'
)
#
# Architecture declerative region begin
#
f
.
write
(
f
'
{
VHDL_TAB
}
-- HDL memory description
\n
'
)
vhdl
.
common
.
write_constant_decl
(
f
,
name
=
'
MEM_WL
'
,
type
=
'
integer
'
,
value
=
word_length
,
name_pad
=
12
)
vhdl
.
common
.
write_constant_decl
(
f
,
name
=
'
MEM_DEPTH
'
,
type
=
'
integer
'
,
value
=
mem_depth
,
name_pad
=
12
)
vhdl
.
common
.
write_type_decl
(
f
,
'
mem_type
'
,
'
array(0 to MEM_DEPTH-1) of std_logic_vector(MEM_WL-1 downto 0)
'
)
vhdl
.
common
.
write_signal_decl
(
f
,
'
memory
'
,
'
mem_type
'
,
name_pad
=
14
)
for
i
in
range
(
read_ports
):
vhdl
.
common
.
write_signal_decl
(
f
,
f
'
read_port_
{
i
}
'
,
'
std_logic_vector(MEM_WL-1 downto 0)
'
,
name_pad
=
14
)
vhdl
.
common
.
write_signal_decl
(
f
,
f
'
read_adr_
{
i
}
'
,
f
'
integer range 0 to
{
schedule_time
}
-1
'
,
name_pad
=
14
)
vhdl
.
common
.
write_signal_decl
(
f
,
f
'
read_en_
{
i
}
'
,
'
std_logic
'
,
name_pad
=
14
)
for
i
in
range
(
write_ports
):
vhdl
.
common
.
write_signal_decl
(
f
,
f
'
write_port_
{
i
}
'
,
'
std_logic_vector(MEM_WL-1 downto 0)
'
,
name_pad
=
14
)
vhdl
.
common
.
write_signal_decl
(
f
,
f
'
write_adr_
{
i
}
'
,
f
'
integer range 0 to
{
schedule_time
}
-1
'
,
name_pad
=
14
)
vhdl
.
common
.
write_signal_decl
(
f
,
f
'
write_en_
{
i
}
'
,
'
std_logic
'
,
name_pad
=
14
)
# Schedule time counter
f
.
write
(
'
\n
'
)
f
.
write
(
f
'
{
VHDL_TAB
}
-- Schedule counter
\n
'
)
vhdl
.
common
.
write_signal_decl
(
f
,
name
=
'
schedule_cnt
'
,
type
=
f
'
integer range 0 to
{
schedule_time
}
-1
'
,
name_pad
=
14
,
)
f
.
write
(
'
\n
'
)
#
# Architecture body begin
#
f
.
write
(
f
'
begin
\n\n
'
)
f
.
write
(
f
'
{
VHDL_TAB
}
-- Schedule counter
\n
'
)
vhdl
.
common
.
write_synchronous_process
(
f
=
f
,
name
=
'
schedule_cnt_proc
'
,
clk
=
'
clk
'
,
indent
=
len
(
1
*
VHDL_TAB
),
body
=
(
f
'
{
0
*
VHDL_TAB
}
if en =
\'
1
\'
then
\n
'
f
'
{
1
*
VHDL_TAB
}
if schedule_cnt =
{
schedule_time
}
-1 then
\n
'
f
'
{
2
*
VHDL_TAB
}
schedule_cnt <= 0;
\n
'
f
'
{
1
*
VHDL_TAB
}
else
\n
'
f
'
{
2
*
VHDL_TAB
}
schedule_cnt <= schedule_cnt + 1;
\n
'
f
'
{
1
*
VHDL_TAB
}
end if;
\n
'
f
'
{
0
*
VHDL_TAB
}
end if;
\n
'
),
)
# Infer memory
f
.
write
(
'
\n
'
)
f
.
write
(
f
'
{
VHDL_TAB
}
-- Memory
\n
'
)
vhdl
.
common
.
write_asynchronous_read_memory
(
f
=
f
,
clk
=
'
clk
'
,
name
=
f
'
mem_
{
0
}
_proc
'
,
read_ports
=
{
(
f
'
read_port_
{
i
}
'
,
f
'
read_adr_
{
i
}
'
,
f
'
read_en_
{
i
}
'
)
for
i
in
range
(
read_ports
)
},
write_ports
=
{
(
f
'
write_port_
{
i
}
'
,
f
'
write_adr_
{
i
}
'
,
f
'
write_en_
{
i
}
'
)
for
i
in
range
(
write_ports
)
},
)
f
.
write
(
f
'
\n
{
VHDL_TAB
}
-- Memory writes
\n
'
)
f
.
write
(
f
'
{
VHDL_TAB
}
process(schedule_cnt)
\n
'
)
f
.
write
(
f
'
{
VHDL_TAB
}
begin
\n
'
)
f
.
write
(
f
'
{
2
*
VHDL_TAB
}
case schedule_cnt is
\n
'
)
for
i
,
collection
in
enumerate
(
assignment
):
for
mv
in
collection
:
mv
=
cast
(
MemoryVariable
,
mv
)
if
mv
.
execution_time
:
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
--
{
mv
!r}
\n
'
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
when
{
mv
.
start_time
}
=>
\n
'
)
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
write_adr_0 <=
{
i
}
;
\n
'
)
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
write_en_0 <=
\'
1
\'
;
\n
'
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
when others =>
\n
'
)
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
write_adr_0 <= 0;
\n
'
)
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
write_en_0 <=
\'
0
\'
;
\n
'
)
f
.
write
(
f
'
{
2
*
VHDL_TAB
}
end case;
\n
'
)
f
.
write
(
f
'
{
1
*
VHDL_TAB
}
end process;
\n
'
)
f
.
write
(
f
'
\n
{
VHDL_TAB
}
-- Memory reads
\n
'
)
f
.
write
(
f
'
{
VHDL_TAB
}
process(schedule_cnt)
\n
'
)
f
.
write
(
f
'
{
VHDL_TAB
}
begin
\n
'
)
f
.
write
(
f
'
{
2
*
VHDL_TAB
}
case schedule_cnt is
\n
'
)
for
i
,
collection
in
enumerate
(
assignment
):
for
mv
in
collection
:
mv
=
cast
(
PlainMemoryVariable
,
mv
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
--
{
mv
!r}
\n
'
)
for
read_time
in
mv
.
reads
.
values
():
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
when
'
f
'
{
(
mv
.
start_time
+
read_time
)
%
schedule_time
}
=>
\n
'
)
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
read_adr_0 <=
{
i
}
;
\n
'
)
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
read_en_0 <=
\'
1
\'
;
\n
'
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
when others =>
\n
'
)
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
read_adr_0 <= 0;
\n
'
)
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
read_en_0 <=
\'
0
\'
;
\n
'
)
f
.
write
(
f
'
{
2
*
VHDL_TAB
}
end case;
\n
'
)
f
.
write
(
f
'
{
1
*
VHDL_TAB
}
end process;
\n\n
'
)
f
.
write
(
f
'
{
1
*
VHDL_TAB
}
-- Input and output assignment
\n
'
)
f
.
write
(
f
'
{
1
*
VHDL_TAB
}
write_port_0 <= p_0_in;
\n
'
)
p_zero_exec
=
filter
(
lambda
p
:
p
.
execution_time
==
0
,
(
p
for
pc
in
assignment
for
p
in
pc
)
)
vhdl
.
common
.
write_synchronous_process_prologue
(
f
,
clk
=
'
clk
'
,
indent
=
len
(
VHDL_TAB
),
name
=
'
output_reg_proc
'
,
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
case schedule_cnt is
\n
'
)
for
p
in
p_zero_exec
:
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
when
{
p
.
start_time
}
=> p_0_out <= p_0_in;
\n
'
)
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
when others => p_0_out <= read_port_0;
\n
'
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
end case;
\n
'
)
vhdl
.
common
.
write_synchronous_process_epilogue
(
f
,
clk
=
'
clk
'
,
indent
=
len
(
VHDL_TAB
),
name
=
'
output_reg_proc
'
,
)
f
.
write
(
'
\n
'
)
f
.
write
(
f
'
end architecture
{
architecture_name
}
;
'
)
def
write_register_based_storage
(
f
:
TextIOWrapper
,
forward_backward_table
:
_ForwardBackwardTable
,
entity_name
:
str
,
word_length
:
int
,
read_ports
:
int
,
write_ports
:
int
,
total_ports
:
int
,
):
architecture_name
=
"
rtl
"
schedule_time
=
len
(
forward_backward_table
)
reg_cnt
=
len
(
forward_backward_table
[
0
].
regs
)
#
# Architecture declerative region begin
#
# Write architecture header
f
.
write
(
f
'
architecture
{
architecture_name
}
of
{
entity_name
}
is
\n\n
'
)
# Schedule time counter
f
.
write
(
f
'
{
VHDL_TAB
}
-- Schedule counter
\n
'
)
vhdl
.
common
.
write_signal_decl
(
f
,
name
=
'
schedule_cnt
'
,
type
=
f
'
integer range 0 to
{
schedule_time
}
-1
'
,
name_pad
=
14
,
default_value
=
'
0
'
,
)
f
.
write
(
'
\n
'
)
# Shift register
f
.
write
(
f
'
{
VHDL_TAB
}
-- Shift register
\n
'
)
vhdl
.
common
.
write_type_decl
(
f
,
name
=
'
shift_reg_type
'
,
alias
=
f
'
array(0 to
{
reg_cnt
}
-1) of std_logic_vector(WL-1 downto 0)
'
,
)
vhdl
.
common
.
write_signal_decl
(
f
,
name
=
'
shift_reg
'
,
type
=
'
shift_reg_type
'
,
name_pad
=
14
,
)
#
# Architecture body begin
#
f
.
write
(
f
'
begin
\n\n
'
)
f
.
write
(
f
'
{
VHDL_TAB
}
-- Schedule counter
\n
'
)
vhdl
.
common
.
write_synchronous_process
(
f
=
f
,
name
=
'
schedule_cnt_proc
'
,
clk
=
'
clk
'
,
indent
=
len
(
1
*
VHDL_TAB
),
body
=
(
f
'
{
0
*
VHDL_TAB
}
if en =
\'
1
\'
then
\n
'
f
'
{
1
*
VHDL_TAB
}
if schedule_cnt =
{
schedule_time
}
-1 then
\n
'
f
'
{
2
*
VHDL_TAB
}
schedule_cnt <= 0;
\n
'
f
'
{
1
*
VHDL_TAB
}
else
\n
'
f
'
{
2
*
VHDL_TAB
}
schedule_cnt <= schedule_cnt + 1;
\n
'
f
'
{
1
*
VHDL_TAB
}
end if;
\n
'
f
'
{
0
*
VHDL_TAB
}
end if;
\n
'
),
)
f
.
write
(
f
'
\n
{
VHDL_TAB
}
-- Multiplexers for shift register
\n
'
)
vhdl
.
common
.
write_synchronous_process_prologue
(
f
,
clk
=
'
clk
'
,
name
=
'
shift_reg_proc
'
,
indent
=
len
(
VHDL_TAB
),
)
# Default for all register
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
-- Default case
\n
'
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
shift_reg(0) <= p_0_in;
\n
'
)
for
reg_idx
in
range
(
1
,
reg_cnt
):
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
shift_reg(
{
reg_idx
}
) <= shift_reg(
{
reg_idx
-
1
}
);
\n
'
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
case schedule_cnt is
\n
'
)
for
i
,
entry
in
enumerate
(
forward_backward_table
):
if
entry
.
back_edge_from
:
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
when
{
schedule_time
-
1
if
(
i
-
1
)
<
0
else
(
i
-
1
)
}
=>
\n
'
)
for
dst
,
src
in
entry
.
back_edge_from
.
items
():
f
.
write
(
f
'
{
5
*
VHDL_TAB
}
shift_reg(
{
dst
}
) <= shift_reg(
{
src
}
);
\n
'
)
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
when others => null;
\n
'
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
end case;
\n
'
)
vhdl
.
common
.
write_synchronous_process_epilogue
(
f
,
clk
=
'
clk
'
,
name
=
'
shift_reg_proc
'
,
indent
=
len
(
VHDL_TAB
),
)
f
.
write
(
f
'
\n
{
VHDL_TAB
}
-- Output muliplexer
\n
'
)
vhdl
.
common
.
write_synchronous_process_prologue
(
f
,
clk
=
'
clk
'
,
name
=
'
out_mux_proc
'
,
indent
=
len
(
VHDL_TAB
),
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
-- Default case
\n
'
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
p_0_out <= shift_reg(
{
reg_cnt
-
1
}
);
\n
'
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
case schedule_cnt is
\n
'
)
for
i
,
entry
in
enumerate
(
forward_backward_table
):
if
entry
.
outputs_from
is
not
None
:
if
entry
.
outputs_from
!=
reg_cnt
-
1
:
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
when
{
i
}
=>
\n
'
)
if
entry
.
outputs_from
<
0
:
f
.
write
(
f
'
{
5
*
VHDL_TAB
}
p_0_out <= p_
{
-
1
-
entry
.
outputs_from
}
_in;
\n
'
)
else
:
f
.
write
(
f
'
{
5
*
VHDL_TAB
}
p_0_out <= shift_reg(
{
entry
.
outputs_from
}
);
\n
'
)
f
.
write
(
f
'
{
4
*
VHDL_TAB
}
when others => null;
\n
'
)
f
.
write
(
f
'
{
3
*
VHDL_TAB
}
end case;
\n
'
)
vhdl
.
common
.
write_synchronous_process_epilogue
(
f
,
clk
=
'
clk
'
,
name
=
'
out_mux_proc
'
,
indent
=
len
(
VHDL_TAB
),
)
f
.
write
(
f
'
end architecture
{
architecture_name
}
;
'
)
Loading