uart: new design using FHDL and bank (TX only, incomplete)
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Sat, 17 Dec 2011 23:29:37 +0000 (00:29 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Sat, 17 Dec 2011 23:29:37 +0000 (00:29 +0100)
build.py
milkymist/uart/__init__.py
top.py
verilog/uart/uart.v [deleted file]
verilog/uart/uart_transceiver.v [deleted file]

index 5e1f007b281ebfeb0adc0d86978304244d557466..e751a040953998b49d7417894da564dcdc74045d 100644 (file)
--- a/build.py
+++ b/build.py
@@ -17,7 +17,6 @@ add_core_files("lm32", ["lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v
        "lm32_interrupt.v", "lm32_ram.v", "lm32_dp_ram.v", "lm32_icache.v",
        "lm32_dcache.v", "lm32_top.v", "lm32_debug.v", "lm32_jtag.v", "jtag_cores.v",
        "jtag_tap_spartan6.v"])
-add_core_dir("uart")
 
 os.system("rm -rf build/*")
 os.chdir("build")
index b4c7185c3835ab5c714e6880a00acf56998620f7..608f3639d90803794c403005e6173a9b8098387d 100644 (file)
@@ -1,28 +1,56 @@
+from functools import partial
+
 from migen.fhdl.structure import *
-from migen.bus import csr
+from migen.bank.description import *
+from migen.bank import csrgen
 
 class Inst:
-       def __init__(self, csr_addr, clk_freq, baud=115200, break_en_default=Constant(0)):
-               self.bus = csr.Slave("uart")
-               declare_signal(self, "tx")
-               declare_signal(self, "rx")
-               declare_signal(self, "irq")
-               declare_signal(self, "brk")
-               self._inst = Instance("uart",
-                       [("csr_do", self.bus.d_o),
-                       ("uart_tx", self.tx),
-                       ("irq", self.irq),
-                       ("break", self.brk)],
-                       [("csr_a", self.bus.a_i),
-                       ("csr_we", self.bus.we_i),
-                       ("csr_di", self.bus.d_i),
-                       ("uart_rx", self.rx)],
-                       [("csr_addr", Constant(csr_addr, BV(5))),
-                       ("clk_freq", clk_freq),
-                       ("baud", baud),
-                       ("break_en_default", break_en_default)],
-                       "sys_clk",
-                       "sys_rst")
+       def __init__(self, address, clk_freq, baud=115200):
+               self._rxtx = rxtx = Register("rxtx", BV(8))
+               divisor = Register("divisor")
+               self._f_divisor = Field(divisor, "divisor", 8) # TODO: 16
+               stat = Register("stat") # TODO: autogenerated event manager
+               self._f_thre = Field(stat, "thre", access_bus=READ_ONLY, access_dev=WRITE_ONLY)
+               
+               self.bank = csrgen.Bank([rxtx, divisor, stat], address=address)
+               d = partial(declare_signal, self)
+               d("tx", reset=1)
+               d("rx")
+               
+               d("_enable16")
+               d("_enable16_counter", BV(16))
+               d("_tx_reg", BV(8))
+               d("_tx_bitcount", BV(4))
+               d("_tx_count16", BV(4))
+               d("_tx_busy")
+               self.divisor = int(clk_freq/baud/16); # TODO
        
        def get_fragment(self):
-               return Fragment(instances=[self._inst], pads={self.tx, self.rx})
+               comb = [self._enable16.eq(self._enable16_counter == Constant(0, BV(16)))]
+               sync = [self._enable16_counter.eq(self._enable16_counter - 1),
+                       If(self._enable16, self._enable16_counter.eq(self.divisor - 1))] # TODO
+               
+               sync += [If(self._rxtx.dev_re,
+                       self._tx_reg.eq(self._rxtx.dev_r),
+                       self._tx_bitcount.eq(0),
+                       self._tx_count16.eq(1),
+                       self._tx_busy.eq(1),
+                       self.tx.eq(0)
+               ).Elif(self._enable16 & self._tx_busy,
+                       self._tx_count16.eq(self._tx_count16 + 1),
+                       If(self._tx_count16 == Constant(0, BV(4)),
+                               self._tx_bitcount.eq(self._tx_bitcount + 1),
+                               If(self._tx_bitcount == 8,
+                                       self.tx.eq(1)
+                               ).Elif(self._tx_bitcount == 9,
+                                       self.tx.eq(1),
+                                       self._tx_busy.eq(0)
+                               ).Else(
+                                       self.tx.eq(self._tx_reg[0]),
+                                       self._tx_reg.eq(Cat(self._tx_reg[1:], 0))
+                               )
+                       )
+               )]
+               
+               comb += [self._f_thre.dev_we.eq(1), self._f_thre.dev_w.eq(~self._tx_busy)]
+               return self.bank.get_fragment() + Fragment(comb, sync, pads={self.tx, self.rx})
diff --git a/top.py b/top.py
index d4ea784fa91a2e218dc4690ce7652a87573c8d1f..c94e67fbbdd8387b65e73452ec786ce0c3f46e88 100644 (file)
--- a/top.py
+++ b/top.py
@@ -21,7 +21,7 @@ def get():
                register=True,
                offset=1)
        uart0 = uart.Inst(0, clk_freq, baud=115200)
-       csrcon0 = csr.Interconnect(wishbone2csr0.csr, [uart0.bus])
+       csrcon0 = csr.Interconnect(wishbone2csr0.csr, [uart0.bank.interface])
        
        frag = autofragment.from_local()
        vns = convtools.Namespace()
diff --git a/verilog/uart/uart.v b/verilog/uart/uart.v
deleted file mode 100644 (file)
index 1d8d67e..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Milkymist SoC
- * Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
- *
- * 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, version 3 of the License.
- *
- * 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 uart #(
-       parameter csr_addr = 5'h0,
-       parameter clk_freq = 100000000,
-       parameter baud = 115200,
-       parameter break_en_default = 1'b0
-) (
-       input sys_clk,
-       input sys_rst,
-       
-       input [13:0] csr_a,
-       input csr_we,
-       input [7:0] csr_di,
-       output reg [7:0] csr_do,
-
-       output irq,
-
-       input uart_rx,
-       output uart_tx,
-
-       output break
-);
-
-reg [15:0] divisor;
-wire [7:0] rx_data;
-wire [7:0] tx_data;
-wire tx_wr;
-
-wire uart_tx_transceiver;
-
-uart_transceiver transceiver(
-       .sys_clk(sys_clk),
-       .sys_rst(sys_rst),
-
-       .uart_rx(uart_rx),
-       .uart_tx(uart_tx_transceiver),
-
-       .divisor(divisor),
-
-       .rx_data(rx_data),
-       .rx_done(rx_done),
-
-       .tx_data(tx_data),
-       .tx_wr(tx_wr),
-       .tx_done(tx_done),
-
-       .break(break_transceiver)
-);
-
-assign uart_tx = thru_en ? uart_rx : uart_tx_transceiver;
-assign break = break_en & break_transceiver;
-
-/* CSR interface */
-wire csr_selected = csr_a[13:9] == csr_addr;
-
-assign irq = (tx_event & tx_irq_en) | (rx_event & rx_irq_en);
-
-assign tx_data = csr_di;
-assign tx_wr = csr_selected & csr_we & (csr_a[2:0] == 3'b000);
-
-parameter default_divisor = clk_freq/baud/16;
-
-reg thru_en;
-reg break_en;
-reg tx_irq_en;
-reg rx_irq_en;
-reg rx_event;
-reg tx_event;
-reg thre;
-
-always @(posedge sys_clk) begin
-       if(sys_rst) begin
-               divisor <= default_divisor;
-               csr_do <= 32'd0;
-               thru_en <= 1'b0;
-               break_en <= break_en_default;
-               rx_irq_en <= 1'b0;
-               tx_irq_en <= 1'b0;
-               tx_event <= 1'b0;
-               rx_event <= 1'b0;
-               thre <= 1'b1;
-       end else begin
-               csr_do <= 32'd0;
-               if(break)
-                       break_en <= 1'b0;
-               if(tx_done) begin
-                       tx_event <= 1'b1;
-                       thre <= 1'b1;
-               end
-               if(tx_wr)
-                       thre <= 1'b0;
-               if(rx_done) begin
-                       rx_event <= 1'b1;
-               end
-               if(csr_selected) begin
-                       case(csr_a[2:0])
-                               3'b000: csr_do <= rx_data;
-// TODO                                3'b001: csr_do <= divisor;
-                               3'b010: csr_do <= {tx_event, rx_event, thre};
-                               3'b011: csr_do <= {thru_en, tx_irq_en, rx_irq_en};
-                               3'b100: csr_do <= {break_en};
-                       endcase
-                       if(csr_we) begin
-                               case(csr_a[2:0])
-                                       3'b000:; /* handled by transceiver */
-// TODO                                        3'b001: divisor <= csr_di[15:0];
-                                       3'b010: begin
-                                               /* write one to clear */
-                                               if(csr_di[1])
-                                                       rx_event <= 1'b0;
-                                               if(csr_di[2])
-                                                       tx_event <= 1'b0;
-                                       end
-                                       3'b011: begin
-                                               rx_irq_en <= csr_di[0];
-                                               tx_irq_en <= csr_di[1];
-                                               thru_en <= csr_di[2];
-                                       end
-                                       3'b100: break_en <= csr_di[0];
-                               endcase
-                       end
-               end
-       end
-end
-
-endmodule
diff --git a/verilog/uart/uart_transceiver.v b/verilog/uart/uart_transceiver.v
deleted file mode 100644 (file)
index 80bd93b..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Milkymist SoC
- * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
- * Copyright (C) 2007 Das Labor
- *
- * 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, version 3 of the License.
- *
- * 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 uart_transceiver(
-       input sys_rst,
-       input sys_clk,
-
-       input uart_rx,
-       output reg uart_tx,
-
-       input [15:0] divisor,
-
-       output reg [7:0] rx_data,
-       output reg rx_done,
-
-       input [7:0] tx_data,
-       input tx_wr,
-       output reg tx_done,
-
-       output reg break
-);
-
-//-----------------------------------------------------------------
-// enable16 generator
-//-----------------------------------------------------------------
-reg [15:0] enable16_counter;
-
-wire enable16;
-assign enable16 = (enable16_counter == 16'd0);
-
-always @(posedge sys_clk) begin
-       if(sys_rst)
-               enable16_counter <= divisor - 16'b1;
-       else begin
-               enable16_counter <= enable16_counter - 16'd1;
-               if(enable16)
-                       enable16_counter <= divisor - 16'b1;
-       end
-end
-
-//-----------------------------------------------------------------
-// Synchronize uart_rx
-//-----------------------------------------------------------------
-reg uart_rx1;
-reg uart_rx2;
-
-always @(posedge sys_clk) begin
-       uart_rx1 <= uart_rx;
-       uart_rx2 <= uart_rx1;
-end
-
-//-----------------------------------------------------------------
-// UART RX Logic
-//-----------------------------------------------------------------
-reg rx_busy;
-reg uart_rx_r;
-reg [3:0] rx_count16;
-reg [3:0] rx_bitcount;
-reg [7:0] rx_reg;
-
-always @(posedge sys_clk) begin
-       if(sys_rst) begin
-               rx_done <= 1'b0;
-               rx_busy <= 1'b0;
-               rx_count16  <= 4'd0;
-               rx_bitcount <= 4'd0;
-               break <= 1'b0;
-               uart_rx_r <= 1'b0;
-       end else begin
-               rx_done <= 1'b0;
-               break <= 1'b0;
-
-               if(enable16) begin
-                       uart_rx_r <= uart_rx2;
-                       if(~rx_busy) begin // look for start bit
-                               if(~uart_rx2 & uart_rx_r) begin // start bit found
-                                       rx_busy <= 1'b1;
-                                       rx_count16 <= 4'd7;
-                                       rx_bitcount <= 4'd0;
-                               end
-                       end else begin
-                               rx_count16 <= rx_count16 + 4'd1;
-
-                               if(rx_count16 == 4'd0) begin // sample
-                                       rx_bitcount <= rx_bitcount + 4'd1;
-
-                                       if(rx_bitcount == 4'd0) begin // verify startbit
-                                               if(uart_rx2)
-                                                       rx_busy <= 1'b0;
-                                       end else if(rx_bitcount == 4'd9) begin
-                                               rx_busy <= 1'b0;
-                                               if(uart_rx2) begin // stop bit ok
-                                                       rx_data <= rx_reg;
-                                                       rx_done <= 1'b1;
-                                               end else if(rx_reg == 8'h00) // break condition
-                                                       break <= 1'b1;
-                                       end else
-                                               rx_reg <= {uart_rx2, rx_reg[7:1]};
-                               end
-                       end
-               end
-       end
-end
-
-//-----------------------------------------------------------------
-// UART TX Logic
-//-----------------------------------------------------------------
-reg tx_busy;
-reg [3:0] tx_bitcount;
-reg [3:0] tx_count16;
-reg [7:0] tx_reg;
-
-always @(posedge sys_clk) begin
-       if(sys_rst) begin
-               tx_done <= 1'b0;
-               tx_busy <= 1'b0;
-               uart_tx <= 1'b1;
-       end else begin
-               tx_done <= 1'b0;
-               if(tx_wr) begin
-                       tx_reg <= tx_data;
-                       tx_bitcount <= 4'd0;
-                       tx_count16 <= 4'd1;
-                       tx_busy <= 1'b1;
-                       uart_tx <= 1'b0;
-`ifdef SIMULATION
-                       $display("UART: %c", tx_data);
-`endif
-               end else if(enable16 && tx_busy) begin
-                       tx_count16  <= tx_count16 + 4'd1;
-
-                       if(tx_count16 == 4'd0) begin
-                               tx_bitcount <= tx_bitcount + 4'd1;
-                               
-                               if(tx_bitcount == 4'd8) begin
-                                       uart_tx <= 1'b1;
-                               end else if(tx_bitcount == 4'd9) begin
-                                       uart_tx <= 1'b1;
-                                       tx_busy <= 1'b0;
-                                       tx_done <= 1'b1;
-                               end else begin
-                                       uart_tx <= tx_reg[0];
-                                       tx_reg <= {1'b0, tx_reg[7:1]};
-                               end
-                       end
-               end
-       end
-end
-
-endmodule