uart: new design using FHDL and bank (TX only, incomplete)
This commit is contained in:
parent
bb21f7584a
commit
6664af73d1
1
build.py
1
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")
|
||||
|
|
|
@ -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})
|
||||
|
|
2
top.py
2
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()
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue