break up hdl definition into multiple member functinos
This commit is contained in:
parent
9dba38925b
commit
3fda03ec90
3
Makefile
3
Makefile
|
|
@ -49,3 +49,6 @@ clean:
|
||||||
rm -f *.out *.vcd
|
rm -f *.out *.vcd
|
||||||
rm -rf dist/
|
rm -rf dist/
|
||||||
rm -rf src/mantaray.egg-info
|
rm -rf src/mantaray.egg-info
|
||||||
|
|
||||||
|
loc:
|
||||||
|
find . -type f \( -iname \*.sv -o -iname \*.v -o -iname \*.py -o -iname \*.yaml -o -iname \*.md \) | sed 's/.*/"&"/' | xargs wc -l
|
||||||
|
|
@ -1,471 +0,0 @@
|
||||||
`default_nettype none
|
|
||||||
`timescale 1ns/1ps
|
|
||||||
/* This manata definition was generated on 08 Mar 2023 at 21:04:09 by fischerm
|
|
||||||
*
|
|
||||||
* If this breaks or if you've got dank formal verification memes,
|
|
||||||
* please contact fischerm [at] mit.edu
|
|
||||||
*/
|
|
||||||
|
|
||||||
rx_uart #(.CLOCKS_PER_BAUD(868)) urx (
|
|
||||||
.i_clk(clk),
|
|
||||||
.i_uart_rx(tb_urx_rxd),
|
|
||||||
.o_wr(urx_brx_axiv),
|
|
||||||
.o_data(urx_brx_axid));
|
|
||||||
|
|
||||||
// uart_rx --> bridge_rx signals
|
|
||||||
logic [7:0] urx_brx_axid;
|
|
||||||
logic urx_brx_axiv;
|
|
||||||
|
|
||||||
bridge_rx brx (
|
|
||||||
.clk(clk),
|
|
||||||
|
|
||||||
.rx_data(urx_brx_axid),
|
|
||||||
.rx_valid(urx_brx_axiv),
|
|
||||||
|
|
||||||
.addr_o(),
|
|
||||||
.wdata_o(),
|
|
||||||
.rw_o(),
|
|
||||||
.valid_o());
|
|
||||||
|
|
||||||
la_core my_logic_analyzer (
|
|
||||||
.clk(),
|
|
||||||
|
|
||||||
.addr_i(),
|
|
||||||
.wdata_i(),
|
|
||||||
.rdata_i(),
|
|
||||||
.rw_i(),
|
|
||||||
.valid_i(),
|
|
||||||
|
|
||||||
.addr_o(),
|
|
||||||
.wdata_o(),
|
|
||||||
.rdata_o(),
|
|
||||||
.rw_o(),
|
|
||||||
.valid_o());
|
|
||||||
|
|
||||||
|
|
||||||
bridge_tx btx (
|
|
||||||
.clk(clk),
|
|
||||||
|
|
||||||
.rdata_i(),
|
|
||||||
.rw_i(),
|
|
||||||
.valid_i(),
|
|
||||||
|
|
||||||
.ready_i(utx_btx_ready),
|
|
||||||
.data_o(btx_utx_data),
|
|
||||||
.valid_o(btx_utx_valid));
|
|
||||||
|
|
||||||
logic utx_btx_ready;
|
|
||||||
logic btx_utx_valid;
|
|
||||||
logic [7:0] btx_utx_data;
|
|
||||||
|
|
||||||
uart_tx #(.CLOCKS_PER_BAUD(868)) utx (
|
|
||||||
.clk(clk),
|
|
||||||
|
|
||||||
.data(btx_utx_data),
|
|
||||||
.valid(btx_utx_valid),
|
|
||||||
.ready(utx_btx_ready),
|
|
||||||
|
|
||||||
.tx(utx_tb_tx));
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
/* ---- Module Definitions ---- */
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Filename: rxuart.v
|
|
||||||
//
|
|
||||||
// Project: Verilog Tutorial Example file
|
|
||||||
//
|
|
||||||
// Purpose: Receives a character from a UART (serial port) wire. Key
|
|
||||||
// features of this core include:
|
|
||||||
//
|
|
||||||
// - The baud rate is constant, and set by the CLOCKS_PER_BAUD parameter.
|
|
||||||
// To be successful, one baud interval must be (approximately)
|
|
||||||
// equal to CLOCKS_PER_BAUD / CLOCK_RATE_HZ seconds long.
|
|
||||||
//
|
|
||||||
// - The protocol used is the basic 8N1: 8 data bits, 1 stop bit, and no
|
|
||||||
// parity.
|
|
||||||
//
|
|
||||||
// - This core has no reset
|
|
||||||
// - This core has no error detection for frame errors
|
|
||||||
// - This core cannot detect, report, or even recover from, a break
|
|
||||||
// condition on the line. A break condition is defined as a
|
|
||||||
// period of time where the i_uart_rx line is held low for longer
|
|
||||||
// than one data byte (10 baud intervals)
|
|
||||||
//
|
|
||||||
// - There's no clock rate detection in this core
|
|
||||||
//
|
|
||||||
// Perhaps one of the nicer features of this core is that it (can be)
|
|
||||||
// formally verified. It depends upon a separate (formally verified)
|
|
||||||
// transmit core for this purpose.
|
|
||||||
//
|
|
||||||
// As with the other cores within this tutorial, there may (or may not) be
|
|
||||||
// bugs within this design for you to find.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Creator: Dan Gisselquist, Ph.D.
|
|
||||||
// Gisselquist Technology, LLC
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Written and distributed by Gisselquist Technology, LLC
|
|
||||||
//
|
|
||||||
// This program is hereby granted to the public domain.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
module rx_uart(
|
|
||||||
input wire i_clk,
|
|
||||||
input wire i_uart_rx,
|
|
||||||
output reg o_wr,
|
|
||||||
output reg [7:0] o_data);
|
|
||||||
|
|
||||||
parameter [15:0] CLOCKS_PER_BAUD = 868;
|
|
||||||
localparam [3:0] IDLE = 4'h0;
|
|
||||||
localparam [3:0] BIT_ZERO = 4'h1;
|
|
||||||
// localparam [3:0] BIT_ONE = 4'h2;
|
|
||||||
// localparam [3:0] BIT_TWO = 4'h3;
|
|
||||||
// localparam [3:0] BIT_THREE = 4'h4;
|
|
||||||
// localparam [3:0] BIT_FOUR = 4'h5;
|
|
||||||
// localparam [3:0] BIT_FIVE = 4'h6;
|
|
||||||
// localparam [3:0] BIT_SIX = 4'h7;
|
|
||||||
// localparam [3:0] BIT_SEVEN = 4'h8;
|
|
||||||
localparam [3:0] STOP_BIT = 4'h9;
|
|
||||||
|
|
||||||
reg [3:0] state;
|
|
||||||
reg [15:0] baud_counter;
|
|
||||||
reg zero_baud_counter;
|
|
||||||
|
|
||||||
// 2FF Synchronizer
|
|
||||||
//
|
|
||||||
reg ck_uart;
|
|
||||||
reg q_uart;
|
|
||||||
initial { ck_uart, q_uart } = -1;
|
|
||||||
always @(posedge i_clk)
|
|
||||||
{ ck_uart, q_uart } <= { q_uart, i_uart_rx };
|
|
||||||
|
|
||||||
initial state = IDLE;
|
|
||||||
initial baud_counter = 0;
|
|
||||||
|
|
||||||
always @(posedge i_clk)
|
|
||||||
if (state == IDLE) begin
|
|
||||||
state <= IDLE;
|
|
||||||
baud_counter <= 0;
|
|
||||||
if (!ck_uart) begin
|
|
||||||
state <= BIT_ZERO;
|
|
||||||
baud_counter <= CLOCKS_PER_BAUD+CLOCKS_PER_BAUD/2-1'b1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
else if (zero_baud_counter) begin
|
|
||||||
state <= state + 1;
|
|
||||||
baud_counter <= CLOCKS_PER_BAUD-1'b1;
|
|
||||||
if (state == STOP_BIT) begin
|
|
||||||
state <= IDLE;
|
|
||||||
baud_counter <= 0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
else baud_counter <= baud_counter - 1'b1;
|
|
||||||
|
|
||||||
always @(*)
|
|
||||||
zero_baud_counter = (baud_counter == 0);
|
|
||||||
|
|
||||||
always @(posedge i_clk)
|
|
||||||
if ((zero_baud_counter)&&(state != STOP_BIT))
|
|
||||||
o_data <= { ck_uart, o_data[7:1] };
|
|
||||||
|
|
||||||
initial o_wr = 1'b0;
|
|
||||||
always @(posedge i_clk)
|
|
||||||
o_wr <= ((zero_baud_counter)&&(state == STOP_BIT));
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module bridge_rx(
|
|
||||||
input wire clk,
|
|
||||||
|
|
||||||
input wire[7:0] rx_data,
|
|
||||||
input wire rx_valid,
|
|
||||||
|
|
||||||
output reg[15:0] addr_o,
|
|
||||||
output reg[15:0] wdata_o,
|
|
||||||
output reg rw_o,
|
|
||||||
output reg valid_o
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// this is a hack, the FSM needs to be updated
|
|
||||||
// but this will bypass it for now
|
|
||||||
parameter ready_i = 1;
|
|
||||||
|
|
||||||
parameter ADDR_WIDTH = 0;
|
|
||||||
parameter DATA_WIDTH = 0;
|
|
||||||
|
|
||||||
localparam PREAMBLE = 8'h4D;
|
|
||||||
localparam CR = 8'h0D;
|
|
||||||
localparam LF = 8'h0A;
|
|
||||||
|
|
||||||
localparam ACQUIRE = 0;
|
|
||||||
localparam TRANSMIT = 1;
|
|
||||||
localparam ERROR = 2;
|
|
||||||
|
|
||||||
reg [1:0] state;
|
|
||||||
reg [3:0] bytes_received;
|
|
||||||
|
|
||||||
// no global resets!
|
|
||||||
initial begin
|
|
||||||
addr_o = 0;
|
|
||||||
wdata_o = 0;
|
|
||||||
rw_o = 0;
|
|
||||||
valid_o = 0;
|
|
||||||
bytes_received = 0;
|
|
||||||
state = ACQUIRE;
|
|
||||||
end
|
|
||||||
|
|
||||||
reg [3:0] rx_data_decoded;
|
|
||||||
reg rx_data_is_0_thru_9;
|
|
||||||
reg rx_data_is_A_thru_F;
|
|
||||||
|
|
||||||
always @(*) begin
|
|
||||||
rx_data_is_0_thru_9 = (rx_data >= 8'h30) & (rx_data <= 8'h39);
|
|
||||||
rx_data_is_A_thru_F = (rx_data >= 8'h41) & (rx_data <= 8'h46);
|
|
||||||
|
|
||||||
if (rx_data_is_0_thru_9) rx_data_decoded = rx_data - 8'h30;
|
|
||||||
else if (rx_data_is_A_thru_F) rx_data_decoded = rx_data - 8'h41 + 'd10;
|
|
||||||
else rx_data_decoded = 0;
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
always @(posedge clk) begin
|
|
||||||
if (state == ACQUIRE) begin
|
|
||||||
if(rx_valid) begin
|
|
||||||
|
|
||||||
if (bytes_received == 0) begin
|
|
||||||
if(rx_data == PREAMBLE) bytes_received <= 1;
|
|
||||||
end
|
|
||||||
|
|
||||||
else if( (bytes_received >= 1) & (bytes_received <= 4) ) begin
|
|
||||||
// only advance if byte is valid hex digit
|
|
||||||
if(rx_data_is_0_thru_9 | rx_data_is_A_thru_F) begin
|
|
||||||
addr_o <= (addr_o << 4) | rx_data_decoded;
|
|
||||||
bytes_received <= bytes_received + 1;
|
|
||||||
end
|
|
||||||
|
|
||||||
else state <= ERROR;
|
|
||||||
end
|
|
||||||
|
|
||||||
else if( bytes_received == 5) begin
|
|
||||||
if( (rx_data == CR) | (rx_data == LF)) begin
|
|
||||||
valid_o <= 1;
|
|
||||||
rw_o = 0;
|
|
||||||
bytes_received <= 0;
|
|
||||||
state <= TRANSMIT;
|
|
||||||
end
|
|
||||||
|
|
||||||
else if (rx_data_is_0_thru_9 | rx_data_is_A_thru_F) begin
|
|
||||||
bytes_received <= bytes_received + 1;
|
|
||||||
wdata_o <= (wdata_o << 4) | rx_data_decoded;
|
|
||||||
end
|
|
||||||
|
|
||||||
else state <= ERROR;
|
|
||||||
end
|
|
||||||
|
|
||||||
else if ( (bytes_received >= 6) & (bytes_received <= 8) ) begin
|
|
||||||
|
|
||||||
if (rx_data_is_0_thru_9 | rx_data_is_A_thru_F) begin
|
|
||||||
wdata_o <= (wdata_o << 4) | rx_data_decoded;
|
|
||||||
bytes_received <= bytes_received + 1;
|
|
||||||
end
|
|
||||||
|
|
||||||
else state <= ERROR;
|
|
||||||
end
|
|
||||||
|
|
||||||
else if (bytes_received == 9) begin
|
|
||||||
bytes_received <= 0;
|
|
||||||
if( (rx_data == CR) | (rx_data == LF)) begin
|
|
||||||
valid_o <= 1;
|
|
||||||
rw_o <= 1;
|
|
||||||
state <= TRANSMIT;
|
|
||||||
end
|
|
||||||
|
|
||||||
else state <= ERROR;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
else if (state == TRANSMIT) begin
|
|
||||||
if(ready_i) begin
|
|
||||||
valid_o <= 0;
|
|
||||||
state <= ACQUIRE;
|
|
||||||
end
|
|
||||||
|
|
||||||
if(rx_valid) begin
|
|
||||||
if ( (rx_data != CR) & (rx_data != LF)) begin
|
|
||||||
valid_o <= 0;
|
|
||||||
state <= ERROR;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module bridge_tx(
|
|
||||||
input wire clk,
|
|
||||||
|
|
||||||
input wire [15:0] rdata_i,
|
|
||||||
input wire rw_i,
|
|
||||||
input wire valid_i,
|
|
||||||
|
|
||||||
output reg [7:0] data_o,
|
|
||||||
input wire ready_i,
|
|
||||||
output reg valid_o);
|
|
||||||
|
|
||||||
localparam PREAMBLE = 8'h4D;
|
|
||||||
localparam CR = 8'h0D;
|
|
||||||
localparam LF = 8'h0A;
|
|
||||||
|
|
||||||
logic busy;
|
|
||||||
logic [15:0] buffer;
|
|
||||||
logic [3:0] byte_counter;
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
busy = 0;
|
|
||||||
buffer = 0;
|
|
||||||
byte_counter = 0;
|
|
||||||
valid_o = 0;
|
|
||||||
end
|
|
||||||
|
|
||||||
always @(posedge clk) begin
|
|
||||||
if (!busy) begin
|
|
||||||
if (valid_i && !rw_i) begin
|
|
||||||
busy <= 1;
|
|
||||||
buffer <= rdata_i;
|
|
||||||
byte_counter <= 0;
|
|
||||||
valid_o <= 1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (busy) begin
|
|
||||||
|
|
||||||
if(ready_i) begin
|
|
||||||
byte_counter <= byte_counter + 1;
|
|
||||||
|
|
||||||
if (byte_counter > 5) begin
|
|
||||||
byte_counter <= 0;
|
|
||||||
|
|
||||||
// stop transmitting if we don't have both valid and read
|
|
||||||
if ( !(valid_i && !rw_i) ) begin
|
|
||||||
busy <= 0;
|
|
||||||
valid_o <= 0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always @(*) begin
|
|
||||||
case (byte_counter)
|
|
||||||
0: data_o = PREAMBLE;
|
|
||||||
1: data_o = (buffer[15:12] < 10) ? (buffer[15:12] + 8'h30) : (buffer[15:12] + 8'h41 - 'd10);
|
|
||||||
2: data_o = (buffer[11:8] < 10) ? (buffer[11:8] + 8'h30) : (buffer[11:8] + 8'h41 - 'd10);
|
|
||||||
3: data_o = (buffer[7:4] < 10) ? (buffer[7:4] + 8'h30) : (buffer[7:4] + 8'h41 - 'd10);
|
|
||||||
4: data_o = (buffer[3:0] < 10) ? (buffer[3:0] + 8'h30) : (buffer[3:0] + 8'h41 - 'd10);
|
|
||||||
5: data_o = CR;
|
|
||||||
6: data_o = LF;
|
|
||||||
default: data_o = 0;
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module uart_tx(
|
|
||||||
input wire clk,
|
|
||||||
|
|
||||||
input wire [7:0] data,
|
|
||||||
input wire valid,
|
|
||||||
output reg busy,
|
|
||||||
output reg ready,
|
|
||||||
|
|
||||||
output reg tx);
|
|
||||||
|
|
||||||
// this transmitter only works with 8N1 serial, at configurable baudrate
|
|
||||||
parameter CLOCKS_PER_BAUD = 868;
|
|
||||||
|
|
||||||
reg [9:0] baud_counter;
|
|
||||||
reg [8:0] data_buf;
|
|
||||||
reg [3:0] bit_index;
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
baud_counter = CLOCKS_PER_BAUD;
|
|
||||||
data_buf = 0;
|
|
||||||
bit_index = 0;
|
|
||||||
busy = 0;
|
|
||||||
ready = 1;
|
|
||||||
tx = 1;
|
|
||||||
end
|
|
||||||
|
|
||||||
always @(posedge clk) begin
|
|
||||||
if (valid && !busy) begin
|
|
||||||
data_buf <= {1'b1, data};
|
|
||||||
bit_index <= 0;
|
|
||||||
tx <= 0; //wafflestomp that start bit
|
|
||||||
baud_counter <= CLOCKS_PER_BAUD - 1;
|
|
||||||
busy <= 1;
|
|
||||||
ready <= 0;
|
|
||||||
end
|
|
||||||
|
|
||||||
else if (busy) begin
|
|
||||||
baud_counter <= baud_counter - 1;
|
|
||||||
|
|
||||||
ready <= (baud_counter == 1) && (bit_index == 9);
|
|
||||||
|
|
||||||
if (baud_counter == 0) begin
|
|
||||||
baud_counter <= CLOCKS_PER_BAUD - 1;
|
|
||||||
|
|
||||||
|
|
||||||
if (bit_index == 9) begin
|
|
||||||
if(valid) begin
|
|
||||||
data_buf <= {1'b1, data};
|
|
||||||
bit_index <= 0;
|
|
||||||
tx <= 0;
|
|
||||||
end
|
|
||||||
|
|
||||||
else begin
|
|
||||||
busy <= 0;
|
|
||||||
ready <= 1;
|
|
||||||
end
|
|
||||||
// if valid happens here then we should bool
|
|
||||||
end
|
|
||||||
|
|
||||||
else begin
|
|
||||||
tx <= data_buf[bit_index];
|
|
||||||
bit_index <= bit_index + 1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
|
|
||||||
`default_nettype wire
|
|
||||||
|
|
@ -103,8 +103,7 @@ class UARTInterface:
|
||||||
.valid(btx_utx_valid),
|
.valid(btx_utx_valid),
|
||||||
.ready(utx_btx_ready),
|
.ready(utx_btx_ready),
|
||||||
|
|
||||||
.tx(utx_tb_tx));
|
.tx(utx_tb_tx));\n"""
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class IOCore:
|
class IOCore:
|
||||||
|
|
@ -138,20 +137,20 @@ class LogicAnalyzerCore:
|
||||||
|
|
||||||
def hdl_inst(self):
|
def hdl_inst(self):
|
||||||
hdl = f"""
|
hdl = f"""
|
||||||
la_core {self.name} (
|
la_core {self.name} (
|
||||||
.clk(),
|
.clk(clk),
|
||||||
|
|
||||||
.addr_i(),
|
.addr_i(),
|
||||||
.wdata_i(),
|
.wdata_i(),
|
||||||
.rdata_i(),
|
.rdata_i(),
|
||||||
.rw_i(),
|
.rw_i(),
|
||||||
.valid_i(),
|
.valid_i(),
|
||||||
|
|
||||||
.addr_o(),
|
.addr_o(),
|
||||||
.wdata_o(),
|
.wdata_o(),
|
||||||
.rdata_o(),
|
.rdata_o(),
|
||||||
.rw_o(),
|
.rw_o(),
|
||||||
.valid_o());\n\n"""
|
.valid_o());\n\n"""
|
||||||
|
|
||||||
return hdl
|
return hdl
|
||||||
|
|
||||||
|
|
@ -262,6 +261,10 @@ class LogicAnalyzerCore:
|
||||||
tmpl = tmpl.replace("@SAMPLE_DEPTH", str(self.sample_depth))
|
tmpl = tmpl.replace("@SAMPLE_DEPTH", str(self.sample_depth))
|
||||||
return tmpl
|
return tmpl
|
||||||
|
|
||||||
|
def hdl_top_level_ports(self):
|
||||||
|
# this should return the probes that we want to connect to top-level, but like as a string of verilog\
|
||||||
|
return "" # TODO: i'll fix this later
|
||||||
|
|
||||||
|
|
||||||
class Manta:
|
class Manta:
|
||||||
def __init__(self, config_filepath):
|
def __init__(self, config_filepath):
|
||||||
|
|
@ -343,7 +346,7 @@ class Manta:
|
||||||
|
|
||||||
return conns
|
return conns
|
||||||
|
|
||||||
def generate_instantiations(self):
|
def generate_instances(self):
|
||||||
# generates hdl for modules that need to be connected together
|
# generates hdl for modules that need to be connected together
|
||||||
|
|
||||||
insts = []
|
insts = []
|
||||||
|
|
@ -372,46 +375,9 @@ class Manta:
|
||||||
insts.append(hdl)
|
insts.append(hdl)
|
||||||
|
|
||||||
return insts
|
return insts
|
||||||
|
|
||||||
def generate_hdl(self):
|
|
||||||
"""
|
|
||||||
anatomy of manta.v:
|
|
||||||
|
|
||||||
- header
|
def generate_core_chain(self):
|
||||||
- top-level module:
|
insts = self.generate_instances()
|
||||||
- module declaration
|
|
||||||
- top <-> cores
|
|
||||||
- interface_in (for uart, this would be uart_rx and bridge_rx)
|
|
||||||
|
|
||||||
- core chain
|
|
||||||
- core inst
|
|
||||||
- core connection
|
|
||||||
- core inst
|
|
||||||
- core connection
|
|
||||||
....
|
|
||||||
|
|
||||||
- interface_out (for uart, this is bridge_tx and uart_tx)
|
|
||||||
- footer
|
|
||||||
|
|
||||||
|
|
||||||
then come all the module definitions
|
|
||||||
"""
|
|
||||||
|
|
||||||
# generate header
|
|
||||||
user = os.environ.get("USER", os.environ.get("USERNAME"))
|
|
||||||
timestamp = datetime.now().strftime("%d %b %Y at %H:%M:%S")
|
|
||||||
|
|
||||||
header = f"/* This manata definition was generated on {timestamp} by {user}\n"
|
|
||||||
header += " *\n"
|
|
||||||
header += " * If this breaks or if you've got dank formal verification memes,\n"
|
|
||||||
header += " * please contact fischerm [at] mit.edu\n"
|
|
||||||
header += " */\n"
|
|
||||||
|
|
||||||
# generate interface_rx
|
|
||||||
interface_rx = self.interface.rx_hdl_inst()
|
|
||||||
|
|
||||||
# generate chain of cores
|
|
||||||
insts = self.generate_instantiations()
|
|
||||||
conns = self.generate_connections()
|
conns = self.generate_connections()
|
||||||
core_chain = []
|
core_chain = []
|
||||||
for i, inst in enumerate(insts):
|
for i, inst in enumerate(insts):
|
||||||
|
|
@ -419,23 +385,130 @@ class Manta:
|
||||||
|
|
||||||
if (i != len(insts)-1):
|
if (i != len(insts)-1):
|
||||||
core_chain.append(conns[i])
|
core_chain.append(conns[i])
|
||||||
|
|
||||||
|
return '\n'.join(core_chain)
|
||||||
|
|
||||||
core_chain = '\n'.join(core_chain)
|
def generate_header(self):
|
||||||
|
# generate header
|
||||||
|
user = os.environ.get("USER", os.environ.get("USERNAME"))
|
||||||
|
timestamp = datetime.now().strftime("%d %b %Y at %H:%M:%S")
|
||||||
|
|
||||||
# generate interface_tx
|
header = f"""
|
||||||
|
/*
|
||||||
|
This manta definition was generated on {timestamp} by {user}
|
||||||
|
|
||||||
|
If this breaks or if you've got dank formal verification memes,
|
||||||
|
please contact fischerm [at] mit.edu
|
||||||
|
|
||||||
|
Provided under a GNU GPLv3 license. Go wild.
|
||||||
|
*/
|
||||||
|
"""
|
||||||
|
return header
|
||||||
|
|
||||||
|
def generate_declaration(self):
|
||||||
|
# get all the top level connections for each module.
|
||||||
|
|
||||||
|
#ports = [core.top_level_ports() for core in self.cores]
|
||||||
|
#ports = "\n".join(ports)
|
||||||
|
|
||||||
|
return f"""
|
||||||
|
module manta (
|
||||||
|
input wire clk,
|
||||||
|
input wire rx,
|
||||||
|
output reg tx,
|
||||||
|
);"""
|
||||||
|
|
||||||
|
def generate_interface_rx(self):
|
||||||
|
interface_rx = self.interface.rx_hdl_inst()
|
||||||
|
# connect interface_rx to core_chain
|
||||||
|
interface_rx_chain_connection = f"""
|
||||||
|
reg [15:0] brx_{self.cores[0].name}_addr;
|
||||||
|
reg [15:0] brx_{self.cores[0].name}_wdata;
|
||||||
|
reg brx_{self.cores[0].name}_rw;
|
||||||
|
reg brx_{self.cores[0].name}_valid;\n"""
|
||||||
|
|
||||||
|
interface_rx = interface_rx.replace("addr_o()", f"addr_o(brx_{self.cores[0].name}_addr)")
|
||||||
|
interface_rx = interface_rx.replace("wdata_o()", f"wdata_o(brx_{self.cores[0].name}_wdata)")
|
||||||
|
interface_rx = interface_rx.replace("rw_o()", f"rw_o(brx_{self.cores[0].name}_rw)")
|
||||||
|
interface_rx = interface_rx.replace("valid_o()", f"valid_o(brx_{self.cores[0].name}_valid)")
|
||||||
|
|
||||||
|
return interface_rx
|
||||||
|
|
||||||
|
def generate_interface_tx(self):
|
||||||
interface_tx = self.interface.tx_hdl_inst()
|
interface_tx = self.interface.tx_hdl_inst()
|
||||||
|
|
||||||
# generate footer
|
interface_tx = interface_tx.replace("addr_i()", f"addr_o({self.cores[0].name}_btx_addr)")
|
||||||
footer = """endmodule\n"""
|
interface_tx = interface_tx.replace("rdata_i()", f"rdata_o({self.cores[0].name}_btx_rdata)")
|
||||||
|
interface_tx = interface_tx.replace("rw_i()", f"rw_o({self.cores[0].name}_btx_rw)")
|
||||||
|
interface_tx = interface_tx.replace("valid_i()", f"valid_o({self.cores[0].name}_btx_valid)")
|
||||||
|
|
||||||
|
return interface_tx
|
||||||
|
|
||||||
|
def generate_footer(self):
|
||||||
|
return """endmodule\n"""
|
||||||
|
|
||||||
|
def generate_module_defs(self):
|
||||||
# aggregate module definitions and remove duplicates
|
# aggregate module definitions and remove duplicates
|
||||||
module_defs_with_dups = [self.interface.rx_hdl_def()] + [core.hdl_def() for core in self.cores] + [self.interface.tx_hdl_def()]
|
module_defs_with_dups = [self.interface.rx_hdl_def()] + [core.hdl_def() for core in self.cores] + [self.interface.tx_hdl_def()]
|
||||||
module_defs = []
|
module_defs = []
|
||||||
module_defs = [m_def for m_def in module_defs_with_dups if m_def not in module_defs]
|
module_defs = [m_def for m_def in module_defs_with_dups if m_def not in module_defs]
|
||||||
module_defs = '\n'.join(module_defs)
|
return '\n'.join(module_defs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def generate_hdl(self, output_filepath):
|
||||||
|
"""
|
||||||
|
This function generates manta.v, which has the following anatomy:
|
||||||
|
- Header - contains a little blurb about when and who generated the file
|
||||||
|
- Top-Level Module - the actual definition of module manta
|
||||||
|
- Declaration - contains `module manta` and top-level ports
|
||||||
|
that constitutent cores need access to
|
||||||
|
- Interface RX - the modules needed to bring whatever interface the user
|
||||||
|
selected onto the bus. For UART, this is just an instance
|
||||||
|
of uart_rx and bridge_rx.
|
||||||
|
- Core Chain - the chain of cores specified by the user. This follows
|
||||||
|
a sequence of:
|
||||||
|
- Core Instance - HDL specifying an instance of the core.
|
||||||
|
- Core Connection - HDL specifying the registers that connect one
|
||||||
|
core to the next.
|
||||||
|
- Core Instance
|
||||||
|
- Core Connection
|
||||||
|
....
|
||||||
|
|
||||||
|
This repeats for however many cores the user specified.
|
||||||
|
|
||||||
|
- Interface TX - the modules needed to bring the bus out to whatever
|
||||||
|
interface the user selected. For UART, this is just
|
||||||
|
an instance of bridge_tx and uart_tx.
|
||||||
|
- Footer - just the 'endmodule' keyword.
|
||||||
|
|
||||||
|
- Module Definitions - all the source for the modules instantiated in the
|
||||||
|
top-level module.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# generate header
|
||||||
|
header = self.generate_header()
|
||||||
|
|
||||||
|
# generate module declaration
|
||||||
|
declar = self.generate_declaration()
|
||||||
|
|
||||||
|
# generate interface_rx
|
||||||
|
interface_rx = self.generate_interface_rx()
|
||||||
|
|
||||||
|
# generate core chain
|
||||||
|
core_chain = self.generate_core_chain()
|
||||||
|
|
||||||
|
# generate interface_tx
|
||||||
|
interface_tx = self.generate_interface_tx()
|
||||||
|
|
||||||
|
# generate footer
|
||||||
|
footer = self.generate_footer()
|
||||||
|
|
||||||
|
# generate module definitions
|
||||||
|
module_defs = self.generate_module_defs()
|
||||||
|
|
||||||
# assemble all the parts
|
# assemble all the parts
|
||||||
hdl = header + interface_rx + core_chain + interface_tx + footer
|
hdl = header + declar + interface_rx + core_chain + interface_tx + footer
|
||||||
hdl += "\n /* ---- Module Definitions ---- */\n"
|
hdl += "\n /* ---- Module Definitions ---- */\n"
|
||||||
hdl += module_defs
|
hdl += module_defs
|
||||||
|
|
||||||
|
|
@ -445,7 +518,9 @@ class Manta:
|
||||||
hdl = hdl.replace("`timescale 1ns/1ps", "")
|
hdl = hdl.replace("`timescale 1ns/1ps", "")
|
||||||
|
|
||||||
hdl = "`default_nettype none\n" + "`timescale 1ns/1ps\n" + hdl + "`default_nettype wire"
|
hdl = "`default_nettype none\n" + "`timescale 1ns/1ps\n" + hdl + "`default_nettype wire"
|
||||||
return hdl
|
|
||||||
|
with open(output_filepath, 'w') as f:
|
||||||
|
f.write(hdl)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from manta import Manta
|
from manta import Manta
|
||||||
|
|
||||||
m = Manta('/Users/fischerm/fpga/manta/examples/nexys_a7/single_lut_ram/manta.yaml')
|
m = Manta('/Users/fischerm/fpga/manta/examples/nexys_a7/single_lut_ram/manta.yaml')
|
||||||
print (m.generate_hdl())
|
m.generate_hdl('inspecto_time.v')
|
||||||
Loading…
Reference in New Issue