Add _very incomplete_ AMBA 3 AHB Lite widget

This is just a start on the first widget. It is still very limited and
not yet functional in any way.
This commit is contained in:
Dennis Potter 2021-08-22 20:38:56 -07:00
parent 145ac70123
commit 5e4a954a0c
Signed by: Dennis
GPG Key ID: 186A8AD440942BAF
8 changed files with 252 additions and 78 deletions

View File

@ -130,7 +130,14 @@ class AddrMap(Component):
# Remove comma from last port entry # Remove comma from last port entry
output_ports_rtl[-1] = output_ports_rtl[-1].rstrip(',') output_ports_rtl[-1] = output_ports_rtl[-1].rstrip(',')
import_package_list = [] # Define packages to be included. Always include the
# b2w and w2b defines.
import_package_list = [
AddrMap.templ_dict['import_package']['rtl'].format(
name = 'srdl2sv_widget'),
'\n'
]
try: try:
for x in self.get_package_names(): for x in self.get_package_names():
import_package_list.append( import_package_list.append(
@ -139,9 +146,10 @@ class AddrMap(Component):
import_package_list.append('\n') import_package_list.append('\n')
import_package_list.pop()
except IndexError: except IndexError:
pass pass
import_package_list.pop()
import getpass import getpass
import socket import socket

View File

@ -69,8 +69,6 @@ module_declaration:
<<INDENT>> <<INDENT>>
// Clock & Resets // Clock & Resets
input reg_clk, input reg_clk,
input bus_clk,
input bus_rst_n,
{resets} {resets}
// Inputs // Inputs
@ -115,13 +113,13 @@ read_mux:
// Read multiplexer // Read multiplexer
always_comb always_comb
begin begin
case(addr) case(b2r.addr)
{list_of_cases} {list_of_cases}
endcase endcase
end end
default_mux_case: default_mux_case:
rtl: |- rtl: |-
default: sw_rd_bus = 0; default: r2b.data = 0;
list_of_mux_cases: list_of_mux_cases:
rtl: |- rtl: |-
32'd{}: sw_rd_bus = {}; 32'd{}: r2b.data = {};

View File

@ -29,9 +29,9 @@ sw_access_field_swwel:
begin begin
sw_access_byte: sw_access_byte:
rtl: |- rtl: |-
if (byte_enable[{i}]) if (b2r.byte_en[{i}])
<<INDENT>> <<INDENT>>
{path}_q{genvars}[{msb_field}:{lsb_field}] <= sw_wr_bus[{msb_bus}:{lsb_bus}]; {path}_q{genvars}[{msb_field}:{lsb_field}] <= b2r.data[{msb_bus}:{lsb_bus}];
<<UNINDENT>> <<UNINDENT>>
signals: signals:
- name: '{path}_q' - name: '{path}_q'
@ -114,33 +114,33 @@ end_field_ff:
end // of {path}'s always_ff end // of {path}'s always_ff
OnWriteType.woset: OnWriteType.woset:
rtl: |- rtl: |-
if (byte_enable[{i}]) // woset property if (b2r.byte_en[{i}]) // woset property
begin begin
{path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] | sw_wr_bus[{msb_bus}:{lsb_bus}]; {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] | b2r.data[{msb_bus}:{lsb_bus}];
end end
OnWriteType.woclr: OnWriteType.woclr:
rtl: |- rtl: |-
if (byte_enable[{i}]) // woclr property if (b2r.byte_en[{i}]) // woclr property
begin begin
{path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] & ~sw_wr_bus[{msb_bus}:{lsb_bus}]; {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] & ~b2r.data[{msb_bus}:{lsb_bus}];
end end
OnWriteType.wot: OnWriteType.wot:
rtl: |- rtl: |-
if (byte_enable[{i}]) // wot property if (b2r.byte_en[{i}]) // wot property
begin begin
{path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] ^ sw_wr_bus[{msb_bus}:{lsb_bus}]; {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] ^ b2r.data[{msb_bus}:{lsb_bus}];
end end
OnWriteType.wzs: OnWriteType.wzs:
rtl: |- rtl: |-
if (byte_enable[{i}]) // wzs property if (b2r.byte_en[{i}]) // wzs property
begin begin
{path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] & sw_wr_bus[{msb_bus}:{lsb_bus}]; {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] & b2r.data[{msb_bus}:{lsb_bus}];
end end
OnWriteType.wzt: OnWriteType.wzt:
rtl: |- rtl: |-
if (byte_enable[{i}]) // wzt property if (b2r.byte_en[{i}]) // wzt property
begin begin
{path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] ~^ sw_wr_bus[{msb_bus}:{lsb_bus}]; {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] ~^ b2r.data[{msb_bus}:{lsb_bus}];
end end
OnWriteType.wclr: OnWriteType.wclr:
rtl: |- rtl: |-
@ -210,7 +210,7 @@ swacc_assign:
rtl: |- rtl: |-
// Combinational block to generate swacc-output signals // Combinational block to generate swacc-output signals
assign {path}_swacc{genvars} = ({path_wo_field}__any_alias_sw_wr{genvars} || {path_wo_field}__any_alias_sw_rd{genvars}) && |byte_enable[{msbyte}:{lsbyte}]; assign {path}_swacc{genvars} = ({path_wo_field}__any_alias_sw_wr{genvars} || {path_wo_field}__any_alias_sw_rd{genvars}) && |b2r.byte_en[{msbyte}:{lsbyte}];
output_ports: output_ports:
- name: '{path}_swacc' - name: '{path}_swacc'
signal_type: 'logic' signal_type: 'logic'
@ -228,7 +228,7 @@ swmod_always_comb:
signal_type: 'logic' signal_type: 'logic'
swmod_assign: swmod_assign:
rtl: |- rtl: |-
{path}_swmod{genvars} |= {path_wo_field}__any_alias_sw_{rd_wr}{genvars} && |byte_enable[{msbyte}:{lsbyte}]; {path}_swmod{genvars} |= {path_wo_field}__any_alias_sw_{rd_wr}{genvars} && |b2r.byte_en[{msbyte}:{lsbyte}];
output_ports: output_ports:
- name: '{path}_swmod' - name: '{path}_swmod'
signal_type: 'logic' signal_type: 'logic'

View File

@ -3,9 +3,9 @@ rw_wire_assign_1_dim:
rtl: | rtl: |
// Register-activation for '{path}' {alias} // Register-activation for '{path}' {alias}
assign {path}_accss = addr == {addr}; assign {path}_accss = b2r.addr == {addr};
assign {path}_sw_wr = {path}_accss && r_vld; assign {path}_sw_wr = {path}_accss && b2r.r_vld;
assign {path}_sw_rd = {path}_accss && w_vld; assign {path}_sw_rd = {path}_accss && b2r.w_vld;
signals: signals:
- name: '{path}_sw_wr' - name: '{path}_sw_wr'
signal_type: 'logic' signal_type: 'logic'
@ -17,9 +17,9 @@ rw_wire_assign_multi_dim:
rtl: |- rtl: |-
// Register-activation for '{path}' {alias} // Register-activation for '{path}' {alias}
assign {path}_accss{genvars} = addr == {addr}+({genvars_sum}); assign {path}_accss{genvars} = b2r.addr == {addr}+({genvars_sum});
assign {path}_sw_wr{genvars} = {path}_accss{genvars} && r_vld; assign {path}_sw_wr{genvars} = {path}_accss{genvars} && b2r.r_vld;
assign {path}_sw_rd{genvars} = {path}_accss{genvars} && w_vld; assign {path}_sw_rd{genvars} = {path}_accss{genvars} && b2r.w_vld;
signals: signals:
- name: '{path}_sw_wr' - name: '{path}_sw_wr'
signal_type: 'logic' signal_type: 'logic'

View File

@ -1,35 +1,174 @@
/*
* Copyright 2021 Dennis Potter <dennis@dennispotter.eu>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
module amba3ahblite_widget module amba3ahblite_widget
import srdl2sv_widget_pkg::*;
#(
parameter FLOP_IN = 0, // Set to '1' to flop input from the AHB bus. This is meant
// to help meet timing. Don't use this to synchronize the input.
parameter SYNC_IO = 0 // Set to '1' to in case HCLK and bus_clk are asynchronous
// By default, mainly for it to directly work in simulations,
// it will double-flops based on always_ff-blocks. To replace
// this module with a proper MTBF-optimized double flop cell,
// the contents of the synchronizer module `srdl2sv_sync.sv`
// shall be updated
)
( (
// Register clock // Register clock
input bus_clk, input reg_clk,
input bus_rst_n,
// Outputs to internal logic // Outputs to internal logic
output [31:0] addr, output b2r_t b2r,
output w_vld,
output r_vld,
output [ 3:0] byte_enable,
output [31:0] sw_wr_bus,
// Inputs from internal logic // Inputs from internal logic
input [31:0] sw_rd_bus, input r2b_t r2b,
// Bus protocol // Bus protocol
input HRESETn, input HRESETn,
input HCLK, input HCLK,
input [31:0] HADDR, input HSEL,
input HWRITE, input [31:0] HADDR,
input [ 2:0] HSIZE, input HWRITE,
input [ 2:0] HBURST, input [ 2:0] HSIZE,
input [ 3:0] HPROT, input [ 2:0] HBURST,
input [ 1:0] HTRANS, input [ 3:0] HPROT,
input HMASTLOCK, input [ 1:0] HTRANS,
input HREADY, input [31:0] HWDATA,
input HREADY,
output HREADYOUT, output logic HREADYOUT,
output HRESP, output logic HRESP,
output [31:0] HRDATA output logic [31:0] HRDATA
); );
// TODO: Add synchronizer logic
/***
* Translate HWRITE & HSEL into a write/read operation for the register logic
***/
logic r_vld_next;
logic w_vld_next;
always_comb
begin
w_vld_next = 1'b0;
r_vld_next = 1'b0;
if (HWRITE)
w_vld_next = HSEL;
else
r_vld_next = HSEL;
end
/***
* Determine the number of active bytes
***/
logic [3:0] b2r_byte_en_next;
always_comb
begin
case (HTRANS)
3'b000 : b2r_byte_en_next = 4'b0001;
3'b001 : b2r_byte_en_next = 4'b0011;
3'b010 : b2r_byte_en_next = 4'b1111;
// TODO: Implement larger sizes
default: b2r_byte_en_next = 4'b1111;
endcase
end
/***
* Flop or sync input if required
***/
generate
if (FLOP_IN)
begin
always_ff @(posedge HCLK or negedge HRESETn)
if (!HRESETn)
begin
b2r.r_vld <= 1'b0;
b2r.w_vld <= 1'b0;
end
else
begin
b2r.r_vld <= r_vld_next;
b2r.w_vld <= w_vld_next;
end
always_ff @(posedge HCLK)
if (HWRITE)
begin
b2r.data <= HWDATA;
b2r.byte_en <= b2r_byte_en_next;
end
end
else
begin
assign b2r.r_vld = r_vld_next;
assign b2r.w_vld = w_vld_next;
assign b2r.data = HWDATA;
end
endgenerate
/***
* Keep track of an ungoing transaction
***/
logic reg_busy_q;
always_ff @(posedge HCLK or negedge HRESETn)
if (!HRESETn)
reg_busy_q <= 1'b0;
else if ((b2r.r_vld || b2r.w_vld) && !r2b.rdy)
reg_busy_q <= 1'b1;
else if (r2b.rdy)
reg_busy_q <= 1'b0;
assign HREADYOUT = !reg_busy_q;
/***
* Return to AHB bus once the register block is ready
***/
// Return actual data
logic ongoing_read_q;
always_ff @(posedge HCLK or negedge HRESETn)
if (!HRESETn)
ongoing_read_q <= 1'b0;
else if (b2r.r_vld && !r2b.rdy)
ongoing_read_q <= 1'b1;
else if (r2b.rdy)
ongoing_read_q <= 1'b0;
always_ff @(posedge HCLK)
if ((b2r.r_vld || ongoing_read_q) && r2b.rdy)
HRDATA <= r2b.data;
// Did an error occur while reading?
always_ff @(posedge HCLK or negedge HRESETn)
if (!HRESETn)
HRESP <= 1'b0;
else
HRESP <= r2b.err;
endmodule endmodule

View File

@ -1,24 +1,30 @@
# This file only contains the instantiation of the module # This file only contains the instantiation of the module
module_instantiation: module_instantiation:
rtl: |- rtl: |-
/**************************** /*******************************************************************
* AMBA 3 AHB Lite Widget * AMBA 3 AHB Lite Widget
****************************/ * ======================
* Naming conventions
* - r2b.* -> Signals from registers to bus
* - b2r.* -> Signals from bus to registers
* - H* -> Signals as defined in AMBA3 AHB Lite
* specification
* - bus_clk -> Clock that that drives signals on bus
* - reg_clk -> Clock that drives register flops
* - bus_rst_n -> Asynchronous reset that resets only the bus (but
* (not the registers). The deassertion of this
* reset shall be synchronized to bus_clk
*******************************************************************/
amba3ahblite_widget amba3ahblite_widget
amba3ahblite_widget_inst amba3ahblite_widget_inst
(// Clocks & Resets (// Register clock
.bus_clk, .reg_clk,
.bus_rst_n,
// Outputs to internal logic // Outputs to internal logic
.addr, .b2r,
.w_vld,
.r_vld,
.byte_enable,
.sw_wr_bus,
// Inputs from internal logic // Inputs from internal logic
.sw_rd_bus, .r2b,
// Bus protocol // Bus protocol
.HRESETn, .HRESETn,
@ -29,25 +35,18 @@ module_instantiation:
.HBURST, .HBURST,
.HPROT, .HPROT,
.HTRANS, .HTRANS,
.HMASTLOCK, .HWDATA,
.HREADY, .HREADY,
.HSEL,
.HREADYOUT, .HREADYOUT,
.HRESP, .HRESP,
.HRDATA); .HRDATA);
signals: signals:
- name: 'addr' - name: 'b2r'
signal_type: 'logic [31:0]' signal_type: 'b2r_t'
- name: 'w_vld' - name: 'r2b'
signal_type: 'logic' signal_type: 'r2b_t'
- name: 'r_vld'
signal_type: 'logic'
- name: 'byte_enable'
signal_type: 'logic [ 3:0]'
- name: 'sw_wr_bus'
signal_type: 'logic [31:0]'
- name: 'sw_rd_bus'
signal_type: 'logic [31:0]'
input_ports: input_ports:
- name: 'HRESETn' - name: 'HRESETn'
signal_type: '' signal_type: ''
@ -65,10 +64,12 @@ module_instantiation:
signal_type: '[3:0]' signal_type: '[3:0]'
- name: 'HTRANS' - name: 'HTRANS'
signal_type: '[1:0]' signal_type: '[1:0]'
- name: 'HMASTLOCK' - name: 'HWDATA'
signal_type: '' signal_type: '[31:0]'
- name: 'HREADY' - name: 'HREADY'
signal_type: '' signal_type: ''
- name: 'HSEL'
signal_type: ''
output_ports: output_ports:
- name: 'HREADYOUT' - name: 'HREADYOUT'
signal_type: '' signal_type: ''

View File

@ -0,0 +1,17 @@
package srdl2sv_widget_pkg;
typedef struct {
logic [31:0] addr;
logic [31:0] data;
logic w_vld;
logic r_vld;
logic [ 3:0] byte_en;
} b2r_t;
typedef struct {
logic [31:0] data;
logic rdy;
logic err;
} r2b_t;
endpackage

View File

@ -58,11 +58,12 @@ if __name__ == "__main__":
out_addrmap_file = "{}/{}.sv".format(config['output_dir'], addrmap.name) out_addrmap_file = "{}/{}.sv".format(config['output_dir'], addrmap.name)
with open(out_addrmap_file, 'w') as file: with open(out_addrmap_file, 'w') as file:
file.write( print(
addrmap.get_rtl( addrmap.get_rtl(
tab_width=config['tab_width'], tab_width=config['tab_width'],
real_tabs=config['real_tabs'] real_tabs=config['real_tabs']
) ),
file=file
) )
logger.info('Succesfully created "{}"'.format(out_addrmap_file)) logger.info('Succesfully created "{}"'.format(out_addrmap_file))
@ -75,7 +76,7 @@ if __name__ == "__main__":
).items(): ).items():
if value: if value:
with open('{}/{}_pkg.sv'.format(config['output_dir'], key), 'w') as file: with open('{}/{}_pkg.sv'.format(config['output_dir'], key), 'w') as file:
file.write(value) print(value, file=file)
# Copy over widget RTL from widget directory # Copy over widget RTL from widget directory
widget_rtl = pkg_resources.read_text(widgets, '{}.sv'.format(config['bus'])) widget_rtl = pkg_resources.read_text(widgets, '{}.sv'.format(config['bus']))
@ -83,9 +84,19 @@ if __name__ == "__main__":
out_widget_file = "{}/{}.sv".format(config['output_dir'], config['bus']) out_widget_file = "{}/{}.sv".format(config['output_dir'], config['bus'])
with open(out_widget_file, 'w') as file: with open(out_widget_file, 'w') as file:
file.write(widget_rtl) print(widget_rtl, file=file)
logger.info("Selected, implemented, and copied '{}' widget".format(config['bus'])) logger.info("Selected, implemented, and copied '{}' widget".format(config['bus']))
# Copy over generic srdl2sv_widget_pkg
widget_if_rtl = pkg_resources.read_text(widgets, 'srdl2sv_widget_pkg.sv')
out_widget_if_file = "{}/srdl2sv_widget_pkg.sv".format(config['output_dir'])
with open(out_widget_if_file, 'w') as file:
print(widget_if_rtl,file=file)
logger.info("Copied 'srdl2sv_widget_pkg.sv")
# Print elapsed time # Print elapsed time
logger.info("Elapsed time: %f seconds", time.time() - start) logger.info("Elapsed time: %f seconds", time.time() - start)