Edge sensitive IRQ on UART
authorlekernel <sebastien.bourdeauducq@lekernel.net>
Fri, 13 Nov 2009 16:36:19 +0000 (17:36 +0100)
committerlekernel <sebastien.bourdeauducq@lekernel.net>
Fri, 13 Nov 2009 16:36:19 +0000 (17:36 +0100)
cores/sysctl/rtl/sysctl.v
cores/uart/rtl/uart.v
cores/uart/rtl/uart_transceiver.v
software/include/hw/uart.h
software/libbase/Makefile
software/libbase/uart-async.c
software/libbase/uart.c

index 5690287..1736e43 100644 (file)
@@ -77,9 +77,6 @@ reg [31:0] compare0, compare1;
 wire match0 = (counter0 == compare0);
 wire match1 = (counter1 == compare1);
 
-assign timer0_irq = trig0;
-assign timer1_irq = trig1;
-
 /*
  * Logic and CSR interface
  */
index 5831f05..a23898f 100644 (file)
@@ -36,15 +36,9 @@ module uart #(
 );
 
 reg [15:0] divisor;
-
 wire [7:0] rx_data;
-wire rx_avail;
-wire rx_error;
-wire rx_ack;
-
 wire [7:0] tx_data;
 wire tx_wr;
-wire tx_busy;
 
 uart_transceiver transceiver(
        .sys_clk(sys_clk),
@@ -56,40 +50,18 @@ uart_transceiver transceiver(
        .divisor(divisor),
 
        .rx_data(rx_data),
-       .rx_avail(rx_avail),
-       .rx_error(rx_error),
-       .rx_ack(rx_ack),
-       
+       .rx_done(rx_irq),
+
        .tx_data(tx_data),
        .tx_wr(tx_wr),
-       .tx_busy(tx_busy)
+       .tx_done(tx_irq)
 );
 
-/* Generate tx_done signal */
-wire tx_ack;
-reg tx_busy_r;
-reg tx_done;
-
-always @(posedge sys_clk) begin
-       if(sys_rst) begin
-               tx_busy_r <= 1'b0;
-               tx_done <= 1'b0;
-       end else begin
-               tx_busy_r <= tx_busy;
-               if(tx_ack|tx_wr)
-                       tx_done <= 1'b0;
-               if(tx_busy_r & ~tx_busy)
-                       tx_done <= 1'b1;
-       end
-end
-
 /* CSR interface */
 wire csr_selected = csr_a[13:10] == csr_addr;
 
-assign rx_ack = csr_selected & csr_we & (csr_a[1:0] == 2'b00) & csr_di[2];
 assign tx_data = csr_di[7:0];
-assign tx_wr = csr_selected & csr_we & (csr_a[1:0] == 2'b01);
-assign tx_ack = csr_selected & csr_we & (csr_a[1:0] == 2'b00) & csr_di[5];
+assign tx_wr = csr_selected & csr_we & (csr_a[0] == 1'b0);
 
 parameter default_divisor = clk_freq/baud/16;
 
@@ -100,21 +72,16 @@ always @(posedge sys_clk) begin
        end else begin
                csr_do <= 32'd0;
                if(csr_selected) begin
-                       case(csr_a[1:0])
-                               2'b00: csr_do <= {1'b0, tx_done, tx_busy, 1'b0, rx_error, rx_avail};
-                               2'b01: csr_do <= rx_data;
-                               2'b10: csr_do <= divisor;
+                       case(csr_a[0])
+                               1'b0: csr_do <= rx_data;
+                               1'b1: csr_do <= divisor;
                        endcase
                        if(csr_we) begin
-                               if(csr_a[1:0] == 2'b10)
+                               if(csr_a[0] == 1'b1)
                                        divisor <= csr_di[15:0];
                        end
                end
        end
 end
 
-/* IRQs */
-assign rx_irq = rx_avail|rx_error;
-assign tx_irq = tx_done;
-
 endmodule
index 1f6fda0..31cf1f1 100644 (file)
@@ -26,12 +26,11 @@ module uart_transceiver(
        input [15:0] divisor,
 
        output reg [7:0] rx_data,
-       output reg rx_avail,
-       output reg rx_error,
-       input rx_ack,
+       output reg rx_done,
+
        input [7:0] tx_data,
        input tx_wr,
-       output reg tx_busy
+       output reg tx_done
 );
 
 //-----------------------------------------------------------------
@@ -39,8 +38,8 @@ module uart_transceiver(
 //-----------------------------------------------------------------
 reg [15:0] enable16_counter;
 
-wire    enable16;
-assign  enable16 = (enable16_counter == 16'd0);
+wire enable16;
+assign enable16 = (enable16_counter == 16'd0);
 
 always @(posedge sys_clk) begin
        if(sys_rst)
@@ -66,29 +65,25 @@ end
 //-----------------------------------------------------------------
 // UART RX Logic
 //-----------------------------------------------------------------
-reg       rx_busy;
+reg rx_busy;
 reg [3:0] rx_count16;
 reg [3:0] rx_bitcount;
 reg [7:0] rxd_reg;
 
 always @(posedge sys_clk) begin
        if(sys_rst) begin
-               rx_busy     <= 1'd0;
+               rx_done <= 1'b0;
+               rx_busy <= 1'b0;
                rx_count16  <= 4'd0;
                rx_bitcount <= 4'd0;
-               rx_avail    <= 1'd0;
-               rx_error    <= 1'd0;
        end else begin
-               if(rx_ack) begin
-                       rx_avail <= 1'd0;
-                       rx_error <= 1'd0;
-               end
+               rx_done <= 1'b0;
 
                if(enable16) begin
-                       if(!rx_busy) begin // look for start bit
-                               if(!uart_rxd2) begin // start bit found
-                                       rx_busy     <= 1'd1;
-                                       rx_count16  <= 4'd7;
+                       if(~rx_busy) begin // look for start bit
+                               if(~uart_rxd2) begin // start bit found
+                                       rx_busy <= 1'b1;
+                                       rx_count16 <= 4'd7;
                                        rx_bitcount <= 4'd0;
                                end
                        end else begin
@@ -99,21 +94,17 @@ always @(posedge sys_clk) begin
 
                                        if(rx_bitcount == 4'd0) begin // verify startbit
                                                if(uart_rxd2)
-                                                       rx_busy <= 1'd0;
-                                       end else if(rx_bitcount == 4'd9) begin // look for stop bit
-                                               rx_busy <= 1'd0;
+                                                       rx_busy <= 1'b0;
+                                       end else if(rx_bitcount == 4'd9) begin
+                                               rx_busy <= 1'b0;
                                                if(uart_rxd2) begin // stop bit ok
-                                                       rx_data  <= rxd_reg;
-                                                       rx_avail <= 4'd1;
-                                                       rx_error <= 1'd0;
-                                               end else begin // bad stop bit
-                                                       rx_error <= 1'd1;
-                                               end
-                                       end else begin
+                                                       rx_data <= rxd_reg;
+                                                       rx_done <= 1'b1;
+                                               end // ignore RX error
+                                       end else
                                                rxd_reg <= {uart_rxd2, rxd_reg[7:1]};
-                                       end
                                end
-                       end 
+                       end
                end
        end
 end
@@ -121,21 +112,23 @@ end
 //-----------------------------------------------------------------
 // UART TX Logic
 //-----------------------------------------------------------------
+reg tx_busy;
 reg [3:0] tx_bitcount;
 reg [3:0] tx_count16;
 reg [7:0] txd_reg;
 
 always @(posedge sys_clk) begin
        if(sys_rst) begin
-               tx_busy     <= 1'd0;
-               uart_txd    <= 1'd1;
+               tx_done <= 1'b0;
+               tx_busy <= 1'b0;
+               uart_txd <= 1'b1;
        end else begin
-               if(tx_wr && !tx_busy) begin
-                       txd_reg     <= tx_data;
+               if(tx_wr) begin
+                       txd_reg <= tx_data;
                        tx_bitcount <= 4'd0;
-                       tx_count16  <= 4'd1;
-                       tx_busy     <= 1'd1;
-                       uart_txd    <= 1'd0;
+                       tx_count16 <= 4'd1;
+                       tx_busy <= 1'b1;
+                       uart_txd <= 1'b0;
 `ifdef SIMULATION
                        $display("UART: %c", tx_data);
 `endif
index 0fe57bd..e4cef8e 100644 (file)
 
 #include <hw/common.h>
 
-#define CSR_UART_UCR           MMPTR(0x80000000)
-#define CSR_UART_RXTX          MMPTR(0x80000004)
-#define CSR_UART_DIVISOR       MMPTR(0x80000008)
-
-#define UART_RXAVAIL           (0x01)
-#define UART_RXERROR           (0x02)
-#define UART_RXACK             (0x04)
-
-#define UART_TXBUSY            (0x08)
-#define UART_TXDONE            (0x10)
-#define UART_TXACK             (0x20)
+#define CSR_UART_RXTX          MMPTR(0x80000000)
+#define CSR_UART_DIVISOR       MMPTR(0x80000004)
 
 #endif /* __HW_UART_H */
index 46ab941..12e5968 100644 (file)
@@ -1,8 +1,8 @@
 MMDIR=../..
 include $(MMDIR)/software/include.mak
 
-OBJECTS_ALL=divsi3.o libc.o crc16.o crc32.o console.o cfcard.o cffat.o system.o board.o
-OBJECTS=$(OBJECTS_ALL) irq.o softfloat.o softfloat-glue.o vsnprintf.o atof.o malloc.o uart-async.o
+OBJECTS_ALL=divsi3.o libc.o crc16.o crc32.o console.o cfcard.o cffat.o system.o board.o irq.o
+OBJECTS=$(OBJECTS_ALL) softfloat.o softfloat-glue.o vsnprintf.o atof.o malloc.o uart-async.o
 OBJECTS_LIGHT=$(OBJECTS_ALL) vsnprintf-nofloat.o uart.o
 
 all: libbase-light.a libbase.a
index ca258c2..578d631 100644 (file)
@@ -1,16 +1,16 @@
 /*
  * Milkymist VJ SoC (Software)
  * Copyright (C) 2007, 2008, 2009 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/>.
  */
@@ -36,13 +36,8 @@ static volatile unsigned int rx_consume;
 
 void uart_async_isr_rx()
 {
-       if(CSR_UART_UCR & UART_RXAVAIL) {
-               rx_buf[rx_produce] = CSR_UART_RXTX;
-               CSR_UART_UCR = UART_RXACK;
-               rx_produce = (rx_produce + 1) & UART_RINGBUFFER_MASK_RX;
-       }
-       if(CSR_UART_UCR & UART_RXERROR)
-               CSR_UART_UCR = UART_RXACK;
+       rx_buf[rx_produce] = CSR_UART_RXTX;
+       rx_produce = (rx_produce + 1) & UART_RINGBUFFER_MASK_RX;
 }
 
 char readchar()
@@ -72,7 +67,6 @@ static int force_sync;
 
 void uart_async_isr_tx()
 {
-       CSR_UART_UCR = UART_TXACK;
        if(tx_produce != tx_consume) {
                CSR_UART_RXTX = tx_buf[tx_consume];
                tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX;
@@ -89,8 +83,8 @@ void writechar(char c)
        irq_setmask(oldmask & (~IRQ_UARTTX));
        if(force_sync) {
                CSR_UART_RXTX = c;
-               while(CSR_UART_UCR & UART_TXBUSY);
-               CSR_UART_UCR = UART_TXACK;
+               while(!(irq_pending() & IRQ_UARTTX));
+               irq_ack(IRQ_UARTTX);
        } else {
                if(tx_cts) {
                        tx_cts = 0;
@@ -112,7 +106,9 @@ void uart_async_init()
        tx_produce = 0;
        tx_consume = 0;
        tx_cts = 1;
-       
+
+       irq_ack(IRQ_UARTRX|IRQ_UARTTX);
+
        mask = irq_getmask();
        mask |= IRQ_UARTRX|IRQ_UARTTX;
        irq_setmask(mask);
index 62a9b3e..a0ba15c 100644 (file)
@@ -1,42 +1,45 @@
 /*
  * Milkymist VJ SoC (Software)
  * Copyright (C) 2007, 2008, 2009 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/>.
  */
 
 #include <hw/uart.h>
+#include <hw/interrupts.h>
 #include <uart.h>
+#include <irq.h>
 
 void writechar(char c)
 {
-       while(CSR_UART_UCR & UART_TXBUSY);
        CSR_UART_RXTX = c;
+       while(!(irq_pending() & IRQ_UARTTX));
+       irq_ack(IRQ_UARTTX);
 }
 
 char readchar()
 {
        char c;
 
-       while(!(CSR_UART_UCR & UART_RXAVAIL));
+       while(!(irq_pending() & IRQ_UARTRX));
+       irq_ack(IRQ_UARTRX);
        c = CSR_UART_RXTX;
-       CSR_UART_UCR = UART_RXACK;
        return c;
 }
 
 int readchar_nonblock()
 {
-       if(CSR_UART_UCR & UART_RXAVAIL)
+       if(irq_pending() & IRQ_UARTRX)
                return 1;
        else
                return 0;