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_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",
|
"lm32_dcache.v", "lm32_top.v", "lm32_debug.v", "lm32_jtag.v", "jtag_cores.v",
|
||||||
"jtag_tap_spartan6.v"])
|
"jtag_tap_spartan6.v"])
|
||||||
add_core_dir("uart")
|
|
||||||
|
|
||||||
os.system("rm -rf build/*")
|
os.system("rm -rf build/*")
|
||||||
os.chdir("build")
|
os.chdir("build")
|
||||||
|
|
|
@ -1,28 +1,56 @@
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from migen.fhdl.structure import *
|
from migen.fhdl.structure import *
|
||||||
from migen.bus import csr
|
from migen.bank.description import *
|
||||||
|
from migen.bank import csrgen
|
||||||
|
|
||||||
class Inst:
|
class Inst:
|
||||||
def __init__(self, csr_addr, clk_freq, baud=115200, break_en_default=Constant(0)):
|
def __init__(self, address, clk_freq, baud=115200):
|
||||||
self.bus = csr.Slave("uart")
|
self._rxtx = rxtx = Register("rxtx", BV(8))
|
||||||
declare_signal(self, "tx")
|
divisor = Register("divisor")
|
||||||
declare_signal(self, "rx")
|
self._f_divisor = Field(divisor, "divisor", 8) # TODO: 16
|
||||||
declare_signal(self, "irq")
|
stat = Register("stat") # TODO: autogenerated event manager
|
||||||
declare_signal(self, "brk")
|
self._f_thre = Field(stat, "thre", access_bus=READ_ONLY, access_dev=WRITE_ONLY)
|
||||||
self._inst = Instance("uart",
|
|
||||||
[("csr_do", self.bus.d_o),
|
self.bank = csrgen.Bank([rxtx, divisor, stat], address=address)
|
||||||
("uart_tx", self.tx),
|
d = partial(declare_signal, self)
|
||||||
("irq", self.irq),
|
d("tx", reset=1)
|
||||||
("break", self.brk)],
|
d("rx")
|
||||||
[("csr_a", self.bus.a_i),
|
|
||||||
("csr_we", self.bus.we_i),
|
d("_enable16")
|
||||||
("csr_di", self.bus.d_i),
|
d("_enable16_counter", BV(16))
|
||||||
("uart_rx", self.rx)],
|
d("_tx_reg", BV(8))
|
||||||
[("csr_addr", Constant(csr_addr, BV(5))),
|
d("_tx_bitcount", BV(4))
|
||||||
("clk_freq", clk_freq),
|
d("_tx_count16", BV(4))
|
||||||
("baud", baud),
|
d("_tx_busy")
|
||||||
("break_en_default", break_en_default)],
|
self.divisor = int(clk_freq/baud/16); # TODO
|
||||||
"sys_clk",
|
|
||||||
"sys_rst")
|
|
||||||
|
|
||||||
def get_fragment(self):
|
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,
|
register=True,
|
||||||
offset=1)
|
offset=1)
|
||||||
uart0 = uart.Inst(0, clk_freq, baud=115200)
|
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()
|
frag = autofragment.from_local()
|
||||||
vns = convtools.Namespace()
|
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