diff options
| author | Josh Blum <josh@joshknows.com> | 2011-11-07 17:09:07 -0800 | 
|---|---|---|
| committer | Josh Blum <josh@joshknows.com> | 2011-11-07 17:09:07 -0800 | 
| commit | 11f1390bbde65c60f45962acb128cac1ce21e474 (patch) | |
| tree | 372f2e426781de9885889bec6aa98697006268ec /fpga/usrp2/control_lib | |
| parent | 902818f50bbd486138a7d4cd2ce9ba3661f4a732 (diff) | |
| parent | bcb80c5cf9a2117f9d6d22b8e793ea2ecb68ed1f (diff) | |
| download | uhd-11f1390bbde65c60f45962acb128cac1ce21e474.tar.gz uhd-11f1390bbde65c60f45962acb128cac1ce21e474.tar.bz2 uhd-11f1390bbde65c60f45962acb128cac1ce21e474.zip  | |
Merge branch 'fpga_master' into uhd_next
Diffstat (limited to 'fpga/usrp2/control_lib')
| -rw-r--r-- | fpga/usrp2/control_lib/Makefile.srcs | 3 | ||||
| -rw-r--r-- | fpga/usrp2/control_lib/dbsm.v | 164 | ||||
| -rw-r--r-- | fpga/usrp2/control_lib/double_buffer.v | 139 | ||||
| -rw-r--r-- | fpga/usrp2/control_lib/double_buffer_tb.v | 253 | ||||
| -rw-r--r-- | fpga/usrp2/control_lib/gpio_atr.v | 71 | 
5 files changed, 630 insertions, 0 deletions
diff --git a/fpga/usrp2/control_lib/Makefile.srcs b/fpga/usrp2/control_lib/Makefile.srcs index a1c11c026..567feacde 100644 --- a/fpga/usrp2/control_lib/Makefile.srcs +++ b/fpga/usrp2/control_lib/Makefile.srcs @@ -11,7 +11,9 @@ atr_controller.v \  bin2gray.v \  dcache.v \  decoder_3_8.v \ +dbsm.v \  dpram32.v \ +double_buffer.v \  gray2bin.v \  gray_send.v \  icache.v \ @@ -51,4 +53,5 @@ nsgpio16LE.v \  settings_bus_16LE.v \  atr_controller16.v \  fifo_to_wb.v \ +gpio_atr.v \  )) diff --git a/fpga/usrp2/control_lib/dbsm.v b/fpga/usrp2/control_lib/dbsm.v new file mode 100644 index 000000000..fea51096f --- /dev/null +++ b/fpga/usrp2/control_lib/dbsm.v @@ -0,0 +1,164 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +module dbsm +  (input clk, +   input reset, +   input clear, +    +   output write_ok, +   output write_ptr, +   input write_done, + +   output read_ok, +   output read_ptr, +   input read_done, + +   output access_ok, +   output access_ptr, +   input access_done, +   input access_skip_read +   ); + +   localparam PORT_WAIT_0 = 0; +   localparam PORT_USE_0 = 1; +   localparam PORT_WAIT_1 = 2; +   localparam PORT_USE_1 = 3; + +   reg [1:0] write_port_state, access_port_state, read_port_state; + +   localparam BUFF_WRITABLE = 0; +   localparam BUFF_ACCESSIBLE = 1; +   localparam BUFF_READABLE = 2; +   localparam BUFF_ERROR = 3; + +   wire [1:0] buff_state[0:1]; +    +   always @(posedge clk) +     if(reset | clear) +       write_port_state <= PORT_WAIT_0; +     else +       case(write_port_state) +	 PORT_WAIT_0 : +	   if(buff_state[0]==BUFF_WRITABLE) +	     write_port_state <= PORT_USE_0; +	 PORT_USE_0 : +	   if(write_done) +	     write_port_state <= PORT_WAIT_1; +	 PORT_WAIT_1 : +	   if(buff_state[1]==BUFF_WRITABLE) +	     write_port_state <= PORT_USE_1; +	 PORT_USE_1 : +	   if(write_done) +	     write_port_state <= PORT_WAIT_0; +       endcase // case (write_port_state) + +   assign write_ok = (write_port_state == PORT_USE_0) | (write_port_state == PORT_USE_1); +   assign write_ptr = (write_port_state == PORT_USE_1); +    +   always @(posedge clk) +     if(reset | clear) +       access_port_state <= PORT_WAIT_0; +     else +       case(access_port_state) +	 PORT_WAIT_0 : +	   if(buff_state[0]==BUFF_ACCESSIBLE) +	     access_port_state <= PORT_USE_0; +	 PORT_USE_0 : +	   if(access_done) +	     access_port_state <= PORT_WAIT_1; +	 PORT_WAIT_1 : +	   if(buff_state[1]==BUFF_ACCESSIBLE) +	     access_port_state <= PORT_USE_1; +	 PORT_USE_1 : +	   if(access_done) +	     access_port_state <= PORT_WAIT_0; +       endcase // case (access_port_state) +    +   assign access_ok = (access_port_state == PORT_USE_0) | (access_port_state == PORT_USE_1); +   assign access_ptr = (access_port_state == PORT_USE_1); + +   always @(posedge clk) +     if(reset | clear) +       read_port_state <= PORT_WAIT_0; +     else +       case(read_port_state) +	 PORT_WAIT_0 : +	   if(buff_state[0]==BUFF_READABLE) +	     read_port_state <= PORT_USE_0; +	 PORT_USE_0 : +	   if(read_done) +	     read_port_state <= PORT_WAIT_1; +	 PORT_WAIT_1 : +	   if(buff_state[1]==BUFF_READABLE) +	     read_port_state <= PORT_USE_1; +	 PORT_USE_1 : +	   if(read_done) +	     read_port_state <= PORT_WAIT_0; +       endcase // case (read_port_state) +    +   assign read_ok = (read_port_state == PORT_USE_0) | (read_port_state == PORT_USE_1); +   assign read_ptr = (read_port_state == PORT_USE_1); + +   buff_sm #(.PORT_USE_FLAG(PORT_USE_0)) buff0_sm +     (.clk(clk), .reset(reset), .clear(clear), +      .write_done(write_done), .access_done(access_done), .access_skip_read(access_skip_read), .read_done(read_done), +      .write_port_state(write_port_state), .access_port_state(access_port_state), .read_port_state(read_port_state), +      .buff_state(buff_state[0])); +    +   buff_sm #(.PORT_USE_FLAG(PORT_USE_1)) buff1_sm +     (.clk(clk), .reset(reset), .clear(clear), +      .write_done(write_done), .access_done(access_done), .access_skip_read(access_skip_read), .read_done(read_done), +      .write_port_state(write_port_state), .access_port_state(access_port_state), .read_port_state(read_port_state), +      .buff_state(buff_state[1])); +    +endmodule // dbsm + +module buff_sm +  #(parameter PORT_USE_FLAG=0) +   (input clk, input reset, input clear, +    input write_done, input access_done, input access_skip_read, input read_done, +    input [1:0] write_port_state, input [1:0] access_port_state, input [1:0] read_port_state, +    output reg [1:0] buff_state); +    +   localparam BUFF_WRITABLE = 0; +   localparam BUFF_ACCESSIBLE = 1; +   localparam BUFF_READABLE = 2; +   localparam BUFF_ERROR = 3; + +   always @(posedge clk) +     if(reset | clear) +       buff_state <= BUFF_WRITABLE; +     else +       case(buff_state) +	 BUFF_WRITABLE : +	   if(write_done & (write_port_state == PORT_USE_FLAG)) +	     buff_state <= BUFF_ACCESSIBLE; +	 BUFF_ACCESSIBLE : +	   if(access_done & (access_port_state == PORT_USE_FLAG)) +	     if(access_skip_read) +	       buff_state <= BUFF_WRITABLE; +	     else +	       buff_state <= BUFF_READABLE; +	 BUFF_READABLE : +	   if(read_done & (read_port_state == PORT_USE_FLAG)) +	     buff_state <= BUFF_WRITABLE; +	 BUFF_ERROR : +	   ; +       endcase +	  +endmodule // buff_sm diff --git a/fpga/usrp2/control_lib/double_buffer.v b/fpga/usrp2/control_lib/double_buffer.v new file mode 100644 index 000000000..8865bddee --- /dev/null +++ b/fpga/usrp2/control_lib/double_buffer.v @@ -0,0 +1,139 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +module double_buffer +  #(parameter BUF_SIZE = 9) +   (input clk, input reset, input clear, + +    // Random access interface to RAM +    input access_we, +    input access_stb, +    output access_ok, +    input access_done, +    input access_skip_read, +    input [BUF_SIZE-1:0] access_adr, +    output [BUF_SIZE-1:0] access_len, +    input [35:0] access_dat_i,    +    output [35:0] access_dat_o, +     +    // Write FIFO Interface +    input [35:0] data_i, +    input src_rdy_i, +    output dst_rdy_o, +     +    // Read FIFO Interface +    output [35:0] data_o, +    output src_rdy_o, +    input dst_rdy_i +    ); + +   wire [35:0] data_o_0, data_o_1; + +   wire        read, read_ok, read_ptr, read_done; +   wire        write, write_ok, write_ptr, write_done; +    +   wire [BUF_SIZE-1:0] rw0_adr, rw1_adr; +   reg [BUF_SIZE-1:0]  read_adr, write_adr; +   reg [BUF_SIZE-1:0]  len0, len1; +  +   assign data_o = read_ptr ? data_o_1 : data_o_0; +   assign rw0_adr = (write_ok & ~write_ptr) ? write_adr : read_adr; +   assign rw1_adr = (write_ok & write_ptr) ? write_adr : read_adr; +    +   wire [35:0] 	       access_dat_o_0, access_dat_o_1; +   wire 	       access_ptr; +   assign access_dat_o = access_ptr? access_dat_o_1 : access_dat_o_0; +    +   dbsm dbsm  +     (.clk(clk), .reset(reset), .clear(clear), +      .write_ok(write_ok), .write_ptr(write_ptr), .write_done(write_done), +      .access_ok(access_ok), .access_ptr(access_ptr), .access_done(access_done), .access_skip_read(access_skip_read), +      .read_ok(read_ok), .read_ptr(read_ptr), .read_done(read_done)); +    +   // Port A for random access, Port B for FIFO read and write +   ram_2port #(.DWIDTH(36),.AWIDTH(BUF_SIZE)) buffer0 +     (.clka(clk),.ena(access_stb & access_ok & (access_ptr == 0)),.wea(access_we), +      .addra(access_adr),.dia(access_dat_i),.doa(access_dat_o_0), +      .clkb(clk),.enb((read & read_ok & ~read_ptr)|(write & write_ok & ~write_ptr) ),.web(write&write_ok&~write_ptr), +      .addrb(rw0_adr),.dib(data_i),.dob(data_o_0)); +    +   ram_2port #(.DWIDTH(36),.AWIDTH(BUF_SIZE)) buffer1 +     (.clka(clk),.ena(access_stb & access_ok & (access_ptr == 1)),.wea(access_we), +      .addra(access_adr),.dia(access_dat_i),.doa(access_dat_o_1), +      .clkb(clk),.enb((read & read_ok & read_ptr)|(write & write_ok & write_ptr) ),.web(write&write_ok&write_ptr), +      .addrb(rw1_adr),.dib(data_i),.dob(data_o_1)); + +   // Write into buffers +   assign dst_rdy_o =  write_ok; +   assign write = src_rdy_i & write_ok; +   assign write_done = write & data_i[33]; // done +   always @(posedge clk) +     if(reset | clear) +       write_adr <= 0; +     else +       if(write_done) +	 begin +	    write_adr <= 0; +	    if(write_ptr) +	      len1 <= write_adr + 1; +	    else +	      len0 <= write_adr + 1; +	 end +       else if(write) +	 write_adr <= write_adr + 1; + +   assign access_len = access_ptr ? len1 : len0; +    +   reg [1:0] 	       read_state; +   localparam IDLE = 0; +   localparam PRE_READ = 1; +   localparam READING = 2; +    +   always @(posedge clk) +     if(reset | clear) +       begin +	  read_state <= IDLE; +	  read_adr <= 0; +       end +     else +       case(read_state) +	 IDLE : +	   begin +	      read_adr <= 0; +	      if(read_ok) +		read_state <= PRE_READ; +	   end +	 PRE_READ : +	   begin +	      read_state <= READING; +	      read_adr <= 1; +	   end +	  +	 READING : +	   if(dst_rdy_i) +	     begin +		read_adr <= read_adr + 1; +		if(data_o[33]) +		  read_state <= IDLE; +	     end +       endcase // case (read_state) +       +   assign read = ~((read_state==READING)& ~dst_rdy_i); +   assign read_done = data_o[33] & dst_rdy_i & src_rdy_o; +   assign src_rdy_o = (read_state == READING); +    +endmodule // double_buffer diff --git a/fpga/usrp2/control_lib/double_buffer_tb.v b/fpga/usrp2/control_lib/double_buffer_tb.v new file mode 100644 index 000000000..a9aae6956 --- /dev/null +++ b/fpga/usrp2/control_lib/double_buffer_tb.v @@ -0,0 +1,253 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +module double_buffer_tb(); +    +   reg clk = 0; +   reg rst = 1; +   reg clear = 0; +   initial #1000 rst = 0; +   always #50 clk = ~clk; + +   wire src_rdy_o; +   reg src_rdy_i = 0; +   wire dst_rdy_o; +    +   wire dst_rdy_i = 1; +   wire [35:0] data_o; +   reg [35:0]  data_i; + +   wire        access_we, access_stb, access_done, access_ok, access_skip_read; + +   wire [8:0]  access_adr, access_len; +   wire [35:0] dsp_to_buf, buf_to_dsp; +   reg 	       set_stb = 0; +    +   double_buffer db +     (.clk(clk),.reset(rst),.clear(0), +      .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),  +      .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),  +      .access_dat_i(dsp_to_buf), .access_dat_o(buf_to_dsp), + +      .data_i(data_i), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o), +      .data_o(data_o), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i)); + +   dspengine_16to8 dspengine_16to8 +     (.clk(clk),.reset(rst),.clear(0), +      .set_stb(set_stb), .set_addr(0), .set_data({13'h0,1'b1,18'h00400}), +      .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),  +      .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),  +      .access_dat_i(buf_to_dsp), .access_dat_o(dsp_to_buf)); +    +   always @(posedge clk) +     if(src_rdy_o & dst_rdy_i) +       begin +	  $display("SOF %d, EOF %d, OCC %x, DAT %x",data_o[32],data_o[33],data_o[35:34],data_o[31:0]); +	  if(data_o[33]) +	    $display(); +       end	   +   initial $dumpfile("double_buffer_tb.vcd"); +   initial $dumpvars(0,double_buffer_tb); + +   initial +     begin +	@(negedge rst); +	@(posedge clk); +	@(posedge clk); +	@(posedge clk); + +	// Passthrough +	$display("Passthrough"); +	src_rdy_i <= 1; +	data_i <= { 2'b00,1'b0,1'b1,32'hFFFFFFFF}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h04050607}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h08090a0b}; +	@(posedge clk); +	data_i <= { 2'b00,1'b1,1'b0,32'h0c0d0e0f}; +	@(posedge clk); +	src_rdy_i <= 0; +	@(posedge clk); + +	repeat (5) +	  @(posedge clk); + +	$display("Enabled"); +	set_stb <= 1; +	@(posedge clk); +	set_stb <= 0; + +	@(posedge clk); +	$display("Non-IF Data Passthrough"); +	src_rdy_i <= 1; +	data_i <= { 2'b00,1'b0,1'b1,32'hC0000000}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h14151617}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h18191a1b}; +	@(posedge clk); +	data_i <= { 2'b00,1'b1,1'b0,32'h1c1d1e1f}; +	@(posedge clk); +	src_rdy_i <= 0; +	@(posedge clk); + +	while(~dst_rdy_o) +	  @(posedge clk); +	 +	$display("No StreamID, No Trailer, Even"); +	src_rdy_i <= 1; +  	data_i <= { 2'b00,1'b0,1'b1,32'h0000FFFF}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h01000200}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h03000400}; +	src_rdy_i <= 0; +	@(posedge clk); +	@(posedge clk); +	@(posedge clk); +	@(posedge clk); +	src_rdy_i <= 1; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h05000600}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h07000800}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h09000a00}; +  	@(posedge clk); +	data_i <= { 2'b00,1'b1,1'b0,32'h0b000c00}; +	@(posedge clk); +	src_rdy_i <= 0; +	@(posedge clk); + +	while(~dst_rdy_o) +	  @(posedge clk); + +	$display("No StreamID, No Trailer, Odd"); +	src_rdy_i <= 1; +  	data_i <= { 2'b00,1'b0,1'b1,32'h0000FFFF}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h11001200}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h13001400}; +	src_rdy_i <= 0; +	@(posedge clk); +	src_rdy_i <= 1; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h15001600}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h17001800}; +	@(posedge clk); +	data_i <= { 2'b00,1'b1,1'b0,32'h19001a00}; +	@(posedge clk); +	src_rdy_i <= 0; +	@(posedge clk); + +	while(~dst_rdy_o) +	  @(posedge clk); + +	$display("No StreamID, Trailer, Even"); +	src_rdy_i <= 1; +  	data_i <= { 2'b00,1'b0,1'b1,32'h0400FFFF}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h21002200}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h23002400}; +	src_rdy_i <= 0; +	@(posedge clk); +	src_rdy_i <= 1; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h25002600}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h27002800}; +	@(posedge clk); +	data_i <= { 2'b00,1'b1,1'b0,32'h29002a00}; +	@(posedge clk); +	src_rdy_i <= 0; +	@(posedge clk); + +	while(~dst_rdy_o) +	  @(posedge clk); + +	$display("No StreamID, Trailer, Odd"); +	src_rdy_i <= 1; +  	data_i <= { 2'b00,1'b0,1'b1,32'h0400FFFF}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h31003200}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h33003400}; +	src_rdy_i <= 0; +	@(posedge clk); +	src_rdy_i <= 1; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h35003600}; +	@(posedge clk); +	data_i <= { 2'b00,1'b1,1'b0,32'h39003a00}; +	@(posedge clk); +	src_rdy_i <= 0; +	@(posedge clk); + +	while(~dst_rdy_o) +	  @(posedge clk); + +	$display("StreamID, No Trailer, Even"); +	src_rdy_i <= 1; +  	data_i <= { 2'b00,1'b0,1'b1,32'h1000FFFF}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h11001200}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h13001400}; +	src_rdy_i <= 0; +	@(posedge clk); +	src_rdy_i <= 1; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h15001600}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'h17001800}; +	@(posedge clk); +	data_i <= { 2'b00,1'b1,1'b0,32'h19001a00}; +	@(posedge clk); +	src_rdy_i <= 0; +	@(posedge clk); + +	while(~dst_rdy_o) +	  @(posedge clk); + +	$display("StreamID, Trailer, Odd"); +	src_rdy_i <= 1; +  	data_i <= { 2'b00,1'b0,1'b1,32'h1400FFFF}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'ha100a200}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'ha300a400}; +	src_rdy_i <= 0; +	@(posedge clk); +	src_rdy_i <= 1; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'ha500a600}; +	@(posedge clk); +	data_i <= { 2'b00,1'b0,1'b0,32'ha700a800}; +	@(posedge clk); +	data_i <= { 2'b00,1'b1,1'b0,32'hbbb0bbb0}; +	@(posedge clk); +	src_rdy_i <= 0; +	@(posedge clk); + +     end +    +   initial #28000 $finish; +endmodule // double_buffer_tb diff --git a/fpga/usrp2/control_lib/gpio_atr.v b/fpga/usrp2/control_lib/gpio_atr.v new file mode 100644 index 000000000..82d72b815 --- /dev/null +++ b/fpga/usrp2/control_lib/gpio_atr.v @@ -0,0 +1,71 @@ + +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + + +module gpio_atr +  #(parameter BASE = 0, +    parameter WIDTH = 32) +   (input clk, input reset, +    input set_stb, input [7:0] set_addr, input [31:0] set_data, +    input rx, input tx, +    inout [WIDTH-1:0] gpio, +    output reg [31:0] gpio_readback +    ); +    +   wire [WIDTH-1:0]   ddr, in_idle, in_tx, in_rx, in_fdx; +   reg [WIDTH-1:0]    rgpio, igpio; +    +   setting_reg #(.my_addr(BASE+0), .width(WIDTH)) reg_idle +     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), +      .out(in_idle),.changed()); + +   setting_reg #(.my_addr(BASE+1), .width(WIDTH)) reg_rx +     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), +      .out(in_rx),.changed()); + +   setting_reg #(.my_addr(BASE+2), .width(WIDTH)) reg_tx +     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), +      .out(in_tx),.changed()); + +   setting_reg #(.my_addr(BASE+3), .width(WIDTH)) reg_fdx +     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), +      .out(in_fdx),.changed()); + +   setting_reg #(.my_addr(BASE+4), .width(WIDTH)) reg_ddr +     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), +      .out(ddr),.changed()); + +   always @(posedge clk) +     case({tx,rx}) +       2'b00: rgpio <= in_idle; +       2'b01: rgpio <= in_rx; +       2'b10: rgpio <= in_tx; +       2'b11: rgpio <= in_fdx; +     endcase // case ({tx,rx}) +    +   integer 	      n; +   always @* +     for(n=0;n<WIDTH;n=n+1) +       igpio[n] <= ddr[n] ? rgpio[n] : 1'bz; + +   assign     gpio = igpio; + +   always @(posedge clk) +     gpio_readback <= gpio; +    +endmodule // gpio_atr  | 
