diff --git a/cMIPS/include/handlers.s b/cMIPS/include/handlers.s index f6e4f310f09b3dfd1ffcf1b9f06ec18422b03a86..d62806d0b1d7c0bdcfcb3a99549753996824ce60 100644 --- a/cMIPS/include/handlers.s +++ b/cMIPS/include/handlers.s @@ -96,8 +96,9 @@ _uart_buff: .space 16*4 # up to 16 registers to be saved here .set UART_tx_irq,0x10 .equ UCTRL,0 # UART registers - .equ USTAT,0 - .equ UDATA,4 + .equ USTAT,4 + .equ UINTER,8 + .equ UDATA,12 .text .set noreorder @@ -127,10 +128,13 @@ UARTinterr: lui $a0, %hi(HW_uart_addr)# get device's address ori $a0, $a0, %lo(HW_uart_addr) - lw $k1, USTAT($a0) # Read status, remove interrupt request + lw $k1, USTAT($a0) # Read status sw $k1, 0*4($k0) # and save UART status to memory - andi $a1, $k1, UART_rx_irq # Is this reception? + li $a1, UART_rx_irq # remove interrupt request + sw $a1, UINTER($a0) + + and $a1, $k1, $a1 # Is this reception? beq $a1, $zero, UARTret # no, ignore it and return nop diff --git a/cMIPS/vhdl/io.vhd b/cMIPS/vhdl/io.vhd index b2c4683e9da9e0820cf2f3c3192424a862d76352..c1c447d4e50c216b782b1d7d62e804151eefe14d 100644 --- a/cMIPS/vhdl/io.vhd +++ b/cMIPS/vhdl/io.vhd @@ -371,7 +371,7 @@ entity simple_uart is clk : in std_logic; -- processor clock sel : in std_logic; wr : in std_logic; - addr : in std_logic; + addr : in std_logic_vector(1 downto 0); data_inp : in std_logic_vector; data_out : out std_logic_vector; txdat : out std_logic; -- serial transmission (output) @@ -386,7 +386,7 @@ architecture behavioral of simple_uart is component uart_int is port(clk, rst: in std_logic; - s_ctrl, s_stat, s_tx, s_rx: in std_logic; -- select 4 registers + s_ctrl, s_stat, s_tx, s_rx, s_int: in std_logic; -- select registers d_inp: in std_logic_vector; -- 32 bit input d_out: out std_logic_vector; -- 32 bit output txdat: out std_logic; -- serial transmission (output) @@ -397,25 +397,28 @@ architecture behavioral of simple_uart is bit_rt: out std_logic_vector); -- communication speed - for TB only end component uart_int; - signal s_ctrl, s_stat, s_tx, s_rx: std_logic; + signal s_ctrl, s_stat, s_tx, s_rx, s_int: std_logic; signal d_inp, d_out : reg32; begin - U_UART: uart_int port map (clk, rst, s_ctrl,s_stat, s_tx,s_rx, + U_UART: uart_int port map (clk, rst, s_ctrl,s_stat, s_tx,s_rx, s_int, d_inp,d_out, txdat,rxdat, rts,cts, irq, bit_rt); - -- a2 wr register (aligned to word addresses) - -- 0 0 control - -- 0 1 status - -- 1 0 transmission - -- 1 1 reception - s_ctrl <= '1' when sel = '0' and addr = '0' and wr = '0' else '0'; - s_stat <= '1' when sel = '0' and addr = '0' and wr = '1' else '0'; - s_tx <= '1' when sel = '0' and addr = '1' and wr = '0' else '0'; - s_rx <= '1' when sel = '0' and addr = '1' and wr = '1' else '0'; + -- a3a2 wr register (aligned to word addresses) + -- 00 0 control, R+W IO_UART_ADDR +0 + -- 01 1 status, R-O IO_UART_ADDR +4 + -- 10 0 interrupt conmtrol W-O IO_UART_ADDR +8 + -- 11 0 transmission W IO_UART_ADDR +12 + -- 11 1 reception R IO_UART_ADDR +12 - data_out <= d_out ; + s_ctrl <= '1' when sel = '0' and addr = b"00" and wr = '0' else '0'; -- R+W + s_stat <= '1' when sel = '0' and addr = b"01" and wr = '1' else '0'; -- R-O + s_int <= '1' when sel = '0' and addr = b"10" and wr = '0' else '0'; -- W-O + s_tx <= '1' when sel = '0' and addr = b"11" and wr = '0' else '0'; -- W+R + s_rx <= '1' when sel = '0' and addr = b"11" and wr = '1' else '0'; + + data_out <= d_out; d_inp <= data_inp; diff --git a/cMIPS/vhdl/tb_cMIPS.vhd b/cMIPS/vhdl/tb_cMIPS.vhd index 2d2bb5a9a5a75f46b0e14f821e01cfca595d1fc2..a55b1f836699ac96a2e2500cc227037a3898c7b5 100644 --- a/cMIPS/vhdl/tb_cMIPS.vhd +++ b/cMIPS/vhdl/tb_cMIPS.vhd @@ -152,7 +152,7 @@ architecture TB of tb_cMIPS is clk : in std_logic; sel : in std_logic; wr : in std_logic; - addr : in std_logic; + addr : in std_logic_vector; data_inp : in std_logic_vector; data_out : out std_logic_vector; txdat : out std_logic; @@ -646,7 +646,8 @@ begin -- TB lcd_data, lcd_rs, lcd_rw, lcd_en, lcd_blon); U_simple_uart: simple_uart - port map (rst,clk, io_uart_sel, wr, d_addr(2), cpu_data, uart_d_out, + port map (rst,clk, io_uart_sel, wr, d_addr(3 downto 2), + cpu_data, uart_d_out, uart_txd, uart_rxd, uart_rts, uart_cts, uart_irq, bit_rt); -- uncoment next line for loop back, comment out previous line -- uart_txd, uart_txd, uart_rts, uart_cts, uart_irq, bit_rt); diff --git a/cMIPS/vhdl/uart.vhd b/cMIPS/vhdl/uart.vhd index 6600c42f97b596e55e25c3d0e1dd1c3b771e3091..75424daafcf8bedca835375854f5b2a499f841da 100644 --- a/cMIPS/vhdl/uart.vhd +++ b/cMIPS/vhdl/uart.vhd @@ -26,7 +26,7 @@ -- 001: 1/8 CPU clock rate -- for VHDL/C debugging only -- 010: 1/16 CPU clock rate -- for VHDL/C debugging only -- 011: 1/32 CPU clock rate -- for VHDL/C debugging only --- 100: 230.400 bits per second +-- 100: 1/64 CPU clock rate -- for VHDL/C debugging only -- 101: 115.200 bits per second -- 110: 19.200 bits per second -- 111: 9.600 bits per second @@ -45,17 +45,23 @@ -- b6: transmit buffer is empty -- b7: Clear to Send (CTS) is active -- --- when CPU reads from RXdat register, bits 0,1,3 are cleared --- when CPU reads from STATUS register, bit 4 is cleared +-- when CPU reads from RXdat register, bits 0 and 1 cleared +-- +-- interrupt clear register, least significant byte only +-- b2..b0: ignored, not used +-- b3=1: clear interrupt bit on RX buffer full +-- b4=1: clear interrupt bit on TX buffer empty +-- b5,,b7: ignored, not used -- -- RX and TX circuits are dobule-buffered +-- library ieee; use ieee.std_logic_1164.all; use work.p_WIRES.all; entity uart_int is port(clk, rst: in std_logic; - s_ctrl, s_stat, s_tx, s_rx: in std_logic; -- select registers + s_ctrl, s_stat, s_tx, s_rx, s_int : in std_logic; -- select registers d_inp: in reg32; -- input d_out: out reg32; -- output txdat: out std_logic; -- interface: serial transmission @@ -69,6 +75,13 @@ end uart_int; architecture estrutural of uart_int is constant CLOCK_DIVIDER : integer := 50; + + -- bit in ctrl registers to set/clear the RTS serial interface signal + constant RTS_B : integer := 7; + -- bit in ctrl/interrupt registers to set/clear TX interrupt request + constant IRQ_TX_B : integer := 4; + -- bit in ctrl/interrupt registers to set/clear RX interrupt request + constant IRQ_RX_B : integer := 3; component register8 is port(clk, rst, ld: in std_logic; @@ -126,20 +139,22 @@ architecture estrutural of uart_int is signal rx_ld, rx_shift, rx_next, rx_bfr_full : std_logic; signal rxdat_1to0, rxdat_new, rxdat_int, rxdat_old : std_logic; signal rxclk_fall, rxclk_rise, en_rx_clk, rx_done, rxclk : std_logic; - signal a_overrun, a_framing, reset_rxck, s_stat_dly : std_logic; + signal a_overrun, a_framing, reset_rxck : std_logic; signal sta_xmit_sto, sta_recv_sto : reg10; signal err_overrun, err_framing : std_logic; signal rx_int_set, interr_RX_full, tx_int_set, interr_TX_empty : std_logic; - signal d_int_tx_empty, d_rx_int_set, d_err_framing, d_err_overrun : std_logic; - + signal d_int_tx_empty,d_rx_int_set,d_err_framing,d_err_overrun : std_logic; + signal clear_tx_irq, clear_rx_irq : std_logic; + signal tx_baud_div, rx_baud_div : integer := 0; begin - d_out <= x"000000" & received when s_rx = '1' else - x"000000" & status; + d_out <= x"000000" & received when s_rx = '1' else + x"000000" & status when s_stat = '1' else + x"000000" & ctrl; - rts <= ctrl(7); + rts <= ctrl(RTS_B); -- for testing only: tells remote unit what is the transmission speed bit_rt <= ctrl(2 downto 0); @@ -162,10 +177,12 @@ begin U_transmit: par_ser10 port map (clk, rst, tx_ld, tx_next, sta_xmit_sto, txdat); - U_STAT_DELAY: FFDsimple port map (clk, rst, s_stat, s_stat_dly); + -- U_STAT_DELAY: FFDsimple port map (clk, rst, s_tx, s_stat_dly); + + clear_tx_irq <= '0' when s_int = '1' and d_inp(IRQ_TX_B) = '1' else '1'; - tx_int_set <= ctrl(4) and tx_ld; - d_int_tx_empty <= (interr_TX_empty or tx_int_set) and not(s_stat_dly); + tx_int_set <= ctrl(IRQ_TX_B) and tx_ld; + d_int_tx_empty <= (interr_TX_empty or tx_int_set) and clear_tx_irq; U_tx_int: FFDsimple port map (clk, rst, d_int_tx_empty, interr_TX_empty); @@ -367,9 +384,11 @@ begin d_err_overrun <= (a_overrun or err_overrun) and not(s_rx); U_overrun: FFDsimple port map (clk, rst, d_err_overrun, err_overrun); + + clear_rx_irq <= '0' when s_int = '1' and d_inp(IRQ_RX_B) = '1' else '1'; - rx_int_set <= ctrl(3) and rx_done; - d_rx_int_set <= (rx_int_set or interr_RX_full) and not(s_rx); + rx_int_set <= ctrl(IRQ_RX_B) and rx_done; + d_rx_int_set <= (rx_int_set or interr_RX_full) and clear_rx_irq; U_rx_int: FFDsimple port map (clk, rst, d_rx_int_set, interr_RX_full); @@ -569,7 +588,7 @@ begin 8/2 when b"001", 16/2 when b"010", 32/2 when b"011", - 217/2 when b"100", -- 230.400 + 64/2 when b"100", 434/2 when b"101", -- 115.200 2604/2 when b"110", -- 19.200 5208/2 when others; -- 9.600 @@ -618,7 +637,7 @@ begin 8/2 when b"001", 16/2 when b"010", 32/2 when b"011", - 217/2 when b"100", -- 230.400 + 64/2 when b"100", 434/2 when b"101", -- 115.200 2604/2 when b"110", -- 19.200 5208/2 when others; -- 9.600 @@ -1060,7 +1079,7 @@ begin 8/2 when b"001", 16/2 when b"010", 32/2 when b"011", - 217/2 when b"100", -- 230.400 + 64/2 when b"100", 434/2 when b"101", -- 115.200 2604/2 when b"110", -- 19.200 5208/2 when others; -- 9.600 @@ -1088,7 +1107,7 @@ begin 8/2 when b"001", 16/2 when b"010", 32/2 when b"011", - 217/2 when b"100", -- 230.400 + 64/2 when b"100", 434/2 when b"101", -- 115.200 2604/2 when b"110", -- 19.200 5208/2 when others; -- 9.600