Second half of mipssim support, plus documentation improvements.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3401 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									6bf5b4e8a8
								
							
						
					
					
						commit
						f0fc6f8fbc
					
				| 
						 | 
					@ -0,0 +1,167 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU/mipssim emulation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Emulates a very simple machine model similiar to the one use by the
 | 
				
			||||||
 | 
					 * proprietary MIPS emulator.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include "vl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TARGET_WORDS_BIGENDIAN
 | 
				
			||||||
 | 
					#define BIOS_FILENAME "mips_bios.bin"
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define BIOS_FILENAME "mipsel_bios.bin"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TARGET_MIPS64
 | 
				
			||||||
 | 
					#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void load_kernel (CPUState *env)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int64_t entry, kernel_low, kernel_high;
 | 
				
			||||||
 | 
					    long kernel_size;
 | 
				
			||||||
 | 
					    long initrd_size;
 | 
				
			||||||
 | 
					    ram_addr_t initrd_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    kernel_size = load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND,
 | 
				
			||||||
 | 
					                           &entry, &kernel_low, &kernel_high);
 | 
				
			||||||
 | 
					    if (kernel_size >= 0) {
 | 
				
			||||||
 | 
					        if ((entry & ~0x7fffffffULL) == 0x80000000)
 | 
				
			||||||
 | 
					            entry = (int32_t)entry;
 | 
				
			||||||
 | 
					        env->PC[env->current_tc] = entry;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        fprintf(stderr, "qemu: could not load kernel '%s'\n",
 | 
				
			||||||
 | 
					                env->kernel_filename);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* load initrd */
 | 
				
			||||||
 | 
					    initrd_size = 0;
 | 
				
			||||||
 | 
					    initrd_offset = 0;
 | 
				
			||||||
 | 
					    if (env->initrd_filename) {
 | 
				
			||||||
 | 
					        initrd_size = get_image_size (env->initrd_filename);
 | 
				
			||||||
 | 
					        if (initrd_size > 0) {
 | 
				
			||||||
 | 
					            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
 | 
				
			||||||
 | 
					            if (initrd_offset + initrd_size > env->ram_size) {
 | 
				
			||||||
 | 
					                fprintf(stderr,
 | 
				
			||||||
 | 
					                        "qemu: memory too small for initial ram disk '%s'\n",
 | 
				
			||||||
 | 
					                        env->initrd_filename);
 | 
				
			||||||
 | 
					                exit(1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            initrd_size = load_image(env->initrd_filename,
 | 
				
			||||||
 | 
					                                     phys_ram_base + initrd_offset);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (initrd_size == (target_ulong) -1) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
 | 
				
			||||||
 | 
					                    env->initrd_filename);
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void main_cpu_reset(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CPUState *env = opaque;
 | 
				
			||||||
 | 
					    cpu_reset(env);
 | 
				
			||||||
 | 
					    cpu_mips_register(env, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (env->kernel_filename)
 | 
				
			||||||
 | 
					        load_kernel (env);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					mips_mipssim_init (int ram_size, int vga_ram_size, int boot_device,
 | 
				
			||||||
 | 
					                   DisplayState *ds, const char **fd_filename, int snapshot,
 | 
				
			||||||
 | 
					                   const char *kernel_filename, const char *kernel_cmdline,
 | 
				
			||||||
 | 
					                   const char *initrd_filename, const char *cpu_model)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char buf[1024];
 | 
				
			||||||
 | 
					    unsigned long bios_offset;
 | 
				
			||||||
 | 
					    CPUState *env;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    mips_def_t *def;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Init CPUs. */
 | 
				
			||||||
 | 
					    if (cpu_model == NULL) {
 | 
				
			||||||
 | 
					#ifdef TARGET_MIPS64
 | 
				
			||||||
 | 
					        cpu_model = "5Kf";
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        cpu_model = "24Kf";
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (mips_find_by_name(cpu_model, &def) != 0)
 | 
				
			||||||
 | 
					        def = NULL;
 | 
				
			||||||
 | 
					    env = cpu_init();
 | 
				
			||||||
 | 
					    cpu_mips_register(env, def);
 | 
				
			||||||
 | 
					    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
 | 
				
			||||||
 | 
					    qemu_register_reset(main_cpu_reset, env);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Allocate RAM. */
 | 
				
			||||||
 | 
					    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Map the BIOS / boot exception handler. */
 | 
				
			||||||
 | 
					    bios_offset = ram_size + vga_ram_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Load a BIOS / boot exception handler image. */
 | 
				
			||||||
 | 
					    if (bios_name == NULL)
 | 
				
			||||||
 | 
					        bios_name = BIOS_FILENAME;
 | 
				
			||||||
 | 
					    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
 | 
				
			||||||
 | 
					    ret = load_image(buf, phys_ram_base + bios_offset);
 | 
				
			||||||
 | 
					    if ((ret < 0 || ret > BIOS_SIZE) && !kernel_filename) {
 | 
				
			||||||
 | 
					        /* Bail out if we have neither a kernel image nor boot vector code. */
 | 
				
			||||||
 | 
					        fprintf(stderr,
 | 
				
			||||||
 | 
					                "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
 | 
				
			||||||
 | 
					                buf);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        /* We have a boot vector start address. */
 | 
				
			||||||
 | 
					        env->PC[env->current_tc] = (target_long)0xbfc00000;
 | 
				
			||||||
 | 
					        cpu_register_physical_memory(0x1fc00000LL,
 | 
				
			||||||
 | 
					                                     ret, bios_offset | IO_MEM_ROM);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (kernel_filename) {
 | 
				
			||||||
 | 
					        env->ram_size = ram_size;
 | 
				
			||||||
 | 
					        env->kernel_filename = kernel_filename;
 | 
				
			||||||
 | 
					        env->kernel_cmdline = kernel_cmdline;
 | 
				
			||||||
 | 
					        env->initrd_filename = initrd_filename;
 | 
				
			||||||
 | 
					        load_kernel(env);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Init CPU internal devices. */
 | 
				
			||||||
 | 
					    cpu_mips_irq_init_cpu(env);
 | 
				
			||||||
 | 
					    cpu_mips_clock_init(env);
 | 
				
			||||||
 | 
					    cpu_mips_irqctrl_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Register 64 KB of ISA IO space at 0x1fd00000. */
 | 
				
			||||||
 | 
					    isa_mmio_init(0x1fd00000, 0x00010000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* A single 16450 sits at offset 0x3f8. It is attached to
 | 
				
			||||||
 | 
					       MIPS CPU INT2, which is interrupt 4. */
 | 
				
			||||||
 | 
					    if (serial_hds[0])
 | 
				
			||||||
 | 
					        serial_init(0x3f8, env->irq[4], serial_hds[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nd_table[0].vlan) {
 | 
				
			||||||
 | 
					        if (nd_table[0].model == NULL
 | 
				
			||||||
 | 
					            || strcmp(nd_table[0].model, "mipsnet") == 0) {
 | 
				
			||||||
 | 
					            /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */
 | 
				
			||||||
 | 
					            mipsnet_init(0x4200, env->irq[2], &nd_table[0]);
 | 
				
			||||||
 | 
					        } else if (strcmp(nd_table[0].model, "?") == 0) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "qemu: Supported NICs: mipsnet\n");
 | 
				
			||||||
 | 
					            exit (1);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
 | 
				
			||||||
 | 
					            exit (1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QEMUMachine mips_mipssim_machine = {
 | 
				
			||||||
 | 
					    "mipssim",
 | 
				
			||||||
 | 
					    "MIPS MIPSsim platform",
 | 
				
			||||||
 | 
					    mips_mipssim_init,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,269 @@
 | 
				
			||||||
 | 
					#include "vl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEBUG_MIPSNET_SEND
 | 
				
			||||||
 | 
					#define DEBUG_MIPSNET_RECEIVE
 | 
				
			||||||
 | 
					//#define DEBUG_MIPSNET_DATA
 | 
				
			||||||
 | 
					#define DEBUG_MIPSNET_IRQ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MIPSnet register offsets */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MIPSNET_DEV_ID		0x00
 | 
				
			||||||
 | 
					# define MIPSNET_DEV_ID_STRING	"MIPSNET0"
 | 
				
			||||||
 | 
					#define MIPSNET_BUSY		0x08
 | 
				
			||||||
 | 
					#define MIPSNET_RX_DATA_COUNT	0x0c
 | 
				
			||||||
 | 
					#define MIPSNET_TX_DATA_COUNT	0x10
 | 
				
			||||||
 | 
					#define MIPSNET_INT_CTL		0x14
 | 
				
			||||||
 | 
					# define MIPSNET_INTCTL_TXDONE		0x00000001
 | 
				
			||||||
 | 
					# define MIPSNET_INTCTL_RXDONE		0x00000002
 | 
				
			||||||
 | 
					# define MIPSNET_INTCTL_TESTBIT		0x80000000
 | 
				
			||||||
 | 
					#define MIPSNET_INTERRUPT_INFO	0x18
 | 
				
			||||||
 | 
					#define MIPSNET_RX_DATA_BUFFER	0x1c
 | 
				
			||||||
 | 
					#define MIPSNET_TX_DATA_BUFFER	0x20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_ETH_FRAME_SIZE	1514
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct MIPSnetState {
 | 
				
			||||||
 | 
					    uint32_t busy;
 | 
				
			||||||
 | 
					    uint32_t rx_count;
 | 
				
			||||||
 | 
					    uint32_t rx_read;
 | 
				
			||||||
 | 
					    uint32_t tx_count;
 | 
				
			||||||
 | 
					    uint32_t tx_written;
 | 
				
			||||||
 | 
					    uint32_t intctl;
 | 
				
			||||||
 | 
					    uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
 | 
				
			||||||
 | 
					    uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
 | 
				
			||||||
 | 
					    qemu_irq irq;
 | 
				
			||||||
 | 
					    VLANClientState *vc;
 | 
				
			||||||
 | 
					    NICInfo *nd;
 | 
				
			||||||
 | 
					} MIPSnetState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void mipsnet_reset(MIPSnetState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    s->busy = 1;
 | 
				
			||||||
 | 
					    s->rx_count = 0;
 | 
				
			||||||
 | 
					    s->rx_read = 0;
 | 
				
			||||||
 | 
					    s->tx_count = 0;
 | 
				
			||||||
 | 
					    s->tx_written = 0;
 | 
				
			||||||
 | 
					    s->intctl = 0;
 | 
				
			||||||
 | 
					    memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
 | 
				
			||||||
 | 
					    memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void mipsnet_update_irq(MIPSnetState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int isr = !!s->intctl;
 | 
				
			||||||
 | 
					#ifdef DEBUG_MIPSNET_IRQ
 | 
				
			||||||
 | 
					    printf("mipsnet: Set IRQ to %d (%02x)\n", isr, s->intctl);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    qemu_set_irq(s->irq, isr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int mipsnet_buffer_full(MIPSnetState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (s->rx_count >= MAX_ETH_FRAME_SIZE)
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int mipsnet_can_receive(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MIPSnetState *s = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->busy)
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    return !mipsnet_buffer_full(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void mipsnet_receive(void *opaque, const uint8_t *buf, int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MIPSnetState *s = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_MIPSNET_RECEIVE
 | 
				
			||||||
 | 
					    printf("mipsnet: receiving len=%d\n", size);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    if (!mipsnet_can_receive(opaque))
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->busy = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Just accept everything. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Write packet data. */
 | 
				
			||||||
 | 
					    memcpy(s->rx_buffer, buf, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->rx_count = size;
 | 
				
			||||||
 | 
					    s->rx_read = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Now we can signal we have received something. */
 | 
				
			||||||
 | 
					    s->intctl |= MIPSNET_INTCTL_RXDONE;
 | 
				
			||||||
 | 
					    mipsnet_update_irq(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MIPSnetState *s = opaque;
 | 
				
			||||||
 | 
					    int ret = 0;
 | 
				
			||||||
 | 
					    const char *devid = MIPSNET_DEV_ID_STRING;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    addr &= 0x3f;
 | 
				
			||||||
 | 
					    switch (addr) {
 | 
				
			||||||
 | 
					    case MIPSNET_DEV_ID:
 | 
				
			||||||
 | 
						ret = *((uint32_t *)&devid);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case MIPSNET_DEV_ID + 4:
 | 
				
			||||||
 | 
						ret = *((uint32_t *)(&devid + 4));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case MIPSNET_BUSY:
 | 
				
			||||||
 | 
						ret = s->busy;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case MIPSNET_RX_DATA_COUNT:
 | 
				
			||||||
 | 
						ret = s->rx_count;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case MIPSNET_TX_DATA_COUNT:
 | 
				
			||||||
 | 
						ret = s->tx_count;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case MIPSNET_INT_CTL:
 | 
				
			||||||
 | 
						ret = s->intctl;
 | 
				
			||||||
 | 
					        s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case MIPSNET_INTERRUPT_INFO:
 | 
				
			||||||
 | 
					        /* XXX: This seems to be a per-VPE interrupt number. */
 | 
				
			||||||
 | 
						ret = 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case MIPSNET_RX_DATA_BUFFER:
 | 
				
			||||||
 | 
					        if (s->rx_count) {
 | 
				
			||||||
 | 
					            s->rx_count--;
 | 
				
			||||||
 | 
					            ret = s->rx_buffer[s->rx_read++];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    /* Reads as zero. */
 | 
				
			||||||
 | 
					    case MIPSNET_TX_DATA_BUFFER:
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#ifdef DEBUG_MIPSNET_DATA
 | 
				
			||||||
 | 
					    printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MIPSnetState *s = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    addr &= 0x3f;
 | 
				
			||||||
 | 
					#ifdef DEBUG_MIPSNET_DATA
 | 
				
			||||||
 | 
					    printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    switch (addr) {
 | 
				
			||||||
 | 
					    case MIPSNET_TX_DATA_COUNT:
 | 
				
			||||||
 | 
						s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
 | 
				
			||||||
 | 
					        s->tx_written = 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case MIPSNET_INT_CTL:
 | 
				
			||||||
 | 
					        if (val & MIPSNET_INTCTL_TXDONE) {
 | 
				
			||||||
 | 
					            s->intctl &= ~MIPSNET_INTCTL_TXDONE;
 | 
				
			||||||
 | 
					        } else if (val & MIPSNET_INTCTL_RXDONE) {
 | 
				
			||||||
 | 
					            s->intctl &= ~MIPSNET_INTCTL_RXDONE;
 | 
				
			||||||
 | 
					        } else if (val & MIPSNET_INTCTL_TESTBIT) {
 | 
				
			||||||
 | 
					            mipsnet_reset(s);
 | 
				
			||||||
 | 
					            s->intctl |= MIPSNET_INTCTL_TESTBIT;
 | 
				
			||||||
 | 
					        } else if (!val) {
 | 
				
			||||||
 | 
					            /* ACK testbit interrupt, flag was cleared on read. */
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        s->busy = !!s->intctl;
 | 
				
			||||||
 | 
					        mipsnet_update_irq(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case MIPSNET_TX_DATA_BUFFER:
 | 
				
			||||||
 | 
					        s->tx_buffer[s->tx_written++] = val;
 | 
				
			||||||
 | 
					        if (s->tx_written == s->tx_count) {
 | 
				
			||||||
 | 
					            /* Send buffer. */
 | 
				
			||||||
 | 
					#ifdef DEBUG_MIPSNET_SEND
 | 
				
			||||||
 | 
					            printf("mipsnet: sending len=%d\n", s->tx_count);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					            qemu_send_packet(s->vc, s->tx_buffer, s->tx_count);
 | 
				
			||||||
 | 
					            s->tx_count = s->tx_written = 0;
 | 
				
			||||||
 | 
					            s->intctl |= MIPSNET_INTCTL_TXDONE;
 | 
				
			||||||
 | 
					            s->busy = 1;
 | 
				
			||||||
 | 
					            mipsnet_update_irq(s);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    /* Read-only registers */
 | 
				
			||||||
 | 
					    case MIPSNET_DEV_ID:
 | 
				
			||||||
 | 
					    case MIPSNET_BUSY:
 | 
				
			||||||
 | 
					    case MIPSNET_RX_DATA_COUNT:
 | 
				
			||||||
 | 
					    case MIPSNET_INTERRUPT_INFO:
 | 
				
			||||||
 | 
					    case MIPSNET_RX_DATA_BUFFER:
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void mipsnet_save(QEMUFile *f, void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MIPSnetState *s = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_put_be32s(f, &s->busy);
 | 
				
			||||||
 | 
					    qemu_put_be32s(f, &s->rx_count);
 | 
				
			||||||
 | 
					    qemu_put_be32s(f, &s->rx_read);
 | 
				
			||||||
 | 
					    qemu_put_be32s(f, &s->tx_count);
 | 
				
			||||||
 | 
					    qemu_put_be32s(f, &s->tx_written);
 | 
				
			||||||
 | 
					    qemu_put_be32s(f, &s->intctl);
 | 
				
			||||||
 | 
					    qemu_put_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
 | 
				
			||||||
 | 
					    qemu_put_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int mipsnet_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MIPSnetState *s = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (version_id > 0)
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_get_be32s(f, &s->busy);
 | 
				
			||||||
 | 
					    qemu_get_be32s(f, &s->rx_count);
 | 
				
			||||||
 | 
					    qemu_get_be32s(f, &s->rx_read);
 | 
				
			||||||
 | 
					    qemu_get_be32s(f, &s->tx_count);
 | 
				
			||||||
 | 
					    qemu_get_be32s(f, &s->tx_written);
 | 
				
			||||||
 | 
					    qemu_get_be32s(f, &s->intctl);
 | 
				
			||||||
 | 
					    qemu_get_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
 | 
				
			||||||
 | 
					    qemu_get_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MIPSnetState *s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s = qemu_mallocz(sizeof(MIPSnetState));
 | 
				
			||||||
 | 
					    if (!s)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
 | 
				
			||||||
 | 
					    register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
 | 
				
			||||||
 | 
					    register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
 | 
				
			||||||
 | 
					    register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
 | 
				
			||||||
 | 
					    register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
 | 
				
			||||||
 | 
					    register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->irq = irq;
 | 
				
			||||||
 | 
					    s->nd = nd;
 | 
				
			||||||
 | 
					    if (nd && nd->vlan) {
 | 
				
			||||||
 | 
					        s->vc = qemu_new_vlan_client(nd->vlan, mipsnet_receive,
 | 
				
			||||||
 | 
					                                     mipsnet_can_receive, s);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        s->vc = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
 | 
				
			||||||
 | 
					             "mipsnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
 | 
				
			||||||
 | 
					              s->nd->macaddr[0],
 | 
				
			||||||
 | 
					              s->nd->macaddr[1],
 | 
				
			||||||
 | 
					              s->nd->macaddr[2],
 | 
				
			||||||
 | 
					              s->nd->macaddr[3],
 | 
				
			||||||
 | 
					              s->nd->macaddr[4],
 | 
				
			||||||
 | 
					              s->nd->macaddr[5]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mipsnet_reset(s);
 | 
				
			||||||
 | 
					    register_savevm("mipsnet", 0, 0, mipsnet_save, mipsnet_load, s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2037,7 +2037,7 @@ The MIPS Malta prototype board "malta"
 | 
				
			||||||
@item
 | 
					@item
 | 
				
			||||||
An ACER Pica "pica61"
 | 
					An ACER Pica "pica61"
 | 
				
			||||||
@item
 | 
					@item
 | 
				
			||||||
MIPS MIPSsim emulator pseudo board "mipssim"
 | 
					MIPS emulator pseudo board "mipssim"
 | 
				
			||||||
@end itemize
 | 
					@end itemize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The generic emulation is supported by Debian 'Etch' and is able to
 | 
					The generic emulation is supported by Debian 'Etch' and is able to
 | 
				
			||||||
| 
						 | 
					@ -2085,7 +2085,9 @@ PC Keyboard
 | 
				
			||||||
IDE controller
 | 
					IDE controller
 | 
				
			||||||
@end itemize
 | 
					@end itemize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The MIPSsim emulation supports:
 | 
					The mipssim pseudo board emulation provides an environment similiar
 | 
				
			||||||
 | 
					to what the proprietary MIPS emulator uses for running Linux.
 | 
				
			||||||
 | 
					It supports:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@itemize @minus
 | 
					@itemize @minus
 | 
				
			||||||
@item
 | 
					@item
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue