/////////////////////////////////////////////////////////////////////// // // serial i/o module // 2 words (A000-A001) // // Visible Registers: // // Read // A000 read_data // A001 status // // Write // A000 write_data // A001 control // // Bits within status/control registers // // Bits within status register // Bit 15 IRQ // Bit 5 TXIRQ (transmit interrupt request) // Bit 4 RXIRQ (receive interrupt request) // Bit 3 TXIE (transmit interrupt enable) // Bit 2 RXIE (receive interrupt enable) // Bit 1 TXE (transmit buffer empty) // Bit 0 RXF (receive buffer full) // // Bits within control register // Bit 3 TXIE (transmit interrupt enable) // Bit 2 RXIE (receive interrupt enable) // // // Operation of the Serial Input // // RXF goes high when data is received and available in the // read_data register. If the RXIE bit is high then an interrupt // will also be generated (the RXIRQ and IRQ bits in the // status register will go high and the nIRQ output of the // module will go active). // // Reading from the read_data register will automatically clear the // RXF bit and any associated interrupt if there is no more data // available. // // Operation of the Serial Output // // TXE goes high to indicate that there is space available in the // write_data register. If the TXIE bit is high then an interrupt // will also be generated (the TXIRQ and IRQ bits in the // status register will go high and the nIRQ output of the // module will go active). // // Writing to the write_data register will automatically clear the // TXE bit and any associated interrupt. // /////////////////////////////////////////////////////////////////////// `ifdef serial_access_time // already defined - do nothing `else `define serial_access_time 500 `endif `timescale 1ns / 100ps module io_serial( Data, Address, nOE, RnW, nCE, nWait, nIRQ, Clock, nReset ); inout [15:0] Data; input [0:0] Address; input nCE, RnW, nOE; output nWait, nIRQ; input Clock, nReset; reg [15:0] received_data[0:20]; integer received_data_cycle[0:20]; reg [15:0] read_data; reg [15:0] write_data; reg [0:0] write_address; wire [15:0] status; reg RXIE, TXIE; //Interrupt masks (high to enable interupts) reg RXF; reg TXE; wire RXIRQ, TXIRQ; wire IRQ; wire read_enable, write_enable; reg delay; initial begin received_data[0] = 3; received_data_cycle[0] = 500; received_data[1] = 5; received_data_cycle[1] = 1000; received_data[2] = 4; received_data_cycle[2] = 1500; received_data[3] = 4; received_data_cycle[3] = 100_000_000; end initial delay = 0; always @(negedge nCE or Address) if (! nCE) begin delay = 1; #`serial_access_time delay = 0; end assign nWait = (delay && !nCE && (!nOE || !RnW)) ? 0 : 1'bz; assign nIRQ = (IRQ) ? 0 : 1'bz; assign IRQ = RXIRQ || TXIRQ; assign RXIRQ = (RXF && RXIE); assign TXIRQ = (TXE && TXIE); assign status = { IRQ, 9'd0, TXIRQ,RXIRQ, TXIE,RXIE, TXE,RXF}; assign read_enable = RnW && !nOE && !nCE; assign Data = (!read_enable) ? 16'bz : (Address == 0) ? read_data : status; assign write_enable = !RnW && !nCE; always @(posedge nCE or negedge nReset) if (!nReset) begin write_data <= 0; RXIE <= 0; TXIE <= 0; end else if ((Address == 0) && !RnW) // Write data begin write_data <= Data; TXE <= 0; end else if ((Address == 1) && !RnW) // Write control begin RXIE <= Data[2]; TXIE <= Data[3]; end else if ((Address == 0) && RnW) // Read data begin RXF <= 0; end integer cycle_number, data_index; always @(posedge Clock or negedge nReset) if (!nReset) begin RXF <= 0; TXE <= 1; cycle_number <= 0; data_index <= 0; end else begin if ( received_data_cycle[data_index] == cycle_number) begin read_data <= received_data[data_index]; RXF <= 1; if ( RXIE ) $display( $time, ": Serial Data Input:", received_data[data_index] ); data_index <= data_index + 1; end if ( TXE == 0 ) begin TXE <= 1; $display( $time, ": Serial Data Output", write_data ); end cycle_number <= cycle_number + 1; end endmodule