Commit 8ec97abe authored by Roberto Hexsel's avatar Roberto Hexsel

several fixes: remote now reads 1st line of serial.inp; UART.status.RX flags...

several fixes: remote now reads 1st line of serial.inp; UART.status.RX flags updated on a DATA-read, UART.status.TX updated on a status-read; improvements to UART interrupt handler
parent 5f697227
......@@ -57,9 +57,6 @@ extCounter:
# lw $a1, 1*4($k1)
#----------------------------------
mfc0 $k0, c0_status # Read STATUS register
ori $k0, $k0, M_StatusIEn # but do not modify its contents
mtc0 $k0, c0_status # except for re-enabling interrupts
eret # Return from interrupt
.end extCounter
#----------------------------------------------------------------
......@@ -72,6 +69,15 @@ extCounter:
.bss
.align 2
.global Ud
.equ RXHD,0
.equ RXTL,4
.equ RX_Q,8
.equ TXHD,24
.equ TXTL,28
.equ TXQ,32
.equ NRX,48
.equ NTX,52
Ud:
rx_hd: .space 4 # reception queue head index
rx_tl: .space 4 # tail index
......@@ -83,18 +89,34 @@ nrx: .space 4 # characters in RX_queue
ntx: .space 4 # spaces left in TX_queue
_uart_buff: .space 16*4 # up to 16 registers to be saved here
# _uart_buff[0]=UARTstatus, [1]=UARTcontrol, [2]=data_inp, [3]=new,
# _uart_buff[0]=UARTstatus, [1]=UARTcontrol, [2]=$v0, [3]=$v1,
# [4]=$ra, [5]=$a0, [6]=$a1, [7]=$a2, [8]=$a3
.set UART_rx_irq,0x08
.set UART_tx_irq,0x10
.equ UCTRL,0 # UART registers
.equ USTAT,0
.equ UDATA,4
.text
.set noreorder
.global UARTinterr
.ent UARTinterr
UARTinterr:
#----------------------------------------------------------------
# While you are developing the complete handler, uncomment the
# line below
#
# .include "../tests/handlerUART.s"
#
# Your new handler should be self-contained and do the
# return-from-exception. To do that, copy the lines below up
# to, but excluding, ".end UARTinterr", to yours handlerUART.s.
#----------------------------------------------------------------
lui $k0, %hi(_uart_buff) # get buffer's address
ori $k0, $k0, %lo(_uart_buff)
......@@ -105,23 +127,17 @@ UARTinterr:
lui $a0, %hi(HW_uart_addr)# get device's address
ori $a0, $a0, %lo(HW_uart_addr)
lw $k1, 0($a0) # Read status, remove interrupt request
lw $k1, USTAT($a0) # Read status, remove interrupt request
sw $k1, 0*4($k0) # and save UART status to memory
#----------------------------------
# while you are developing the complete handler,
# uncomment the line below and comment out lines up to UARTret
# .include "../tests/handlerUART.s"
#----------------------------------
andi $a1, $k1, UART_rx_irq # Is this reception?
beq $a1, $zero, UARTret # no, ignore it and return
nop
# handle reception
lw $a1, 4($a0) # Read data from device
lw $a1, UDATA($a0) # Read data from device
lui $a2, %hi(Ud) # get address for data & flag
lui $a2, %hi(Ud) # get address for data & flag
ori $a2, $a2, %lo(Ud)
sw $a1, 0*4($a2) # and return from interrupt
......@@ -133,9 +149,6 @@ UARTret:
lw $a1, 6*4($k0) # restore registers $a0,$a1, others?
lw $a0, 5*4($k0)
mfc0 $k0, c0_status # Read STATUS register
ori $k0, $k0, M_StatusIEn # but do not modify its contents
mtc0 $k0, c0_status # except for re-enabling interrupts
eret # Return from interrupt
.end UARTinterr
#----------------------------------------------------------------
......@@ -153,10 +166,6 @@ countCompare:
addiu $k1,$k1,num_cycles # set next interrupt in so many ticks
mtc0 $k1,c0_compare # write to COMPARE to clear IRQ
mfc0 $k0, c0_status # Read STATUS register
ori $k0, $k0, M_StatusIEn # but do not modify its contents
mtc0 $k0, c0_status # except for re-enabling interrupts
ehb
eret # Return from interrupt
.end countCompare
#----------------------------------------------------------------
......
......@@ -321,7 +321,7 @@ _excp_0200:
nop
## the code for each handler must repeat the exception return
## the code for each handler must contain an exception return
## sequence shown below in excp_0200ret.
handlers_tbl:
j dismiss # no request: 000
......@@ -354,7 +354,6 @@ _excp_0200ret:
mtc0 $k0, c0_status # else keep as it was on int entry
ehb
eret # Return from interrupt
nop
.end _excp_0200
#----------------------------------------------------------------
......
......@@ -22,6 +22,7 @@
.equ numCy,0xc0000000 # enable counter
.equ PRINT,$15
.equ STDOUT,$17
.equ COUNT,$16
.equ NL,$13
......@@ -84,21 +85,21 @@ _excp_180:
# interrupt handler ------------------------------------------------
#
##
## stop the counter, print EPC and CAUSE, and return
## stop the counter, print EPC, and return
##
.org x_EXCEPTION_0200,0
_excp_200:
sw $zero, 0(COUNT) # stop the counter
lw $k0, 0(COUNT) # read the counter and disable counting
la $k1, 0x3ffffff
and $k0, $k1, $k0
sw $k0, 0(COUNT) # stop the counter
mfc0 $k1, c0_epc # read EPC
sw $k1, 0(PRINT)
addi $k1, $k1, 4 # skip interrupted instruction
nop
mtc0 $k1, c0_epc # write new EPC
mfc0 $k1, c0_cause # read CAUSE
sw $k1, 0(PRINT)
mfc0 $k1, c0_epc # read EPC -- this is a "return value", keep it!
# sw $k1, 0(PRINT)
addi $k0, $k1, 4 # skip interrupted instruction
nop
mtc0 $k0, c0_epc # write new EPC
ehb
eret
#
......@@ -122,10 +123,11 @@ _excp_BFC0:
##
.org x_ENTRY_POINT,0
main: la PRINT, x_IO_BASE_ADDR
la STDOUT, (x_IO_BASE_ADDR + 1 * x_IO_ADDR_RANGE)
la COUNT, HW_counter_addr
li NL, '\n'
sw NL, 0(STDOUT) # print a new line
##
## counter will interrupt right on the MULT instruction
## MULT is cancelled by the interrupt
......@@ -145,15 +147,106 @@ main: la PRINT, x_IO_BASE_ADDR
nop # counter starts counting
nop
nop
mult $20, $21 # interrupts on the 4th cycle
_mult: mult $20, $21 # interrupts on the 4th cycle
# this MULT is cancelled by the handler
mflo $22
sw $22, 0(PRINT) # should print zero
la $4, _mult
nop
nop
bne $4, $k1, _err1 # error if EPC != _mult
nop
jal ok
nop
nop # clear out the pipeline
nop
nop
nop
nop
##
## counter will interrupt right on the MTC0 instruction
## the MTC0 disables the interrupts
## MTC0 is NOT cancelled by the interrupt
## handler skips the interrupted instruction
## STATUS.IE must be zero and interrupt is cancelled
##
li $6, c0_status_reset # RESET, kernel mode, all else disabled
li $5, (numCy+4) # interrupt in 4+4 cycles
sw $5, 0(COUNT) # it takes four cycles to start counting
nop # 4 pipestages
nop
nop
nop # counter starts counting
# change to STATUS must be in EXEC pipestage
_mtc0: mtc0 $6, c0_status # this MUST NOT be cancelled by the interrupt
nop
nop
lw $7, 0(COUNT) # was the IRQ taken? If so,
la $4, (numCy+4) # value in count must be 4 (b31b30=00)
nop
nop
bne $4, $7, _err2 # error if COUNTER != 4
nop
jal ok
nop
here: j exit
nop
_err1: # interrupt was on the wrong instruction
li $30, 'n'
sw $30, x_IO_ADDR_RANGE($15)
li $30, 'o'
sw $30, x_IO_ADDR_RANGE($15)
li $30, 't'
sw $30, x_IO_ADDR_RANGE($15)
li $30, 'M'
sw $30, x_IO_ADDR_RANGE($15)
li $30, 'U'
sw $30, x_IO_ADDR_RANGE($15)
li $30, 'L'
sw $30, x_IO_ADDR_RANGE($15)
li $30, 'T'
sw $30, x_IO_ADDR_RANGE($15)
j exit
sw NL, x_IO_ADDR_RANGE($15) # print a newline
_err2: # interrupt was on the wrong instruction
li $30, 'w'
sw $30, x_IO_ADDR_RANGE($15)
li $30, 'a'
sw $30, x_IO_ADDR_RANGE($15)
li $30, 's'
sw $30, x_IO_ADDR_RANGE($15)
li $30, ' '
sw $30, x_IO_ADDR_RANGE($15)
li $30, 'I'
sw $30, x_IO_ADDR_RANGE($15)
li $30, 'R'
sw $30, x_IO_ADDR_RANGE($15)
li $30, 'Q'
sw $30, x_IO_ADDR_RANGE($15)
j exit
sw NL, x_IO_ADDR_RANGE($15) # print a newline
# nothing wrong
ok: li $30, 'o'
sw $30, x_IO_ADDR_RANGE($15)
li $30, 'k'
sw $30, x_IO_ADDR_RANGE($15)
sw $13, x_IO_ADDR_RANGE($15) # print a newline
jr $ra
sw $13, x_IO_ADDR_RANGE($15) # print a newline
......@@ -35,3 +35,5 @@ typedef struct serial {
Tdata d; // address is (int *)(IO_UART_ADDR+1)
} Tserial;
#define EOT 0x04 // End Of Transmission character
......@@ -4,10 +4,15 @@
// Remote unit reads string from serial.inp and sends it over the
// serial line.
//
// This program makes use of abstraction to synchronize handler and main().
// handler sets a flag on receiving a new character; main() waits for
// flag==1, reads char, makes flag=0.
//
// UARTinterr, in include/handlers.s, reads newly arrived character,
// sets a flag and puts character in a buffer. main() reads from the
// buffer and prints it to the simulator's standard output.
// sets a flag and puts character in a buffer.
// main() waits for flag==1, then reads from the buffer, prints
// character to the simulator's standard output, makes flag=0.
//
#include "cMIPS.h"
......@@ -36,7 +41,7 @@ int main(void) { // receive a string through the UART serial interface
ctrl.speed = SPEED;
uart->cs.ctl = ctrl; // initizlize UART
// handler sets flag=bfr[3] to 1 after new character is received;
// handler sets flag=[U_FLAg] to 1 after new character is received;
// this program resets the flag on fetching a new character from buffer
bfr[U_FLAG] = 0; // reset flag
......@@ -48,13 +53,16 @@ int main(void) { // receive a string through the UART serial interface
uart->cs.ctl = ctrl;
do {
while ( (c = (char)bfr[U_FLAG]) == 0 ) // check flag in Ud[1]
{}; // nothing new
while ( (c = (char)bfr[U_FLAG]) == 0 ) // check flag in Ud[]
delay_cycle(1); // nothing new, wait
c = (char)bfr[U_DATA]; // get new character
bfr[U_FLAG] = 0; // and reset flag
to_stdout( (int)c ); // and print new char
} while (c != '\0'); // end of string?
if (c != EOT)
to_stdout( c ); // and print new char
else
to_stdout( '\n' ); // and print new-line
} while (c != EOT); // end of transmission?
return c;
return c; // so compiler won't optimize away the last loop
}
......@@ -51,11 +51,14 @@ int main(void) { // receive a string through the UART serial interface
i = i+1;
while ( (state = (int)uart->cs.stat.rxFull) == 0 )
if (state == 0) cmips_delay(1); // just do something with state
delay_cycle(1); // just do something
s[i] = (char)uart->d.rx;
to_stdout( s[i] );
if (s[i] != EOT)
to_stdout( s[i] ); // and print new char
else
to_stdout( '\n' ); // and print new-line
} while (s[i] != '\0');
} while (s[i] != EOT);
return(state);
......
......@@ -69,17 +69,16 @@ int main(void) { // send a string through the UART serial interface
i = i+1;
while ( (state = (int)uart->cs.stat.txEmpty) == 0 )
{}; // if (state == 1) cmips_delay(2); // just do something with state
delay_cycle(1); // do something
uart->d.tx = (int)s[i];
} while (s[i] != '\0'); // '\0' is transmitted in previous line
// then wait until last char is sent out of the shift-register to return
startCounter(COUNTING, 0);
while ( (val=(readCounter() & 0x3fffffff)) < COUNTING )
{};
delay_cycle(1);
return val; // so compiler won't optimize away the last loop
return val; // so compiler won't optimize away the last loop
}
......@@ -26,10 +26,10 @@
-- 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 baud
-- 101: 115.200 baud
-- 110: 19.200 baud
-- 111: 9.600 baus
-- 100: 230.400 bits per second
-- 101: 115.200 bits per second
-- 110: 19.200 bits per second
-- 111: 9.600 bits per second
-- b3=1: signal interrupt on RX buffer full, when a new octet is available
-- b4=1: signal interrupt on TX buffer empty, when TX space is available
-- b5,b6: ignored, not used
......@@ -44,7 +44,9 @@
-- b5: receive buffer is full
-- b6: transmit buffer is empty
-- b7: Clear to Send (CTS) is active
-- when CPU reads status register bits 0,1,3,4 are cleared
--
-- when CPU reads from RXdat register, bits 0,1,3 are cleared
-- when CPU reads from STATUS register, bit 4 is cleared
--
-- RX and TX circuits are dobule-buffered
......@@ -124,7 +126,7 @@ 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, sel_delayed, reset_rxck : std_logic;
signal a_overrun, a_framing, reset_rxck, s_stat_dly : 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;
......@@ -150,8 +152,6 @@ begin
interr <= interr_TX_empty or interr_RX_full;
U_delay: FFDsimple port map (clk, rst, s_stat, sel_delayed);
-- TRANSMISSION ===========================================================
-- txreg is updated under the assumption that SW checked TXempty beforehand
U_txreg: register8 port map (clk,rst, s_tx, d_inp(7 downto 0), txreg);
......@@ -162,8 +162,10 @@ 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);
tx_int_set <= ctrl(4) and tx_ld;
d_int_tx_empty <= (interr_TX_empty or tx_int_set) and not(sel_delayed);
d_int_tx_empty <= (interr_TX_empty or tx_int_set) and not(s_stat_dly);
U_tx_int: FFDsimple port map (clk, rst, d_int_tx_empty, interr_TX_empty);
......@@ -360,14 +362,14 @@ begin
(sta_recv_sto(9) /= '1' or sta_recv_sto(0)/='0') )
else '0';
d_err_framing <= (a_framing or err_framing) and not(sel_delayed);
d_err_framing <= (a_framing or err_framing) and not(s_rx);
U_framing: FFDsimple port map (clk, rst, d_err_framing, err_framing);
d_err_overrun <= (a_overrun or err_overrun) and not(sel_delayed);
d_err_overrun <= (a_overrun or err_overrun) and not(s_rx);
U_overrun: FFDsimple port map (clk, rst, d_err_overrun, err_overrun);
rx_int_set <= ctrl(3) and rx_done;
d_rx_int_set <= (rx_int_set or interr_RX_full) and not(sel_delayed);
d_rx_int_set <= (rx_int_set or interr_RX_full) and not(s_rx);
U_rx_int: FFDsimple port map (clk, rst, d_rx_int_set, interr_RX_full);
......@@ -778,6 +780,7 @@ entity remota is
inpDat : in std_logic; -- serial input
outDat : out std_logic; -- serial output
bit_rt : in reg3); -- selects bit rate
constant EOT : reg8 := x"04"; -- end of transmission character
end remota;
architecture behavior of remota is
......@@ -836,10 +839,10 @@ begin
tx_dbg_st <= integer(tx_state'pos(tx_current_st)); -- debugging only
U_tx: process (tx_current_st, start)
U_tx: process (tx_current_st, start, rst)
variable sentence : line;
variable char : character;
variable good, send_null : boolean;
variable good, send_eot : boolean;
variable bfr : reg8;
variable j : integer;
begin
......@@ -848,13 +851,13 @@ begin
when st_wait => -- 12 wait for starting signal
outDat <= '1';
tx_run <= '0'; -- hold TX clock
send_null := FALSE;
if start = '0' then
send_eot := FALSE;
if start = '0' then
tx_next_st <= st_wait;
else
if not endfile(input_stream) then
if not endfile(input_stream) and rst = '1' then
readline( input_stream, sentence ); -- read first line of text
-- assert false report "fst line: "&integer'image(sentence'length);
assert TRUE report "fst line: "&integer'image(sentence'length);
j := 1;
tx_next_st <= st_init;
else
......@@ -869,15 +872,15 @@ begin
if not endfile(input_stream) then
if j > sentence'right then -- read new line of input
readline( input_stream, sentence );
-- assert false report "new line: "&integer'image(sentence'length);
assert TRUE report "new line: "&integer'image(sentence'length);
bfr := x"0a"; -- new line
j := 0;
elsif sentence'length = 0 then
bfr := x"0a"; -- send new line for empty line
-- assert false report "empty line: " & integer'image(j)&" " & LF;
assert TRUE report "empty line: " & integer'image(j)&" " & LF;
else
read (sentence, char, good);
-- assert false report "read: " & integer'image(j) & " " &char;
assert TRUE report "read: " & integer'image(j) & " " &char;
bfr := std_logic_vector(to_signed( character'pos(char), 8));
end if;
tx_next_st <= st_start;
......@@ -916,12 +919,12 @@ begin
outDat <= '1';
tx_next_st <= st_idle;
when st_done => -- 13 wait forever
if send_null = FALSE then
bfr := x"00"; -- send out a NULL character
send_null := TRUE;
if send_eot = FALSE then
bfr := EOT; -- send out an END-OF-TRANSMISSION
send_eot := TRUE;
tx_next_st <= st_start;
else
tx_next_st <= st_done; -- no more input, done!
tx_next_st <= st_done; -- no more input, wait forever
outDat <= '1';
end if;
tx_run <= '0'; -- stop clock
......@@ -968,11 +971,7 @@ begin
rx_next_st <= st_start;
when st_start =>
reset_rxck <= '0';
-- if rising_edge(rx_clk) then
rx_next_st <= st_b0;
-- else
-- rx_next_st <= st_start;
-- end if;
when st_b0 =>
if falling_edge(rx_clk) then
recv(0) <= inpDat;
......@@ -1039,8 +1038,11 @@ begin
rx_run <= '0';
rx_next_st <= st_idle;
write ( msg, character'val(to_integer( unsigned(recv))) );
if recv = x"00" or recv = x"0a" then
if ((recv /= x"0a") and (recv /= x"04")) then
write ( msg, character'val(to_integer(unsigned(recv))) );
end if;
if ((recv = x"0a") or (recv = x"04")) then
writeline( output_stream, msg );
end if;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment