/* Copyright (c) 1996-1998 Swiss Federal Institute of Technology, Computer Engineering and Networks Laboratory. All rights reserved. Written by David Schweikert . For more documentation please visit http://www.tik.ee.ethz.ch/~gfa. Ethernet device simulation using Ethertap device under Linux 2.1.x. Based on UART.java by George Fankhauser . File: $Source: /usr/drwho/vault/cvs/topsy/MipsSim/Ethertap.java,v $ Affiliation: ETH Zuerich, TIK Version: $Revision: 1.1 $ Creation Date: December 1996 Last Date of Change: $Date: 2000/04/05 14:33:15 $ by: $Author: gfa $ $Log: Ethertap.java,v $ Revision 1.1 2000/04/05 14:33:15 gfa *** empty log message *** */ import java.io.*; import java.net.*; import java.util.*; /* I don't know how the real ethernet devices are memory mapped. I have tried to do it as simple as possible. - Memory layout (bytes): Offset Description ------------ --------------------------------- 0 (0x000) Status 4 (0x001) Control 16 (0x010) Hardware Address (read only), 6 bytes 32 (0x020) Data In length (short) 36 (0x024) Data In (device -> OS) 2048 (0x800) Data Out length (short) 2052 (0x804) Data Out (OS -> device) - Control register (8 bit): Offset (bit) Description ------------ -------------------------------- 0 (LSM) Send data (SD) 1 Data read (DR) - Status register (8 bit): Offset (bit) Description ------------ -------------------------------- 0 (LSM) Received data (RD) Send protocol: fill data, SD->1 Recv protocol: RD=1? -> read data -> DR=1 */ public final class Ethertap extends MemoryRegion { final static int INTERRUPT_NR = 2; final static int ADDRSIZE = 4096; // max. frame len: 1518 bytes final static int STATUS_REGISTER = 0x000; final static int CONTROL_REGISTER = 0x004; final static int HW_ADDRESS = 0x010; final static int RX_SIZE = 0x020; final static int RX_DATA = 0x024; final static int RX_END = 0x7FF; final static int TX_SIZE = 0x800; final static int TX_DATA = 0x804; final static int TX_END = 0xFFF; final static byte SEND_MASK = 0x01; // Control register final static byte READ_MASK = 0x02; final static byte RECV_MASK = 0x01; // Status register InputStream in; OutputStream out; public Ethertap(int baseAddress, int port) { try { Socket s = new Socket(InetAddress.getLocalHost(), port); in = s.getInputStream(); out = s.getOutputStream(); } catch (IOException e) { System.out.print(e.getClass().getName()+ " ("+e.getMessage()+")\n"); System.out.println("Ethertap: couldn't connect to Ethertap server."); } from = baseAddress; to = baseAddress+ADDRSIZE; memory = new byte[ADDRSIZE]; // Initialize HW address memory[HW_ADDRESS] = 0x01; memory[HW_ADDRESS+1] = 0x02; memory[HW_ADDRESS+2] = 0x03; memory[HW_ADDRESS+3] = 0x04; memory[HW_ADDRESS+4] = 0x05; memory[HW_ADDRESS+5] = 0x06; } void writePacket() throws BusErrorException { try { short len = super.readShort(TX_SIZE+from); //System.out.println("Ethertap: sending packet (" + len + ")"); out.write(memory,TX_DATA,len); } catch (IOException e) { System.out.print(e.getClass().getName()+ " ("+e.getMessage()+")\n"); System.out.println("Ethertap: couldn't send to Ethertap server."); } } byte readByte(int address) throws BusErrorException { int offset = address-from; if (offset >= ADDRSIZE) throw new BusErrorException(); //System.out.println("Ethertap: device memory read: " + (address-from)); return memory[offset]; // why not 'return super.readByte(address)' ? } short readShort(int address) throws BusErrorException { if(address-from >= ADDRSIZE) throw new BusErrorException(); //System.out.println("Ethertap: device memory read: " + (address-from)); return super.readShort(address); } int readInt(int address) throws BusErrorException { if(address-from >= ADDRSIZE) throw new BusErrorException(); //System.out.println("Ethertap: device memory read: " + (address-from) + // " [" + Integer.toHexString(super.readInt(address)) + "]"); return super.readInt(address); } void writeByte(int address, byte data) throws BusErrorException { if(out == null) return; int offset = address-from; if (offset != CONTROL_REGISTER && (offset < TX_SIZE || offset > TX_END)) throw new BusErrorException(); memory[offset] = data; if (offset == CONTROL_REGISTER) { if ((data & SEND_MASK) != 0) { writePacket(); memory[offset] ^= SEND_MASK; // clear send } else if ((data & READ_MASK) != 0) { memory[STATUS_REGISTER] &= ~RECV_MASK; memory[offset] ^= READ_MASK; // clear read } } } void checkInterrupt(Processor p) throws IOException { if(in == null) return; try { if (in.available() > 0) { if ((memory[STATUS_REGISTER] & RECV_MASK) == 0) { int len = in.read(memory, RX_DATA, RX_END-RX_DATA); //System.out.println("Ethertap: Got " + len + " bytes!"); super.writeShort(RX_SIZE+from, (short) len); memory[STATUS_REGISTER] |= RECV_MASK; p.interrupt(INTERRUPT_NR); } else { byte b[]; b = new byte[2000]; System.out.println("*** Ethertap: Packets overflow! Discarding packet."); in.read(b); } } } catch (Exception e) { System.out.print(e.getClass().getName()+ " ("+e.getMessage()+")\n"); System.out.println("Ethertap: couldn't receive from Ethertap server."); } } } // Local Variables: // c-basic-offset: 8 // End: