commit 2fe8d6fb46993d09e450b139e9b2d2e7585aea64
parent 3af7ccf4e3afd729225d9d5b0f1234c602d0dbcf
Author: Brian Swetland <swetland@frotz.net>
Date: Wed, 30 Jul 2014 02:59:41 -0700
reg_ifc and axi_to_reg_*: simple register interface and axi->reg bridge
Diffstat:
5 files changed, 471 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
@@ -65,7 +65,11 @@ MODULE_NAME := axi-regs-test
MODULE_SRCS := hdl/test/axi_registers_test.sv
MODULE_SRCS += hdl/axi_ifc.sv
MODULE_SRCS += hdl/axi_registers.sv
-include build/verilator-sim.mk
+MODULE_SRCS += hdl/axi_to_reg_x8.sv
+MODULE_SRCS += hdl/axi_to_reg_impl.sv
+MODULE_SRCS += hdl/reg_ifc.sv
+include build/vivado-xsim.mk
+#include build/verilator-sim.mk
MODULE_NAME := eth-capture-test
MODULE_SRCS := hdl/test/eth_capture_test.sv
diff --git a/hdl/axi_to_reg_impl.sv b/hdl/axi_to_reg_impl.sv
@@ -0,0 +1,237 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+`timescale 1ns/1ps
+
+// AXI Register Bridge
+//
+// Reads and Writes may happen simultaneously
+//
+// Reads:
+// o_rd=1 o_rreg=n on posedge clk
+// i_rdata sampled on next posedge clk
+// Writes:
+// o_wr=1 o_wreg=n o_wdata=w on posedge clk
+
+// TODO: deal with non-length-1 bursts
+
+module axi_to_reg_impl (
+ input clk,
+
+ // AXI Interface
+ axi_ifc.slave s,
+
+ // Register File Interface
+ output reg [R_ADDR_WIDTH-1:0]o_rreg = 0,
+ output reg [R_ADDR_WIDTH-1:0]o_wreg = 0,
+ input wire [31:0]i_rdata[0:COUNT-1],
+ output wire [31:0]o_wdata,
+ output wire o_rd[0:COUNT-1],
+ output wire o_wr[0:COUNT-1]
+ );
+
+parameter integer COUNT = 8;
+
+parameter integer R_ADDR_WIDTH = 2;
+
+`define IWIDTH $bits(s.awid)
+
+typedef enum { W_ADDR, W_DATA, W_RESP } wstate_t;
+
+assign s.bresp = 0;
+assign s.rresp = 0;
+
+//reg [31:0]wdata = 0;
+//reg [31:0]wdata_next;
+
+wstate_t wstate = W_ADDR;
+wstate_t wstate_next;
+
+reg awready_next;
+reg wready_next;
+reg bvalid_next;
+
+reg [R_ADDR_WIDTH-1:0]wreg_next;
+reg [R_ADDR_WIDTH-1:0]rreg_next;
+
+assign o_wdata = s.wdata;
+wire do_wr = (s.wvalid & s.wready);
+reg do_rd = 0;
+
+reg [`IWIDTH-1:0]twid = 0;
+reg [`IWIDTH-1:0]twid_next;
+
+assign s.bid = twid;
+
+reg [2:0]rsel = 0;
+reg [2:0]rsel_next;
+reg [2:0]wsel = 0;
+reg [2:0]wsel_next;
+
+reg [7:0]wselbits;
+reg [7:0]rselbits;
+
+decoder3to8 wsel_decoder(
+ .in(wsel),
+ .out(wselbits)
+ );
+
+decoder3to8 rsel_decoder(
+ .in(rsel),
+ .out(rselbits)
+ );
+
+generate
+for (genvar i = 0; i < COUNT; i++) begin: stuff
+ assign o_rd[i] = do_rd & rselbits[i];
+ assign o_wr[i] = do_wr & wselbits[i];
+end
+endgenerate
+
+always_comb begin
+ wstate_next = wstate;
+ //wdata_next = wdata;
+ wreg_next = o_wreg;
+ wsel_next = wsel;
+ twid_next = twid;
+ awready_next = 0;
+ wready_next = 0;
+ bvalid_next = 0;
+ case (wstate)
+ W_ADDR: if (s.awvalid) begin
+ wstate_next = W_DATA;
+ wready_next = 1;
+ twid_next = s.awid;
+ wreg_next = s.awaddr[R_ADDR_WIDTH+1:2];
+ wsel_next = s.awaddr[22:20];
+ end else begin
+ awready_next = 1;
+ end
+ W_DATA: if (s.wvalid) begin
+ wstate_next = W_RESP;
+ bvalid_next = 1;
+ end else begin
+ wready_next = 1;
+ end
+ W_RESP: if (s.bready) begin
+ wstate_next = W_ADDR;
+ awready_next = 1;
+ end else begin
+ bvalid_next = 1;
+ end
+ endcase
+end
+
+typedef enum { R_ADDR, R_CAPTURE, R_CAPTURE2, R_DATA } rstate_t;
+
+rstate_t rstate = R_ADDR;
+rstate_t rstate_next;
+
+reg arready_next;
+reg rvalid_next;
+reg rlast_next;
+
+reg [31:0]rdata = 0;
+reg [31:0]rdata_next;
+assign s.rdata = rdata;
+
+reg rd_next;
+
+reg [`IWIDTH-1:0]trid = 0;
+reg [`IWIDTH-1:0]trid_next;
+assign s.rid = trid;
+
+always_comb begin
+ rstate_next = rstate;
+ rdata_next = rdata;
+ rreg_next = o_rreg;
+ rsel_next = rsel;
+ trid_next = trid;
+ arready_next = 0;
+ rvalid_next = 0;
+ rlast_next = 0;
+ rd_next = 0;
+ case (rstate)
+ R_ADDR: if (s.arvalid) begin
+ // accept address from AXI
+ rstate_next = R_CAPTURE;
+ trid_next = s.arid;
+ rreg_next = s.araddr[R_ADDR_WIDTH+1:2];
+ rsel_next = s.araddr[22:20];
+ rd_next = 1;
+ end else begin
+ arready_next = 1;
+ end
+ R_CAPTURE: begin
+ // present address and rd to register file
+ rstate_next = R_CAPTURE2;
+ end
+ R_CAPTURE2: begin
+ // capture register file output
+ rstate_next = R_DATA;
+ rvalid_next = 1;
+ rlast_next = 1;
+ rdata_next = i_rdata[rsel];
+ end
+ R_DATA: if (s.rready) begin
+ // present register data to AXI
+ rstate_next = R_ADDR;
+ arready_next = 1;
+ end else begin
+ rvalid_next = 1;
+ rlast_next = 1;
+ end
+ endcase
+end
+
+always_ff @(posedge clk) begin
+ wstate <= wstate_next;
+ wsel <= wsel_next;
+ //wdata <= wdata_next;
+ twid <= twid_next;
+ s.awready <= awready_next;
+ s.wready <= wready_next;
+ s.bvalid <= bvalid_next;
+ o_wreg <= wreg_next;
+
+ rstate <= rstate_next;
+ rdata <= rdata_next;
+ rsel <= rsel_next;
+ trid <= trid_next;
+ s.arready <= arready_next;
+ s.rvalid <= rvalid_next;
+ s.rlast <= rlast_next;
+ o_rreg <= rreg_next;
+ do_rd <= rd_next;
+end
+
+endmodule
+
+module decoder3to8(
+ input [2:0]in,
+ output reg [7:0]out
+ );
+
+always_comb case(in)
+ 0: out = 8'b00000001;
+ 1: out = 8'b00000010;
+ 2: out = 8'b00000100;
+ 3: out = 8'b00001000;
+ 4: out = 8'b00010000;
+ 5: out = 8'b00100000;
+ 6: out = 8'b01000000;
+ 7: out = 8'b10000000;
+endcase
+
+endmodule
diff --git a/hdl/axi_to_reg_x8.sv b/hdl/axi_to_reg_x8.sv
@@ -0,0 +1,110 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+`timescale 1ns / 1ps
+
+module axi_to_reg_x8(
+ input clk,
+ axi_ifc.slave axi,
+ reg_ifc.master bank0,
+ reg_ifc.master bank1,
+ reg_ifc.master bank2,
+ reg_ifc.master bank3,
+ reg_ifc.master bank4,
+ reg_ifc.master bank5,
+ reg_ifc.master bank6,
+ reg_ifc.master bank7
+ );
+
+localparam COUNT = 8;
+localparam WIDTH = 20;
+
+wire [WIDTH-1:0]rreg;
+wire [WIDTH-1:0]wreg;
+wire [31:0]rdata[0:COUNT-1];
+wire [31:0]wdata;
+wire rd[0:COUNT-1];
+wire wr[0:COUNT-1];
+
+axi_to_reg_impl #(
+ .R_ADDR_WIDTH(20),
+ .COUNT(8)
+ ) bridge_impl (
+ .clk(clk),
+ .s(axi),
+ .o_rreg(rreg),
+ .o_wreg(wreg),
+ .o_rd(rd),
+ .o_wr(wr),
+ .i_rdata(rdata),
+ .o_wdata(wdata)
+ );
+
+assign bank0.rd = rd[0];
+assign bank0.wr = wr[0];
+assign bank0.raddr = rreg[$bits(bank0.raddr)-1:0];
+assign bank0.waddr = wreg[$bits(bank0.waddr)-1:0];
+assign bank0.wdata = wdata[$bits(bank0.wdata)-1:0];
+assign rdata[0] = { {32-$bits(bank0.rdata){1'b0}}, bank0.rdata };
+
+assign bank1.rd = rd[1];
+assign bank1.wr = wr[1];
+assign bank1.raddr = rreg[$bits(bank1.raddr)-1:0];
+assign bank1.waddr = wreg[$bits(bank1.waddr)-1:0];
+assign bank1.wdata = wdata[$bits(bank1.wdata)-1:0];
+assign rdata[1] = { {32-$bits(bank1.rdata){1'b0}}, bank1.rdata };
+
+assign bank2.rd = rd[2];
+assign bank2.wr = wr[2];
+assign bank2.raddr = rreg[$bits(bank2.raddr)-1:0];
+assign bank2.waddr = wreg[$bits(bank2.waddr)-1:0];
+assign bank2.wdata = wdata[$bits(bank2.wdata)-1:0];
+assign rdata[2] = { {32-$bits(bank2.rdata){1'b0}}, bank2.rdata };
+
+assign bank3.rd = rd[3];
+assign bank3.wr = wr[3];
+assign bank3.raddr = rreg[$bits(bank3.raddr)-1:0];
+assign bank3.waddr = wreg[$bits(bank3.waddr)-1:0];
+assign bank3.wdata = wdata[$bits(bank3.wdata)-1:0];
+assign rdata[3] = { {32-$bits(bank3.rdata){1'b0}}, bank3.rdata };
+
+assign bank4.rd = rd[4];
+assign bank4.wr = wr[4];
+assign bank4.raddr = rreg[$bits(bank4.raddr)-1:0];
+assign bank4.waddr = wreg[$bits(bank4.waddr)-1:0];
+assign bank4.wdata = wdata[$bits(bank4.wdata)-1:0];
+assign rdata[4] = { {32-$bits(bank4.rdata){1'b0}}, bank4.rdata };
+
+assign bank5.rd = rd[5];
+assign bank5.wr = wr[5];
+assign bank5.raddr = rreg[$bits(bank5.raddr)-1:0];
+assign bank5.waddr = wreg[$bits(bank5.waddr)-1:0];
+assign bank5.wdata = wdata[$bits(bank5.wdata)-1:0];
+assign rdata[5] = { {32-$bits(bank5.rdata){1'b0}}, bank5.rdata };
+
+assign bank6.rd = rd[6];
+assign bank6.wr = wr[6];
+assign bank6.raddr = rreg[$bits(bank6.raddr)-1:0];
+assign bank6.waddr = wreg[$bits(bank6.waddr)-1:0];
+assign bank6.wdata = wdata[$bits(bank6.wdata)-1:0];
+assign rdata[6] = { {32-$bits(bank6.rdata){1'b0}}, bank6.rdata };
+
+assign bank7.rd = rd[7];
+assign bank7.wr = wr[7];
+assign bank7.raddr = rreg[$bits(bank7.raddr)-1:0];
+assign bank7.waddr = wreg[$bits(bank7.waddr)-1:0];
+assign bank7.wdata = wdata[$bits(bank7.wdata)-1:0];
+assign rdata[7] = { {32-$bits(bank7.rdata){1'b0}}, bank7.rdata };
+
+endmodule
diff --git a/hdl/reg_ifc.sv b/hdl/reg_ifc.sv
@@ -0,0 +1,47 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+`timescale 1ns/1ps
+
+// write:
+// slave samples wr, waddr, wdata on posedge clk
+// if wr==1, wdata written to waddr
+// read:
+// slave samples rd, raddr on posedge clk
+// if rd==1, read is requested
+// master samples rdata on next posedge clk
+
+interface reg_ifc;
+
+parameter AWIDTH = 2;
+parameter DWIDTH = 32;
+
+logic [AWIDTH-1:0]raddr;
+logic [AWIDTH-1:0]waddr;
+logic rd;
+logic wr;
+logic [DWIDTH-1:0]rdata;
+logic [DWIDTH-1:0]wdata;
+
+modport master (
+ output raddr, waddr, rd, wr, wdata,
+ input rdata
+ );
+
+modport slave (
+ input raddr, waddr, rd, wr, wdata,
+ output rdata
+ );
+
+endinterface
diff --git a/hdl/test/axi_registers_test.sv b/hdl/test/axi_registers_test.sv
@@ -1,10 +1,30 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
-module testbench(input clk);
+`timescale 1ns/1ps
+`ifdef verilator
+module testbench(input clk);
+`else
+module testbench();
+reg clk = 0;
+always #5 clk = ~clk;
+`endif
axi_ifc axi0();
-
+`ifdef SIMPLE_REGS
wire [1:0]rreg;
wire [1:0]wreg;
reg [31:0]rdata = 32'hdeadbeef;
@@ -22,8 +42,7 @@ axi_registers regs(
.o_rd(rrd),
.o_wr(rwr)
);
-
-wire [31:0]tmp;
+reg [31:0]tmp = 32'heeeeeeee;
always_ff @(posedge clk) begin
if (rrd) case(rreg)
@@ -36,6 +55,46 @@ always_ff @(posedge clk) begin
tmp <= wdata;
end
+`else
+reg_ifc ri0();
+reg_ifc ri1();
+reg_ifc ri2();
+reg_ifc ri3();
+reg_ifc ri4();
+reg_ifc ri5();
+reg_ifc ri6();
+reg_ifc ri7();
+
+axi_to_reg_x8 bridge0(
+ .clk(clk),
+ .axi(axi0),
+ .bank0(ri0),
+ .bank1(ri1),
+ .bank2(ri2),
+ .bank3(ri3),
+ .bank4(ri4),
+ .bank5(ri5),
+ .bank6(ri6),
+ .bank7(ri7)
+ );
+
+reg [31:0]tmp = 32'heeeeeeee;
+
+always_ff @(posedge clk) begin
+ if (ri1.rd) case(ri1.raddr)
+ 0: ri1.rdata <= 32'h10101010;
+ 1: ri1.rdata <= 32'h20202020;
+ 2: ri1.rdata <= 32'h30303030;
+ 3: ri1.rdata <= tmp;
+ endcase
+ if (ri1.wr & (ri1.waddr == 3))
+ tmp <= ri1.wdata;
+end
+
+assign ri3.rdata = 32'h33303330;
+
+`endif
+
integer tick = 0;
reg [31:0]addr = 32'hffffffff;
@@ -56,6 +115,8 @@ axi_rw_engine engine0(
.data(data)
);
+integer BASE = 32'h00100000;
+
always_comb begin
next_do_rd = 0;
next_do_wr = 0;
@@ -63,20 +124,20 @@ always_comb begin
next_data = 32'hffffffff;
if (tick == 10) begin
next_do_rd = 1;
- next_addr = 4;
+ next_addr = BASE + 4;
end else if (tick == 20) begin
next_do_rd = 1;
- next_addr = 0;
+ next_addr = 32'h00300000; //BASE + 0;
end else if (tick == 30) begin
next_do_wr = 1;
next_data = 32'haabbccdd;
- next_addr = 12;
+ next_addr = BASE + 12;
end else if (tick == 40) begin
next_do_rd = 1;
- next_addr = 4;
+ next_addr = BASE + 4;
end else if (tick == 50) begin
next_do_rd = 1;
- next_addr = 12;
+ next_addr = BASE + 12;
end else if (tick == 60) begin
$finish;
end
@@ -226,3 +287,5 @@ assign m.arsize = 2; // 4 bytes
assign m.arlock = 0;
endmodule
+
+