From: Sebastien Bourdeauducq Date: Sat, 17 Dec 2011 23:29:37 +0000 (+0100) Subject: uart: new design using FHDL and bank (TX only, incomplete) X-Git-Tag: 24jan2021_ls180~3278 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6664af73d11166b97be77470e9ff76d57dd90452;p=litex.git uart: new design using FHDL and bank (TX only, incomplete) --- diff --git a/build.py b/build.py index 5e1f007b..e751a040 100644 --- 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") diff --git a/milkymist/uart/__init__.py b/milkymist/uart/__init__.py index b4c7185c..608f3639 100644 --- a/milkymist/uart/__init__.py +++ b/milkymist/uart/__init__.py @@ -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 d4ea784f..c94e67fb 100644 --- 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 index 1d8d67e3..00000000 --- a/verilog/uart/uart.v +++ /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 . - */ - -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 index 80bd93bf..00000000 --- a/verilog/uart/uart_transceiver.v +++ /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 . - */ - -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