zynq-sandbox

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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:
MMakefile | 6+++++-
Ahdl/axi_to_reg_impl.sv | 237+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahdl/axi_to_reg_x8.sv | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahdl/reg_ifc.sv | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mhdl/test/axi_registers_test.sv | 81++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
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 + +