qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] PowerPC 4xx enhacement


From: Salvatore Lionetti
Subject: Re: [Qemu-devel] PowerPC 4xx enhacement
Date: Fri, 21 Nov 2008 01:53:20 +0000 (GMT)

Source modified
===============
- code factoring for ppc405GPr, ppc405EP, ppc405GPe
- reorganization in i2c code, with possibility of board customization callback
- new board added for 'DHT Walnut board', fw in pc-bios/walnut_uboot.bin
- cfi flash now support 'buffer mode', write N {byte, halfword, word} 
consecutively.
- emac/mal now work with vlan mode

Board Walnut:
=============
http://elinux.org/DHT-Walnut-Flameman

CPU PowerPC 405 GPe running at 266Mhz
LAN On-chip 405GP ethernet, namely emac/mal
ROM 512k of boot flash, AMD 29LV040B
PID eeprom via i2c

Full Tested (eth, flash, pid)
=============================
- u-boot 1.1.6 on walnut board (with few patch, see ppc405_board.c)
- OSE on proprietary NSN 4G radio module
- Can anyone test ref405ep and taihu?

P.S:
I've tryed to have patch for bin file but no luck
Since i can not version file, does diff support binary file?does attachment 
work?



Index: Makefile.target
===================================================================
--- Makefile.target     (revision 5720)
+++ Makefile.target     (working copy)
@@ -679,7 +679,7 @@
 # NewWorld PowerMac
 OBJS+= unin_pci.o ppc_chrp.o
 # PowerPC 4xx boards
-OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc405_uc.o ppc405_boards.o
+OBJS+= pflash_cfi02.o emac.o ppc4xx_devs.o ppc405_uc.o ppc405_boards.o
 endif
 ifeq ($(TARGET_BASE_ARCH), mips)
 OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
Index: osdep.c
===================================================================
--- osdep.c     (revision 5720)
+++ osdep.c     (working copy)
@@ -32,6 +32,7 @@
 #include <sys/types.h>
 #include <sys/statvfs.h>
 #endif
+#include <assert.h>
 
 #include "qemu-common.h"
 #include "sysemu.h"
@@ -310,3 +311,49 @@
     fcntl(fd, F_SETFL, f | O_NONBLOCK);
 }
 #endif
+
+void *qemu_mmap(void * start, size_t length, int prot, int flags, int fd, 
off_t  offset) {
+       void *ret;
+#ifndef _WIN32
+       ret = mmap(start, length, prot, flags, fd, offset);
+#else
+       { /* TO TEST!!! */
+               static char name[15];
+               static char ind=0;
+               HANDLE fd_map;
+               LPVOID fd_buf;
+               char*  buf;
+
+               assert(fd!=INVALID_HANDLE_VALUE);
+
+               snprintf(name, 15, "qemu_mmap%d", ind++);
+               fd_map = CreateFileMapping(fd,
+                                          NULL, /* Security attr */
+                                          PAGE_READWRITE,
+                                          0, TOTAL_SIZE,
+                                          name);
+
+               fd_buf = MapViewOfFile(fd_map,
+                                      FILE_MAP_ALL_ACCESS,
+                                      0, 0, /* Offset */
+                                      TOTAL_SIZE);
+               assert(fd_buf);
+               ret = fd_buf;
+
+       }
+#endif
+       return ret;
+}
+int qemu_munmap(void *start, size_t length) {
+       int ret;
+#ifndef _WIN32
+       ret = munmap(start, length);
+#else
+       { /* TO TEST!!! */
+               UnmapViewOfFile(start);
+               /*CloseHandle(fd_map);
+               CloseHandle(fd);*/
+       }
+#endif
+       return ret;
+}
Index: target-ppc/machine.c
===================================================================
--- target-ppc/machine.c        (revision 5720)
+++ target-ppc/machine.c        (working copy)
@@ -8,6 +8,7 @@
     qemu_register_machine(&prep_machine);
     qemu_register_machine(&ref405ep_machine);
     qemu_register_machine(&taihu_machine);
+    qemu_register_machine(&walnut_machine);
 }
 
 void cpu_save(QEMUFile *f, void *opaque)
Index: qemu-common.h
===================================================================
--- qemu-common.h       (revision 5720)
+++ qemu-common.h       (working copy)
@@ -152,4 +152,11 @@
 /* Force QEMU to stop what it's doing and service IO */
 void qemu_service_io(void);
 
+/* KR function prototype. */
+typedef size_t KRHandler(int fd, char* buf, size_t size);
+
+/* mmap like function
+ * (cygwin seem !have aio yet so no linux env under Winzozz) */
+void *qemu_mmap(void * start, size_t length, int prot, int flags, int fd, 
off_t  offset);
+int qemu_munmap(void *start, size_t length);
 #endif
Index: hw/ppc405_boards.c
===================================================================
--- hw/ppc405_boards.c  (revision 5720)
+++ hw/ppc405_boards.c  (working copy)
@@ -206,7 +206,7 @@
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register cpu\n", __func__);
 #endif
-    env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &sram_offset,
+    env = ppc405xp_init("405ep", ram_bases, ram_sizes, 33333333, &pic, 
&sram_offset,
                         kernel_filename == NULL ? 0 : 1);
     /* allocate SRAM */
 #ifdef DEBUG_BOARD_INIT
@@ -353,7 +353,6 @@
     printf("bdloc %016lx %s\n",
            (unsigned long)bdloc, (char *)(phys_ram_base + bdloc));
 }
-
 QEMUMachine ref405ep_machine = {
     .name = "ref405ep",
     .desc = "ref405ep",
@@ -361,6 +360,349 @@
     .ram_require = (128 * 1024 * 1024 + 4096 + 512 * 1024 + BIOS_SIZE) | 
RAMSIZE_FIXED,
 };
 
+/* 
+ * Walnut board
+ *
+ * Starting point from official uboot 1.1.6 with following patch:
+ * - compilation error: cmd_bootm.c:470 manually expand #if
+ * - mac address not in nvram: include/configs/walnut.h add 
"ethaddr=52:54:00:12:34:56\0" in CONFIG_EXTRA_ENV_SETTING
+ * - remove trailer from recv packet(fcs?): cpu/ppc4xx/4xx_enet.c:1478 call 
NetReceive with 'length' as 2nd parameter.
+ */
+/* Addedum related to 405GP: is it only for such device? */
+static target_ulong walnut_dcr_read (void *opaque, int dcrn)
+{
+       target_ulong ret=0;
+       switch (dcrn) {
+               case 0xAA: /* CPCO_ECR */
+                       break;
+               case 0xB0: /* CPC0_PLLMR */
+                       /*                                    |--> {ForwardA, 
Backward} Divisor
+                        *                              ----  |--> Opb
+                        *                        ---> | x2 |-|--> ExtBus
+                        *            ----        |     ----
+                        * CPU  ---> | /4 | ---> PLB ------------> PCI
+                        * Clock      ----
+                        */
+                       ret  = -2 << 29;/* Forward divisor is 2         */
+                       ret |= 2 << 25; /* Backward divisor is 2        */
+                       ret |= 3 << 17; /* Cpu/Plb is 4                 */
+                       ret |= 0 << 13; /* Pci/Plb is 1                 */
+                       ret |= 0 << 11; /* ExtBus/Plb is 2              */
+                       ret |= 1 << 15; /* Opb/Plb is 2                 */
+                       break;
+               case 0xB1: /* CPC0_CR0 */
+                       break;
+               case 0xB2: /* CPC0_CR1 */
+                       break;
+               case 0xB4: /* CPC0_PSR: For same uP model, could be different! 
*/
+                       break;
+               default:
+                       break;
+       }
+/*     printf("walnut_dcr [%x] => %x\n", dcrn, ret);*/
+       return ret;
+}
+static void walnut_dcr_write (void *opaque, int dcrn, target_ulong val)
+{
+/*     printf("walnut_dcr [%x] <= %x\n", dcrn, val);*/
+}
+
+/* 
+ * I2C Customization
+ *
+ * A file.
+ */
+static char PID_content[128]; /* If no file present */
+static uint32_t PID_cursor;
+size_t PID_read(int addr, char *buf, size_t len) {
+       int ret;
+       ret = len;
+       if (len+PID_cursor>128)
+               len = 128 - PID_cursor;
+       memcpy(buf, &PID_content[PID_cursor], len);
+
+#if 0
+       {
+       int i;
+       printf("PID_Read dev(%x) len %d offs %d =>(", addr, ret, PID_cursor);
+       for (i=0; i<ret; i++) {
+               printf(" %x,", buf[i]);
+       }
+       printf(") ret %d\n", ret);
+       }
+#endif
+       return ret;
+}
+size_t PID_write(int addr, char *buf, size_t len) {
+       int ret;
+       ret = len;
+       /* buf = {offset}                  if write to set position (a read'll 
follow)
+        *     = {offset,data0, data1 ...} if write data different from 
position */
+       if (len>0) {
+               PID_cursor = buf[0];
+               len--;
+               if (len>0) {
+                       if (len+PID_cursor>128)
+                               len = 128 - PID_cursor;
+                       memcpy(&PID_content[PID_cursor], buf+1, len);
+               }
+       }
+#if 0
+       {
+       int i;
+       printf("PID_Write dev(0x%x) len %d, off %d <=(", addr, ret, PID_cursor);
+       for (i=0; i<ret; i++) {
+               printf(" %x,", buf[i]);
+       }
+       printf(")\n");
+       }
+#endif
+
+       return ret;
+}
+static void walnut_init (ram_addr_t ram_size, int vga_ram_size,
+                         const char *boot_device, DisplayState *ds,
+                         const char *kernel_filename,
+                         const char *kernel_cmdline,
+                         const char *initrd_filename,
+                         const char *cpu_model)
+{
+    ppc4xx_bd_info_t bd;
+    CPUPPCState *env;
+    qemu_irq *pic;
+    ram_addr_t sram_offset, bios_offset, bdloc;
+    target_phys_addr_t ram_bases[2], ram_sizes[2];
+    target_ulong sram_size, bios_size;
+    //int phy_addr = 0;
+    //static int phy_addr = 1;
+    target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+    int linux_boot;
+    int fl_idx, fl_sectors, len;
+    int ppc_boot_device = boot_device[0];
+    int index;
+
+    /* XXX: fix this */
+    ram_bases[0] = 0x00000000;
+    ram_sizes[0] = 0x08000000;
+    ram_bases[1] = 0x00000000;
+    ram_sizes[1] = 0x00000000;
+    ram_size = 128 * 1024 * 1024;
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register cpu\n", __func__);
+#endif
+    env = ppc405xp_init("405GPe", ram_bases, ram_sizes, 33333333, &pic, 
&sram_offset,
+                        kernel_filename == NULL ? 0 : 1);
+    /* Customize some dcr */
+    ppc_dcr_register(env, 0xAA/* CPC0_ECR   */, NULL, &walnut_dcr_read, 
&walnut_dcr_write);
+    ppc_dcr_register(env, 0xB0/* CPC0_PLLMR */, NULL, &walnut_dcr_read, NULL);
+    ppc_dcr_register(env, 0xB1/* CPC0_CR0   */, NULL, &walnut_dcr_read, 
&walnut_dcr_write);
+    ppc_dcr_register(env, 0xB2/* CPC0_CR1   */, NULL, &walnut_dcr_read, 
&walnut_dcr_write);
+    ppc_dcr_register(env, 0xB4/* CPC0_PSR   */, NULL, &walnut_dcr_read, NULL);
+
+    /* Customize I2C access */
+    {
+       extern KRHandler* readF;
+       extern KRHandler* writeF;
+
+       /* PID */
+       //load_init_image("pid.bin", NULL, 256, 0xff);
+       int PID_fd;
+       memset(PID_content, 0, 128);
+       if ((PID_fd=open("pid.bin", O_RDWR | O_BINARY, 0666))>=0) { /*"r+b");*/
+               int n = read(PID_fd, PID_content, 128);
+               if (n<0) {
+                       printf("Error reading file pid.bin (ret %d)\n", n); 
+               } else if (n<128) {
+                       printf("Warning reading file pid.bin: only %d/128 bytes 
loaded\n", n);
+               }
+               close(PID_fd);
+       }
+       if (PID_fd<0) {
+               /* Built in eeprom */
+               printf("Warning using builtin pid content!\n");
+               PID_content[2]  = 4; /* Magic word, use sdram */
+               PID_content[3]  = 12; /* Row word, use sdram */
+               PID_content[4]  = 10; /* Col word, use sdram */
+               PID_content[5]  = 1; /* 1 bank */
+               PID_content[6]  = 32; /* Module width */
+               PID_content[31] = 0x10; /* How many 4MB is long */
+               PID_content[127]= 0 | 2 /* Cas latency */;
+       }
+
+       readF = &PID_read;
+       writeF = &PID_write;
+    }
+    /* allocate SRAM */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register SRAM at offset %08lx\n", __func__, sram_offset);
+#endif
+    /* Last 48 (max 128) bytes) used for bd info */
+    sram_size = 8 * 1024;
+    cpu_register_physical_memory(0x40000000, sram_size,
+                                 sram_offset | IO_MEM_RAM);
+    /* allocate and load BIOS */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register BIOS\n", __func__);
+#endif
+    bios_offset = sram_offset + sram_size;
+    fl_idx = 0;
+#ifdef USE_FLASH_BIOS
+    index = drive_get_index(IF_PFLASH, 0, fl_idx);
+    if (index != -1) {
+        bios_size = bdrv_getlength(drives_table[index].bdrv);
+        fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+        printf("Register parallel flash %d size " ADDRX " at offset %08lx "
+               " addr " ADDRX " '%s' %d\n",
+               fl_idx, bios_size, bios_offset, -bios_size,
+               bdrv_get_device_name(drives_table[index].bdrv), fl_sectors);
+#endif
+        pflash_cfi02_register((uint32_t)(-bios_size), bios_offset,
+                              drives_table[index].bdrv, 65536, fl_sectors, 1,
+                              2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA);
+        fl_idx++;
+    } else
+#endif
+    {
+        char buf[1024];
+        ram_addr_t flash_offset;
+       target_ulong flash_size;
+       
+       flash_offset = bios_offset;
+       flash_size = 512*1024;
+#ifdef DEBUG_BOARD_INIT
+        printf("Load BIOS from file\n");
+#endif
+        if (bios_name == NULL)
+            bios_name = BIOS_FILENAME;
+        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
+        bios_size = get_image_size(buf);
+        if (bios_size < 0 || bios_size > BIOS_SIZE) {
+            fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
+            exit(1);
+        }
+        bios_size = (bios_size + 0xfff) & ~0xfff;
+#ifdef DEBUG_BOARD_INIT
+        printf("Loading bios@" ADDRX " %d bytes\n", (uint32_t)(-bios_size), 
bios_size);
+#endif
+#if 1
+        pflash_cfi02_register((uint32_t)(-flash_size), flash_offset,
+                              NULL, 65536 /*sector len*/, flash_size/65536 /* 
nblocks */, 1,
+                              1 /* width */, 0x0001/* AMD */, 0x4F/* 
Am29LV040B */, 0x0000, 0x0000, 0x555/* unlock addrs */, 0x2AA);
+#else
+        cpu_register_physical_memory((uint32_t)(-flash_size),
+                                     flash_size, flash_offset | IO_MEM_ROM);
+#endif
+
+        bios_size = load_image_targphys(buf, (-bios_size), BIOS_SIZE/* max sz 
*/);
+        if (bios_size < 0 || bios_size > BIOS_SIZE) {
+            fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
+            exit(1);
+        }
+       bios_size = flash_size;
+    }
+    bios_offset += bios_size;
+    /* Register FPGA */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register FPGA\n", __func__);
+#endif
+    ref405ep_fpga_init(0xF0300000);
+    /* Register NVRAM */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register NVRAM\n", __func__);
+#endif
+    m48t59_init(NULL, 0xF0000000, 0, 8192, 8);
+    /* Load kernel */
+    linux_boot = (kernel_filename != NULL);
+    if (0) {
+#ifdef DEBUG_BOARD_INIT
+        printf("%s: load kernel\n", __func__);
+#endif
+        memset(&bd, 0, sizeof(bd));
+        bd.bi_memstart = 0x00000000;
+        bd.bi_memsize = ram_size;
+        bd.bi_flashstart = -bios_size;
+        bd.bi_flashsize = -bios_size;
+        bd.bi_flashoffset = 0;
+        bd.bi_sramstart = 0xFFF00000;
+        bd.bi_sramsize = sram_size;
+        bd.bi_bootflags = 0;
+        bd.bi_intfreq = 133333333;
+        bd.bi_busfreq = 33333333;
+        bd.bi_baudrate = 115200;
+        bd.bi_s_version[0] = 'Q';
+        bd.bi_s_version[1] = 'M';
+        bd.bi_s_version[2] = 'U';
+        bd.bi_s_version[3] = '\0';
+        bd.bi_r_version[0] = 'Q';
+        bd.bi_r_version[1] = 'E';
+        bd.bi_r_version[2] = 'M';
+        bd.bi_r_version[3] = 'U';
+        bd.bi_r_version[4] = '\0';
+        bd.bi_procfreq = 133333333;
+        bd.bi_plb_busfreq = 33333333;
+        bd.bi_pci_busfreq = 33333333;
+        bd.bi_opbfreq = 33333333;
+        bdloc = ppc405_set_bootinfo(env, &bd, 0x00000001);
+        env->gpr[3] = bdloc;
+        kernel_base = KERNEL_LOAD_ADDR;
+        /* now we can load the kernel */
+        kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        printf("Load kernel size " TARGET_FMT_ld " at " TARGET_FMT_lx
+               " %02x %02x %02x %02x\n", kernel_size, kernel_base,
+               *(char *)(phys_ram_base + kernel_base),
+               *(char *)(phys_ram_base + kernel_base + 1),
+               *(char *)(phys_ram_base + kernel_base + 2),
+               *(char *)(phys_ram_base + kernel_base + 3));
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = INITRD_LOAD_ADDR;
+            initrd_size = load_image(initrd_filename,
+                                     phys_ram_base + initrd_base);
+            if (initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+        env->gpr[4] = initrd_base;
+        env->gpr[5] = initrd_size;
+        ppc_boot_device = 'm';
+        if (kernel_cmdline != NULL) {
+            len = strlen(kernel_cmdline);
+            bdloc -= ((len + 255) & ~255);
+            memcpy(phys_ram_base + bdloc, kernel_cmdline, len + 1);
+            env->gpr[6] = bdloc;
+            env->gpr[7] = bdloc + len;
+        } else {
+            env->gpr[6] = 0;
+            env->gpr[7] = 0;
+        }
+        env->nip = KERNEL_LOAD_ADDR;
+    } else {
+        env->nip = 0xFFFFFFFC;
+    }
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: Done\n", __func__);
+#endif
+    /*printf("bdloc %016lx %s\n",
+           (unsigned long)bdloc, (char *)(phys_ram_base + bdloc));*/
+}
+QEMUMachine walnut_machine = {
+    .name = "walnut",
+    .desc = "DHT Walnut board, based on ppc405GPe",
+    .init = walnut_init,
+    .ram_require = (128 * 1024 * 1024 + 4096 + 512 * 1024 + BIOS_SIZE) | 
RAMSIZE_FIXED,
+};
+
 /*****************************************************************************/
 /* AMCC Taihu evaluation board */
 /* - PowerPC 405EP processor
@@ -530,7 +872,7 @@
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register cpu\n", __func__);
 #endif
-    env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &bios_offset,
+    env = ppc405xp_init("405ep", ram_bases, ram_sizes, 33333333, &pic, 
&bios_offset,
                         kernel_filename == NULL ? 0 : 1);
     /* allocate and load BIOS */
 #ifdef DEBUG_BOARD_INIT
Index: hw/emac.c
===================================================================
--- hw/emac.c   (revision 0)
+++ hw/emac.c   (revision 0)
@@ -0,0 +1,797 @@
+/*
+ * QEMU EMAC emulation
+ *
+ * Copyright (c) 2008, Lionetti Salvatore address@hidden
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* This module provide an emulation for ethernet onchip controller on ppc4xx 
cpu.
+ * Tested on
+ * - emulator of a NSN proprietary board, for 4G
+ * - walnut board/u-boot-1.1.6 (whith some patch)
+ *
+ * TODO:
+ * - >1 {tx, rx} channel 
+ * - can_receive() and buffer_full() too simple.
+ */
+#include "hw.h"
+#include "ppc.h"
+#include "ppc405.h"
+#include "pc.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "net.h"
+
+/*#define DEBUG_EMAC*/
+#ifdef DEBUG_EMAC
+#define DPRINT(fmt, args...)                           \
+    do { printf("%" PRIu64 " %s: " fmt , qemu_get_clock(rt_clock), __func__, 
##args); } while (0)
+#else
+#define DPRINT(fmt, args...)
+#endif 
+
+/* 
+ * Redefined because if !exist, linker gives a warning but produce qemu,
+ * but on execution this call cause problem
+ * (could be cygwin & mingw cohesistence?)
+ */
+#if (defined(WORDS_BIGENDIAN) && defined(TARGET_WORDS_BIGENDIAN)) || 
((!defined(WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN)))
+#if 0
+static unsigned long int htonl(unsigned long int hostlong);
+static unsigned short int htons(unsigned short int hostshort);
+#endif
+static unsigned long int ntohl(unsigned long int ing) {
+       return ing;
+}
+static unsigned short int ntohs(unsigned short int ing) {
+       return ing;
+}
+#else
+static unsigned long int ntohl(unsigned long int ing) {
+       unsigned char tmp;
+       unsigned char* tmpp = (unsigned char*)&ing;
+       tmp=tmpp[0]; tmpp[0]=tmpp[3]; tmpp[3]=tmp;
+       tmp=tmpp[1]; tmpp[1]=tmpp[2]; tmpp[2]=tmp;
+       return *(unsigned long int*)tmpp;
+}
+static unsigned short int ntohs(unsigned short int ing) {
+       return ((ing&0xFF)<<8) | ((ing&0xFF00)>>8);
+}
+#endif
+
+/* qemu initialization:
+ *
+ * parse command line: call net_client_init() for each -net, either for {if, 
collision domain} options.
+ *                     ==========                                      
================
+ *                     IF MAC=...      <==== Vlan{Id,Ptr} ====>        
COLLISION DOMAIN (mean N-1 other IF MAC=...)
+ *                     ==========                                      
================
+ *                             -net nic[,...]: fill field onto nd_table[] 
{MAC(cl|auto), model, vlanPtr=f(vlanId)}
+ *                                             vlanPtr=f(vlanId)->guest++
+ *                             -net tap[,...]: vlanPtr=f(vlanId)->host ++
+ *                                             tap_win32_init(vlanPtr, 
"ifname=tap..."):
+ *                                                     
qemu_new_vlan_client(vlanPtr,tap_receive, tap* opaque)          RECV
+ *                                                     
qemu_add_wait_object(tap_sem, tap_w32_send, tap* opaque)        SEND
+ *                     
+ *                     For each vlan created,
+ *                             exit if no GUEST & some HOST
+ *                             warn if some GUEST & no HOST
+ *                                                                             
          
+ * start machine:      Es ppc (also pc use n2000) call machine->init():
+ *                     isa_ne2000_init(base, irqno, &nd_table[i])
+ *                             register_ioport_write(base + ..., 
ne2000_asic_ioport_write, opaque NE2000State*);       SEND
+ *                             qemu_new_vlan_client(nd->vlan, ne2000_receive, 
ne2000_can_receive, opaque NE2000State*) RECV
+ *
+ * Done!!!
+ *
+ * qemu runtime scenario:
+ *
+ * packet send from HOST:      a signal (after exec() cycle) is sent to 
tap_sem => tap_w32_send() => tap_win32_read()
+ *                             if some bytes returned => qemu_send_packet() => 
send to all 'client' (better peer) of
+ *                             such vlan, different from itself => 
ne2000_receive()
+ *
+ * packet send from GUEST:     in machine code we call qemu_send_packet() => 
(prec) => tap_receive() => tap_w32_write()
+ *
+ *
+ * So onto VLAN actors always call qemu_send_packet() that dispatch packet to 
all peer attached to same vlan.
+ *
+ */
+/* PPC405 layer 2, reversed MII mode:
+ *
+ * address@hidden already mapped.
+ * Configuration RW:
+ *
+ * Read(ind, data):
+ *     [EMAC0_STACR] <= (STACR_STAC_R | ind)
+ *     [EMAC0_STACR] & STACR_OC must goes to 0
+ *     [EMAC0_STACR] => >>16 => data
+ *
+ * Write(ind, data)
+ *     [EMAC0_STACR] <= (STACR_STAC_W | ind | data<<16)
+ *     [EMAC0_STACR] & STACR_OC must goes to 0
+ *
+ * Physical access:
+ * Read(ind_phy, ind_reg, data)
+ *     [EMAC0_STACR] <= (STACR_STAC_W | TANTOS_REG_MIIAC | (ind_reg&0x1F | 
OP_READ | (ind_phy&0x1F)<<5))>>16
+ *     [EMAC0_STACR] & STACR_OC must goes to 0
+ *     
+ *     Verify:
+ *     [EMAC0_STACR] <= (STACR_STAC_R | TANTOS_REG_MIIRD)
+ *     [EMAC0_STACR] & STACR_OC must goes to 0
+ *     [EMAC0_STACR] => data
+ *     data & STACR_PHYE should be 0
+ *     data=data>>16
+ *
+ * Tantos Stub Layer: (needed?)
+ *
+ * From mal we need
+ * - MAL0_TXCTPxR
+ * - MAL0_RXCTPxR
+ * - MAL0_RCBS0
+ */
+/* TODO: need interaction between device!
+ * very difficult since all struct is in .c file */
+extern uint32_t txctpr[4];
+extern uint32_t rxctpr[2];
+extern uint32_t rcbs[2];
+extern uint32_t *rxeobisr; /* With namespace, use & to automatize 
correlation.*/
+extern uint32_t *txeobisr;
+// For PPC405
+#define EMAC0_BASE        0xEF600800
+#define EMAC0_STACR_DISP  0x35
+#define EMAC0_STACR      (EMAC0_BASE + EMAC0_STACR_DISP) /* 4 byte addressing 
*/
+#define STACR_OC          0x00008000 /* Occupied flag */
+#define STACR_PHYE        0x00004000
+#define STACR_STAC_W      0x00002000
+#define STACR_STAC_R      0x00001000
+
+#define TANTOS_REG_MIIAC    0x120      /// TANTOS3G MII indirect acess 
registers
+#define TANTOS_REG_MIIWD    0x121
+#define TANTOS_REG_MIIRD    0x122
+#define OP_WRITE       0x0400
+#define OP_READ                0x0800
+#define MBUSY          0x8000
+
+/* WORDS_BIGENDIAN = FALSE su HOST i386, GUEST ppc
+ * per cui e' l'architetura HOST
+ */
+struct EmacMalRxDes {
+#ifndef WORDS_BIGENDIAN
+    union {
+           struct { /* Mal */
+                   unsigned int emac1_nu       : 2;
+                   unsigned int bit5_intr      : 1;
+                   unsigned int bit4_first     : 1;
+                   unsigned int bit3_last      : 1;
+                   unsigned int bit2_contm     : 1;
+                   unsigned int bit1_wrap      : 1;
+                   unsigned int bit0_empty     : 1;
+                   unsigned int emac2_nu       : 8; 
+           } __attribute__ ((packed)) mal;
+           struct { /* Status: Read access, error cause */
+                   unsigned int bit7_pausepacket       : 1;
+                   unsigned int bit6_overrun           : 1;
+                   unsigned int mal_nu                 : 6;
+                   unsigned int bit15_inrange          : 1;
+                   unsigned int bit14_outrange         : 1;
+                   unsigned int bit13_longpacket       : 1;
+                   unsigned int bit12_fcs              : 1;
+                   unsigned int bit11_alignment        : 1;
+                   unsigned int bit10_shortevent       : 1;
+                   unsigned int bit9_runtpacket        : 1;
+                   unsigned int bit8_badpacket         : 1;
+           } __attribute__ ((packed)) emac_errstatus;
+    } __attribute__ ((packed));
+#else
+#error "Host endianism BUG: To Test!!!"
+#endif
+    unsigned short len;
+    unsigned char* buf;
+} __attribute__ ((packed)); /* Host endianism, to be converted */
+
+struct EmacMalTxDes {
+#ifndef WORDS_BIGENDIAN
+    /* IN A HALF-WORD (16bits)
+     * position                position
+     * in bitfield     in value
+     * from high       from MSb
+     * =========================
+     * 0               8
+     * 1               9
+     * 2               10
+     * 3               11
+     * 4               12
+     * 5               13
+     * 6               14
+     * 7               15
+     * 8               0
+     * 9               1
+     * 10              2
+     * 11              3
+     * 12              4
+     * 13              5
+     * 14              6
+     * 15              7
+     *
+     * ===HOST LE, TARGET BE===
+     * IN A BYTE (8bits)
+     *
+     * IN A HALF-WORD (16bits)
+     * 0-7             8-15
+     * 8-15            0-7
+     */
+    union {
+           struct { /* Mal */
+                   unsigned int emac1_nu       : 2;
+                   unsigned int bit5_intr      : 1;
+                   unsigned int bit4_resv      : 1;
+                   unsigned int bit3_last      : 1;
+                   unsigned int bit2_contm     : 1;
+                   unsigned int bit1_wrap      : 1;
+                   unsigned int bit0_ready     : 1;
+                   unsigned int emac2_nu       : 8; 
+           } __attribute__ ((packed)) mal;
+           struct { /* Status: Read access, error cause */
+                   unsigned int bit7_badpacket         : 1;
+                   unsigned int bit6_badfsc            : 1;
+                   unsigned int mal_nu                 : 6;
+                   unsigned int bit15_sqe              : 1;
+                   unsigned int bit14_underrun         : 1;
+                   unsigned int bit13_singlecoll       : 1;
+                   unsigned int bit12_multiplecoll     : 1;
+                   unsigned int bit11_latecoll         : 1;
+                   unsigned int bit10_excessivecoll    : 1;
+                   unsigned int bit9_excessivedeferral : 1;
+                   unsigned int bit8_lossofcarrier     : 1;
+           } __attribute__ ((packed)) emac_errorstatus;
+           struct { /* Control: Write access */
+                   unsigned int bit7_generatepad       : 1;
+                   unsigned int bit6_generatefcs       : 1;
+                   unsigned int mal_nu                 : 6;
+                   unsigned int emac_nu                : 4;
+                   unsigned int bit11_vlantag_replace  : 1;
+                   unsigned int bit10_vlantag_insert   : 1;
+                   unsigned int bit9_sourceaddr_insert : 1;
+                   unsigned int bit8_sourceaddr_replace: 1;
+           } __attribute__ ((packed)) emac_control;
+    };
+#else
+#error "Host endianism BUG: To Test!!!"
+#endif
+    unsigned short len;
+    unsigned char* buf;
+}__attribute__ ((packed)); /* Host endianism, to be converted */
+
+/* Controlo Register definition */
+struct EmacRegs {
+#if 0
+#ifndef WORDS_BIGENDIAN
+       struct Emac0_mr0 {
+               unsigned int ;
+       } __attribute__((packed)); 
+#else
+#error "Host endianism BUG: To Test!!!"
+#endif
+#else
+       /* 0 */
+       uint32_t mr0;
+       uint32_t mr1;
+       uint32_t tmr0;
+       uint32_t tmr1;
+       uint32_t rmr;
+       uint32_t isr;
+       uint32_t isre;
+       uint32_t iahr;
+       uint32_t ialr;
+       uint32_t vtpid;
+       /* 10 */
+       uint32_t vtci;
+       uint32_t ptr;
+       uint32_t iaht1;
+       uint32_t iaht2;
+       uint32_t iaht3;
+       uint32_t iaht4;
+       uint32_t gaht1;
+       uint32_t gaht2;
+       uint32_t gaht3;
+       uint32_t gaht4;
+       /* 20 */
+       uint32_t lsah;
+       uint32_t lsal;
+       uint32_t ipgvr;
+       uint32_t stacr;
+       uint32_t trtr;
+       uint32_t rwmr;
+       uint32_t octx;
+       uint32_t ocrx;
+       /* 28 reg */
+
+#define RSTA  mr0 & 0x20000000 
+#define TXEN  mr0 & 0x10000000 
+#define RXEN  mr0 & 0x08000000 
+#endif 
+} __attribute__ ((packed));
+
+typedef struct ppc4xx_emac_t ppc4xx_emac_t;
+struct ppc4xx_emac_t {
+    /* Guest related */
+    target_phys_addr_t base;
+    NICInfo nic;
+    /* To remove, already defined in mal */
+    qemu_irq mal_irqs_txeob;
+    qemu_irq mal_irqs_rxeob;
+    qemu_irq mal_irqs_txerr;
+    qemu_irq mal_irqs_rxerr;
+    qemu_irq mal_irqs_syserr;
+
+    struct EmacRegs reg, _reg;
+
+    struct EmacMalTxDes* tx;
+    struct EmacMalRxDes* rx;
+
+    int txPos, rxPos;
+    int txNum, rxNum;
+
+    int rxLostNum, rxLostLimit;
+
+    /* Host related */
+    VLANClientState *vc;
+    QEMUTimer* tx_timer;
+};
+
+#if 0
+#define EMACMAL_EMPTY 0x8000
+#define EMACMAL_WRAP  0x8000
+#define EMACMAL_EMPTY 0x8000
+#define EMACMAL_EMPTY 0x8000
+void EmacMalDes_readFromTarget(struct EmacMalDes* host, struct EmacMalDes* 
guest) {
+
+    host->status = ntohs(guest->status);
+    host->len = ntohs(guest->len);
+    host->buf = htol(guest->buf);
+}
+void EmacMalDes_writeToTarget(struct EmacMalDes* host, struct EmacMalDes* 
guest) {
+}
+#endif
+void EmacMalRxDes_dump(struct EmacMalRxDes* des) {
+#ifdef DEBUG_EMAC
+       unsigned char* tdes = (unsigned char*) ((unsigned char*)des - 
phys_ram_base);
+       printf("address@hidden,buf%p,empty%d wrap%d contm %d last%d first%d 
intr%d\n",
+                       tdes, ntohs(des->len), (unsigned char*) ntohl((unsigned 
long int)des->buf),
+                       des->mal.bit0_empty, des->mal.bit1_wrap, 
des->mal.bit2_contm, des->mal.bit3_last, des->mal.bit4_first, 
des->mal.bit5_intr);
+#endif
+}
+void EmacMalTxDes_dump(struct EmacMalTxDes* des) {
+#ifdef DEBUG_EMAC
+       unsigned char* tdes = (unsigned char*)((unsigned char*)des - 
phys_ram_base);
+       printf("address@hidden,buf%p,ready%d wrap%d contm %d last%d first%d 
intr%d\n",
+                       tdes, ntohs(des->len), (unsigned char*)ntohl((unsigned 
long int)des->buf),
+                       des->mal.bit0_ready, des->mal.bit1_wrap, 
des->mal.bit2_contm, des->mal.bit3_last, des->mal.bit4_resv, 
des->mal.bit5_intr);
+#endif
+}
+#if 0
+static int emac_buffer_full(ppc4xx_emac_t *s)
+{
+#if 0
+    int avail, index, boundary;
+
+    index = s->curpag << 8;
+    boundary = s->boundary << 8;
+    if (index < boundary)
+        avail = boundary - index;
+    else
+        avail = (s->stop - s->start) - (index - boundary);
+    if (avail < (MAX_ETH_FRAME_SIZE + 4))
+        return 1;
+#endif
+    return 0;
+}
+
+static int emac_can_receive(void *opaque)
+{
+#if 0
+    NE2000State *s = opaque;
+
+    if (s->cmd & E8390_STOP)
+        return 1;
+    return !ne2000_buffer_full(s);
+#endif
+    return 0;
+}
+#endif
+
+
+static void emac_receive(void *opaque, const uint8_t *buf, int size)
+{
+    ppc4xx_emac_t* emac = (ppc4xx_emac_t*) opaque;
+
+    DPRINT("%d bytes\n", size);
+    if (emac->reg.RXEN) {
+    if (emac->rx->buf) {
+    if (size<1520) {
+           if (emac->rx[emac->rxPos].mal.bit0_empty) {
+           /* data is allocated with the maximum possible length, on eth = 
1520Bytes
+            * len field represent packet size.*/
+                   /* We !use Continuos mode, first & last field ignored */
+                   unsigned char* dstG = (unsigned char*) ntohl((unsigned long 
int)emac->rx[emac->rxPos].buf);
+                   unsigned char* dstH= dstG+(unsigned int)phys_ram_base;
+                   unsigned short size16 = size;
+                   DPRINT(" Delivery message HOST %p-> GUEST %p,pos%d\n", 
dstH, dstG, emac->rxPos);
+                   EmacMalRxDes_dump(&emac->rx[emac->rxPos]);
+                   emac->reg.ocrx += size16;
+                   memcpy(dstH, buf, size);    
+                   emac->rx[emac->rxPos].len = ntohs(size16);
+                   emac->rx[emac->rxPos].mal.bit0_empty = 0;
+                   if (emac->rx[emac->rxPos].mal.bit5_intr) {
+                           /* TODO: use appropriate channel */
+                           *rxeobisr = 0xC0000000;
+                           qemu_irq_raise(emac->mal_irqs_rxeob);
+                   }
+
+                   emac->rxPos += (emac->rx[emac->rxPos].mal.bit1_wrap)? 
-(emac->rxPos) : 1;
+           } else {
+                   if (++emac->rxLostNum == emac->rxLostLimit) {
+                           printf(" %d Message lost, board seem hung up!\n", 
emac->rxLostNum);
+                           emac->rxLostLimit*=10;
+                   }
+           }
+    } else {
+           printf(" Message size > 1520, discarding packet\n");
+    }
+    } else {
+    }
+    } else {
+           static int sndOrMore=0;
+           if (!sndOrMore) {
+                   printf("emac/mal: Driver !command start yet\n");
+                   sndOrMore=1;
+           }
+    }
+#if 0
+#define MIN_BUF_SIZE 60
+    NE2000State *s = opaque;
+    uint8_t *p;
+    unsigned int total_len, next, avail, len, index, mcast_idx;
+    uint8_t buf1[60];
+    static const uint8_t broadcast_macaddr[6] =
+        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+#if defined(DEBUG_NE2000)
+    printf("NE2000: received len=%d\n", size);
+#endif
+
+    if (s->cmd & E8390_STOP || ne2000_bufstruct mal_emac_bdfer_full(s))
+        return;
+
+    /* XXX: check this */
+    if (s->rxcr & 0x10) {
+        /* promiscuous: receive all */
+    } else {
+        if (!memcmp(buf,  broadcast_macaddr, 6)) {
+            /* broadcast address */
+            if (!(s->rxcr & 0x04))
+                return;
+        } else if (buf[0] & 0x01) {
+            /* multicast */
+            if (!(s->rxcr & 0x08))
+                return;
+            mcast_idx = compute_mcast_idx(buf);
+            if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
+                return;
+        } else if (s->mem[0] == buf[0] &&
+                   s->mem[2] == buf[1] &&
+                   s->mem[4] == buf[2] &&
+                   s->mem[6] == buf[3] &&
+                   s->mem[8] == buf[4] &&
+                   s->mem[10] == buf[5]) {
+            /* match */
+        } else {
+            return;
+        }
+    }
+
+
+    /* if too small buffer, then expand it */
+    if (size < MIN_BUF_SIZE) {
+        memcpy(buf1, buf, size);
+        memset(buf1 + size, 0, MIN_BUF_SIZE - size);
+        buf = buf1;
+        size = MIN_BUF_SIZE;
+    }
+
+    index = s->curpag << 8;
+    /* 4 bytes for header */
+    total_len = size + 4;
+    /* address for next packet (4 bytes for CRC) */
+    next = index + ((total_len + 4 + 255) & ~0xff);
+    if (next >= s->stop)
+        next -= (s->stop - s->start);
+    /* prepare packet header */
+    p = s->mem + index;
+    s->rsr = ENRSR_RXOK; /* receive status */
+    /* XXX: check this */
+    if (buf[0] & 0x01)
+        s->rsr |= ENRSR_PHY;
+    p[0] = s->rsr;
+    p[1] = next >> 8;
+    p[2] = total_len;
+    p[3] = total_len >> 8;
+    index += 4;
+
+    /* write packet data */
+    while (size > 0) {
+        if (index <= s->stop)
+            avail = s->stop - index;
+        else
+            avail = 0;
+        len = size;
+        if (len > avail)
+            len = avail;
+        memcpy(s->mem + index, buf, len);
+        buf += len;
+        index += len;
+        if (index == s->stop)
+            index = s->start;
+        size -= len;
+    }
+    s->curpag = next >> 8;
+
+    /* now we can signal we have received something */
+    s->isr |= ENISR_RX;
+    ne2000_update_irq(s);
+#endif
+}
+
+void emac_ppc405_init(ppc4xx_emac_t* emac, NICInfo *nd)
+{
+    memcpy(&emac->nic, nd, sizeof(NICInfo));
+    /* We are only be able to receive. Sending packet mean receiver action get 
up */
+    emac->vc = qemu_new_vlan_client(nd->vlan, emac_receive,
+                                 NULL/*emac_can_receive*/, emac);
+
+    snprintf(emac->vc->info_str, sizeof(emac->vc->info_str),
+             "emac macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+             emac->nic.macaddr[0],
+             emac->nic.macaddr[1],
+             emac->nic.macaddr[2],
+             emac->nic.macaddr[3],
+             emac->nic.macaddr[4],
+             emac->nic.macaddr[5]);
+    printf("%s\n", emac->vc->info_str);
+}
+
+static void ppc4xx_emac_reset (void *opaque)
+{
+    ppc4xx_emac_t *emac;
+
+    emac = opaque;
+    emac->rx = NULL;
+    emac->tx = NULL;
+    emac->txPos = emac->rxPos = 0;
+    emac->txNum = emac->rxNum = 0;
+    emac->rxLostNum=0;
+    emac->rxLostLimit=1;
+
+    memset(&emac->reg, 0, sizeof(emac->reg));
+    emac->reg.mr0   = 0xC0000000;
+    emac->reg.tmr1  = 0x380F0000;
+    emac->reg.vtpid = 0x00008808;
+    emac->reg.ptr   = 0x0000FFFF;
+    emac->reg.ipgvr = 0x00000004;
+    emac->reg.stacr = 0x00008000;
+    emac->reg.rwmr  = 0x04001000;
+
+    /* Now ready to issue mii control transfer */
+    emac->reg.stacr = 0;
+}
+/* It looks like a lot of Linux programs assume page size
+ * is 4kB long. This is evil, but we have to deal with it...
+ *
+#define TARGET_PAGE_BITS 12
+ * Here we have many register.
+ * Do action only for reset or transmit command.
+ * Other will be simple configuration latched during device emulation
+ * es stop rx, allow pause packet.
+ *
+ * Another tip:
+ * When possible only implemente the read of value, since using var read/write 
is target indep
+ */
+static uint32_t emac_readl (void *opaque, target_phys_addr_t addr)
+{
+       uint32_t value;
+       ppc4xx_emac_t* emac = (ppc4xx_emac_t*)opaque;
+       uint32_t ind = (addr-emac->base)>>2;
+       /* Keep in a separate way, as stackable code */
+       if (ind>=28) {
+               printf("emac: Out of range register %d!\n", ind);
+               return 0;
+       }
+       value = ((uint32_t*)&emac->reg)[ind];
+       DPRINT("emac: [%d] => %x\n", ind, value);
+       return value/*STACR_OC*/;
+}
+
+static void emac_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+       ppc4xx_emac_t* emac = (ppc4xx_emac_t*)opaque;
+       uint32_t ind = (addr-emac->base)>>2;
+
+/*     printf("%s: " PADDRX " val %x\n",__func__, addr, value);*/
+       /* Exist some common code for this? */
+       if (ind>=28) {
+               printf("emac: Out of range register %d!\n", ind);
+               return;
+       }
+       switch (ind) {
+               case 20:
+               case 21:
+               case 26:
+               case 27:
+                       printf("emac: Attemping to write to read only reg!");
+                       return;
+       }
+       DPRINT("emac: [%d] <= %x\n", ind, value);
+       /* Keep in a separate way, as stackable code */
+       ((uint32_t*)&emac->reg)[ind] = value;
+       if (ind==0) {
+               emac->_reg.mr0 = value;
+               /* soft reset */
+               if (emac->_reg.RSTA) {
+                       printf("emac: soft reset commanded!\n");
+                       ppc4xx_emac_reset(emac);/* Should be protected with a 
semaphore, also in emac_receive()? */
+                       value &= ~(emac->_reg.RSTA);    /* Sw look for this bit 
go down */
+               }
+
+               DPRINT("emac: St%s tx channel!\n", 
emac->_reg.TXEN?"arting":"opping");
+               DPRINT("emac: St%s rx channel!\n", 
emac->_reg.RXEN?"arting":"opping");
+
+               /* Suppose the mal reg was updated, seem a good approximation */
+               if (emac->_reg.TXEN && emac->tx==NULL) {
+                       int l=0;
+                       emac->tx = (struct EmacMalTxDes*) (txctpr[0] + 
phys_ram_base);
+                       do { EmacMalTxDes_dump(&emac->tx[l]); } while 
(!emac->tx[l].mal.bit1_wrap && l++<50);
+               }
+               if (emac->_reg.RXEN && emac->rx==NULL) {
+                       int l=0;
+                       emac->rx = (struct EmacMalRxDes*) (rxctpr[0] + 
phys_ram_base);
+                       do { EmacMalRxDes_dump(&emac->rx[l]); } while 
(!emac->rx[l].mal.bit1_wrap && l++<50);
+               }
+               /* A timer that periodically check packet to send 
+               emac->tx_timer = qemu_new_timer();*/
+       }
+       if (ind==2) {
+               if (value & 0xC0000000) { /* both channel */
+                       if (emac->reg.TXEN) {
+                       if (emac->tx[emac->txPos].mal.bit0_ready) {
+                               unsigned char* dstG = (unsigned char*) 
ntohl((unsigned long int)emac->tx[emac->txPos].buf);
+                               unsigned char* dstH= dstG+(unsigned 
int)phys_ram_base;
+                               unsigned short size16 = 
ntohs(emac->tx[emac->txPos].len);
+
+                               DPRINT("Sending packet on pos %d\n", 
emac->txPos);
+                               qemu_send_packet(emac->vc, dstH, size16);
+                               emac->reg.octx += size16;
+                               if (emac->tx[emac->txPos].mal.bit5_intr) {
+                                       /* TODO: use appropriate channel */
+                                       *txeobisr = 0xC0000000;
+                                       qemu_irq_raise(emac->mal_irqs_txeob);
+                               }
+
+                               /* Clear status */
+                               emac->tx[emac->txPos].mal.bit0_ready = 0;
+                               /* 0x808 is stucked at STACR_OC */
+                               emac->txPos += 
(emac->tx[emac->txPos].mal.bit1_wrap)? -(emac->txPos) : 1;
+
+                               /* 
+                                * u-boot driver (no os=>no task) poll this bit 
until became 0,
+                                * but in PPC405GPr User manual nothing said 
about this
+                                */
+                               value &= ~0xC0000000;
+                       } else {printf("Processor goes crazy(ready bit was 
0)!!! Stopping tx\n");}
+                       } else {DPRINT("Tx is disabled\n");}
+               }
+       }
+       if (ind==23) {
+               /* PPC405GPr_UM2004 say, on page 568:
+                * 'EMAC sets EMAC0_STACR[OC] = 0 when the EMAC0_STACR is 
written to.'
+                * 'EMAC then sets EMAC0_STACR[OC] = 1 to indicate that the 
data has been written to the PHY, or the data'
+                * 'read from the PHY is valid. The device driver should poll 
for EMAC0_STACR[OC] = 1 before issuing a new'
+                * 'command, or before using data read from the PHY'
+                * 
+                * our approximation:
+                * - initial condition                  0
+                * - write(sw start some MII command)   1 (we end in the same 
cycle)
+                * - read(poll status)                  1
+                * - write(sw start new cmd | ...)      0
+                *
+                * reg write clear (bit index is opposite then those reported 
by official manual)
+                * PHYD bit 31:16       Data (RW)
+                * OC   bit 15          0 when this reg is addressed, 1 data 
written to PHY/data readed correctly from PHY
+                * PHYE bit 14          1 PhyError during read
+                * STAC bit 13:12       00 Reserved/01 Read/10 Write/11 Reserved
+                * OPBC bit 11:10       OPB Bus clock freq. signal EMCMDCIk
+                * PCDA bit 9:5         PHY Command destination address
+                * PRA  bit 4:0         PHY Register address
+                *
+               value &= ~(1<<15);*/
+               value ^=  (1<<15);
+               value &= ~(1<<14);
+       }
+       /* Keep in a separate way, as stackable code */
+       ((uint32_t*)&emac->reg)[ind] = value;
+}
+static uint32_t emac_readw (void *opaque, target_phys_addr_t addr)
+{
+       printf("Lettura a granularita' word su EMAC " PADDRX "\n",addr);
+       return 0;
+}
+
+static void emac_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+       printf("Scrittura a granularita' word su EMAC " PADDRX "\n",addr);
+}
+
+static uint32_t emac_readb (void *opaque, target_phys_addr_t addr)
+{
+       printf("Lettura a granularita' byte su EMAC " PADDRX "\n",addr);
+       return 0;
+}
+
+static void emac_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+       printf("Scrittura a granularita' byte su EMAC " PADDRX "\n",addr);
+}
+
+
+static CPUReadMemoryFunc *emac_read[] = {
+    &emac_readb,
+    &emac_readw,
+    &emac_readl,
+};
+
+static CPUWriteMemoryFunc *emac_write[] = {
+    &emac_writeb,
+    &emac_writew,
+    &emac_writel,
+};
+void ppc4xx_emac_init (CPUState *env, ppc4xx_mmio_t *mmio, target_phys_addr_t 
offset, NICInfo *nic, qemu_irq mal_irqs[4])
+{
+    ppc4xx_emac_t *emac;
+
+    emac = qemu_mallocz(sizeof(ppc4xx_emac_t));
+    if (emac != NULL) {
+        emac->base = offset;
+#ifdef DEBUG_OPBA
+        printf("%s: offset " PADDRX "\n", __func__, offset);
+#endif
+        ppc4xx_mmio_register(env, mmio, offset, 0x70,
+                             emac_read, emac_write, emac);
+        qemu_register_reset(ppc4xx_emac_reset, emac);
+
+       /* One time configuration, HOST related */
+       emac_ppc405_init(emac, nic);
+
+       emac->mal_irqs_txeob = mal_irqs[0];
+       emac->mal_irqs_rxeob = mal_irqs[1];
+       emac->mal_irqs_txerr = mal_irqs[2];
+       emac->mal_irqs_rxerr = mal_irqs[3];
+
+       /* N Time configuration, GUEST related */
+        ppc4xx_emac_reset(emac);
+    }
+}
Index: hw/pflash_cfi02.c
===================================================================
--- hw/pflash_cfi02.c   (revision 5720)
+++ hw/pflash_cfi02.c   (working copy)
@@ -2,6 +2,7 @@
  *  CFI parallel flash with AMD command set emulation
  *
  *  Copyright (c) 2005 Jocelyn Mayer
+ *  Copyright (c) 2008 Lionetti Salvatore
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,7 +23,7 @@
  * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
  * Supported commands/modes are:
  * - flash read
- * - flash write
+ * - flash write (also buffer mode)
  * - flash ID read
  * - sector erase
  * - chip erase
@@ -34,14 +35,20 @@
  * It does not implement software data protection as found in many real chips
  * It does not implement erase suspend/resume commands
  * It does not implement multiple sectors erase
+ *
+ * Revisione done to optimize, (the next'll be mmap()), expecially for 
WriteBufferLoad command.
+ * Use different name for structure, so multiple device could be 
address@hidden time
  */
 
 #include "hw.h"
 #include "flash.h"
 #include "qemu-timer.h"
 #include "block.h"
+#include "cpu-all.h" /* To have FLASH_LOG_CFI */
+#include "exec-all.h" /* To have loglevel */
 
-//#define PFLASH_DEBUG
+#define USE_SIMPLE_TABLE
+/*#define PFLASH_DEBUG*/
 #ifdef PFLASH_DEBUG
 #define DPRINTF(fmt, args...)                      \
 do {                                               \
@@ -51,7 +58,8 @@
 #define DPRINTF(fmt, args...) do { } while (0)
 #endif
 
-struct pflash_t {
+#define pflash_cfi02_t pflash_t
+struct pflash_cfi02_t {
     BlockDriverState *bs;
     target_phys_addr_t base;
     uint32_t sector_len;
@@ -60,18 +68,30 @@
     int width;
     int wcycle; /* if 0, the flash is read normally */
     int bypass;
+    uint32_t bytes2write; /* In buffer load mode, must remember the number of 
bytes to elaborate */
+    uint8_t buffer_loading; /* For buffer load mode 1 mean read nword-1 & 
apply write & apply end command */
+    uint32_t buffer_loading_start;
+    uint32_t buffer_loading_end;
     int ro;
     uint8_t cmd;
     uint8_t status;
     uint16_t ident[4];
     uint16_t unlock_addr[2];
     uint8_t cfi_len;
-    uint8_t cfi_table[0x52];
+    uint8_t cfi_table[0x80];
     QEMUTimer *timer;
     ram_addr_t off;
     int fl_mem;
     int rom_mode;
     void *storage;
+#if 0
+    /* Layer needed to optimize (driver common size) Vs (device common size)
+     * Used by timer() & update(), update() use SIGNED!!!
+     * A simple way to represent a list of number. */
+    int pendingW;
+    int fstSector;
+    int curSector;
+#endif
 };
 
 static void pflash_register_memory(pflash_t *pfl, int rom_mode)
@@ -88,9 +108,41 @@
                                      pfl->chip_len, phys_offset);
 }
 
+static void pflash_cfi02_core_reset (void *opaque) {
+    struct pflash_cfi02_t *pfl = (struct pflash_cfi02_t*)opaque;
+
+    pfl->bypass = 0;
+    pfl->wcycle = 0;
+    pfl->cmd = 0;
+    pfl->status = 0;
+
+    pfl->bytes2write = 0;
+    pfl->buffer_loading = 0;
+    pfl->buffer_loading_start = 0;
+    pfl->buffer_loading_end = 0;
+
+/*    pfl->pendingW = pfl->fstSector = curSector = 0; Lost current write? */
+    
+    pflash_register_memory(pfl, 1);
+}
+
+static void pflash_cfi02_reset (void *opaque) {
+    struct pflash_cfi02_t *pfl = (struct pflash_cfi02_t*)opaque;
+
+    qemu_del_timer(pfl->timer);
+#if 0 /* XXX: there should be a bit to set up read-only,
+       *      the same way the hardware does (with WP pin).
+       */
+    pfl->ro = 1;
+#else
+    pfl->ro = 0;
+#endif
+    pflash_cfi02_core_reset(pfl);
+    printf("Resetting cfi chip!\n");
+}
 static void pflash_timer (void *opaque)
 {
-    pflash_t *pfl = opaque;
+    struct pflash_cfi02_t *pfl = opaque;
 
     DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
     /* Reset flash */
@@ -104,13 +156,12 @@
     pfl->cmd = 0;
 }
 
-static uint32_t pflash_read (pflash_t *pfl, uint32_t offset, int width)
+static uint32_t pflash_read (struct pflash_cfi02_t *pfl, uint32_t offset, int 
width)
 {
-    uint32_t boff;
+    uint32_t boff, _boff;
     uint32_t ret;
     uint8_t *p;
 
-    DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset);
     ret = -1;
     offset -= pfl->base;
     if (pfl->rom_mode) {
@@ -119,7 +170,7 @@
             pflash_register_memory(pfl, 1);
     }
     offset &= pfl->chip_len - 1;
-    boff = offset & 0xFF;
+    boff = _boff = offset & 0xFF;
     if (pfl->width == 2)
         boff = boff >> 1;
     else if (pfl->width == 4)
@@ -136,32 +187,34 @@
     flash_read:
         /* Flash area read */
         p = pfl->storage;
+        p += offset;
+common_read:
         switch (width) {
         case 1:
-            ret = p[offset];
+            ret = p[0];
 //            DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
             break;
         case 2:
 #if defined(TARGET_WORDS_BIGENDIAN)
-            ret = p[offset] << 8;
-            ret |= p[offset + 1];
+            ret = p[0] << 8;
+            ret |= p[1];
 #else
-            ret = p[offset];
-            ret |= p[offset + 1] << 8;
+            ret = p[0];
+            ret |= p[1] << 8;
 #endif
 //            DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
             break;
         case 4:
 #if defined(TARGET_WORDS_BIGENDIAN)
-            ret = p[offset] << 24;
-            ret |= p[offset + 1] << 16;
-            ret |= p[offset + 2] << 8;
-            ret |= p[offset + 3];
+            ret = p[0] << 24;
+            ret |= p[1] << 16;
+            ret |= p[2] << 8;
+            ret |= p[3];
 #else
-            ret = p[offset];
-            ret |= p[offset + 1] << 8;
-            ret |= p[offset + 2] << 16;
-            ret |= p[offset + 3] << 24;
+            ret = p[0];
+            ret |= p[1] << 8;
+            ret |= p[2] << 16;
+            ret |= p[3] << 24;
 #endif
 //            DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
             break;
@@ -199,16 +252,81 @@
         break;
     case 0x98:
         /* CFI query mode */
-        if (boff > pfl->cfi_len)
+        if (_boff > pfl->cfi_len)
             ret = 0;
-        else
-            ret = pfl->cfi_table[boff];
+        else {
+#ifndef        USE_SIMPLE_TABLE
+            ret = pfl->cfi_table[_boff];
+#else
+           p = &pfl->cfi_table[_boff];
+           goto common_read;
+#endif
+       }
         break;
     }
 
+    DPRINTF("%s: offset " TARGET_FMT_lx " value 0x%x width %d func %x\n", 
__func__, _boff, ret, width, pfl->cmd);
     return ret;
 }
 
+#if 0
+/* 
+ * update flash content on disk 
+ * Act as intermediate between
+ * - 32B from Driver 
+ * - 512B of device
+ * Optimize only when length==32 & Write only when sector is crossed
+ * Need a timer that commit if no more write? No if we write every 512B
+ * RAM is always updated 
+ */
+#define PFLASH_512BLOCK 8      /* 0 -> sector of 512B, 1 -> sector of 1024B, 
... */
+#define PFLASH_XBLOCK  (9 + PFLASH_512BLOCK)
+#define PFLASH_XBOUND  ((1 << PFLASH_XBLOCK)-1)
+static inline void pflash_update(struct pflash_cfi02_t *pfl, int offset,
+                          int size)
+{
+       int offset_end;
+       int grouped = 0; /* Current version is linked with internal cache */
+       int forcefl = 0; /* Force flush after all op */
+
+       if (pfl->bs) {
+               int _offset = offset;
+               offset = offset >> PFLASH_XBLOCK;
+
+               /* Try to group sequential write
+                * Stop also if found a sector bound! (so avoid timer for now) 
*/
+               if (size == 32) {
+                       forcefl = (((_offset+size)&PFLASH_XBOUND/*511*/)==0);
+                       if (pfl->pendingW) {
+                               /* Try to group with previous write() */
+                               grouped = (offset == pfl->curSector);
+                       } else {
+                               /* First write in this group */
+                               pfl->fstSector = offset;
+                               pfl->curSector = offset;
+                               pfl->pendingW = 1;
+                               grouped = 1;
+                       }
+               }
+
+               /* Commit any pending write if the case. */
+               if ((pfl->pendingW && !grouped) || forcefl) {
+                       DPRINTF("%s: flushing sectors " TARGET_FMT_lx " ns 
%d\n", __func__, pfl->fstSector, pfl->curSector - pfl->fstSector + 1);
+                       bdrv_write(pfl->bs, pfl->fstSector<<PFLASH_512BLOCK, 
pfl->storage + (pfl->fstSector << (PFLASH_XBLOCK)), (pfl->curSector - 
pfl->fstSector + 1)<<(PFLASH_512BLOCK));
+                       pfl->pendingW = 0;
+               }
+
+               /* Current write (!in case we just do it with previous commit) 
*/
+               if (!grouped) {
+                       offset_end = _offset + size;
+                       /* round to sectors */
+                       offset_end = (offset_end + 511) >> 9;
+                       DPRINTF("%s: flushing sectors " TARGET_FMT_lx " ns 
%d\n", __func__, offset, offset_end - offset);
+                       bdrv_write(pfl->bs, offset, pfl->storage + (offset << 
9), offset_end - offset);
+               }
+       }
+}
+#endif
 /* update flash content on disk */
 static void pflash_update(pflash_t *pfl, int offset,
                           int size)
@@ -224,7 +342,7 @@
     }
 }
 
-static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value,
+static void pflash_write (struct pflash_cfi02_t *pfl, uint32_t offset, 
uint32_t value,
                           int width)
 {
     uint32_t boff;
@@ -232,31 +350,32 @@
     uint8_t cmd;
 
     cmd = value;
-    if (pfl->cmd != 0xA0 && cmd == 0xF0) {
-#if 0
-        DPRINTF("%s: flash reset asked (%02x %02x)\n",
-                __func__, pfl->cmd, cmd);
+    if (pfl->cmd != 0xA0 && pfl->cmd != 0x25 && cmd == 0xF0) {
+#if 1
+        DPRINTF("%s: flash reset asked, cmd(%02x) " TARGET_FMT_lx " %x %d\n",
+                __func__, pfl->cmd, (char*)offset-(char*)pfl->storage, value, 
width);
 #endif
         goto reset_flash;
     }
-    DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__,
-            offset, value, width, pfl->wcycle);
+
     offset -= pfl->base;
     offset &= pfl->chip_len - 1;
 
-    DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__,
-            offset, value, width);
     boff = offset & (pfl->sector_len - 1);
     if (pfl->width == 2)
         boff = boff >> 1;
     else if (pfl->width == 4)
         boff = boff >> 2;
+
+    DPRINTF("%s: offset " TARGET_FMT_lx " val %x wid %d wcycle %d\n", __func__,
+           boff, value, width, pfl->wcycle);
+
     switch (pfl->wcycle) {
     case 0:
         /* Set the device in I/O access mode if required */
         if (pfl->rom_mode)
             pflash_register_memory(pfl, 0);
-        /* We're in read mode */
+    /* We're in read mode */
     check_unlock0:
         if (boff == 0x55 && cmd == 0x98) {
         enter_CFI_mode:
@@ -265,26 +384,40 @@
             pfl->cmd = 0x98;
             return;
         }
-        if (boff != pfl->unlock_addr[0] || cmd != 0xAA) {
+        if (!(boff == pfl->unlock_addr[0] || boff == 0x5555) || cmd != 0xAA) {
             DPRINTF("%s: unlock0 failed " TARGET_FMT_lx " %02x %04x\n",
                     __func__, boff, cmd, pfl->unlock_addr[0]);
             goto reset_flash;
         }
         DPRINTF("%s: unlock sequence started\n", __func__);
+       pfl->wcycle++;
         break;
     case 1:
         /* We started an unlock sequence */
     check_unlock1:
-        if (boff != pfl->unlock_addr[1] || cmd != 0x55) {
+        if (!(boff == pfl->unlock_addr[1] || boff == 0x2AAA) || cmd != 0x55) {
             DPRINTF("%s: unlock1 failed " TARGET_FMT_lx " %02x\n", __func__,
                     boff, cmd);
             goto reset_flash;
         }
         DPRINTF("%s: unlock sequence done\n", __func__);
+       pfl->wcycle++;
         break;
     case 2:
+       /* Command write buffer load. */
+       if (boff==0 && cmd==0x25) {
+               /* Wait #word - 1 on same addr */
+               DPRINTF("%s: start buffer load, expect len4next write\n", 
__func__);
+               pfl->buffer_loading=1;
+               pfl->wcycle--;
+       } else if (pfl->buffer_loading) {
+               pfl->bytes2write=(value+1)<<(width>>1);
+               DPRINTF("%s: got %d bytes2write\n", __func__, pfl->bytes2write);
+               pfl->wcycle++;
+               break;
+       } else 
         /* We finished an unlock sequence */
-        if (!pfl->bypass && boff != pfl->unlock_addr[0]) {
+        if (!pfl->bypass && (boff != pfl->unlock_addr[0] && boff != 0x5555)) {
             DPRINTF("%s: command failed " TARGET_FMT_lx " %02x\n", __func__,
                     boff, cmd);
             goto reset_flash;
@@ -296,19 +429,29 @@
         case 0x80:
         case 0x90:
         case 0xA0:
-            pfl->cmd = cmd;
-            DPRINTF("%s: starting command %02x\n", __func__, cmd);
-            break;
+        case 0x25:
+           pfl->cmd = cmd;
+           DPRINTF("%s: starting command %02x\n", __func__, cmd);
+           break;
         default:
             DPRINTF("%s: unknown command %02x\n", __func__, cmd);
             goto reset_flash;
         }
-        break;
+       pfl->wcycle++;
+       break;
     case 3:
         switch (pfl->cmd) {
         case 0x80:
             /* We need another unlock sequence */
             goto check_unlock0;
+        case 0x25:
+           if (pfl->bytes2write==0) {
+                   printf("%s: buffer mode have 0 bytes2write!\n", __func__);
+                   goto reset_flash;
+           }
+           if (!pfl->buffer_loading_start)
+                   pfl->buffer_loading_start=offset;
+           pfl->buffer_loading_end=offset+width;
         case 0xA0:
             DPRINTF("%s: write data offset " TARGET_FMT_lx " %08x %d\n",
                     __func__, offset, value, width);
@@ -343,11 +486,24 @@
                 pflash_update(pfl, offset, 4);
                 break;
             }
-            pfl->status = 0x00 | ~(value & 0x80);
-            /* Let's pretend write is immediate */
-            if (pfl->bypass)
-                goto do_bypass;
-            goto reset_flash;
+           /* In buffer load mode, status is available only after requested 
bytes2write */
+           if (pfl->cmd!=0x25) {
+                   pfl->status = 0x00 | ~(value & 0x80);
+                   /* Let's pretend write is immediate */
+                   if (pfl->bypass)
+                       goto do_bypass;
+                   goto reset_flash;
+           } else {
+                   if (pfl->bytes2write>=width)
+                           pfl->bytes2write-=width;
+                   else {
+                           printf("%s: buffer mode discarded %d bytes at end 
of transfer\n",__func__,width-pfl->bytes2write);
+                           pfl->bytes2write=0;
+                   }
+                   if (pfl->bytes2write)
+                           pfl->wcycle--; /* Dangerous if use timer */
+           }
+           break;
         case 0x90:
             if (pfl->bypass && cmd == 0x00) {
                 /* Unlock bypass reset */
@@ -362,6 +518,8 @@
                     __func__, pfl->cmd);
             goto reset_flash;
         }
+       pfl->wcycle++;
+       break;
     case 4:
         switch (pfl->cmd) {
         case 0xA0:
@@ -370,6 +528,13 @@
             return;
         case 0x80:
             goto check_unlock1;
+        case 0x25:
+           DPRINTF("%s: Buffer load terminated %s (%d bytes remaining)\n", 
__func__, !pfl->bytes2write?"Ok" : "NOK", pfl->bytes2write);
+           /* Update written sequence 
+           pflash_update(pfl, pfl->buffer_loading_start, 
pfl->buffer_loading_end - pfl->buffer_loading_start); */
+           pfl->buffer_loading = 0;
+           pfl->buffer_loading_start = 0;
+           goto reset_flash;
         default:
             /* Should never happen */
             DPRINTF("%s: invalid command state %02x (wc 4)\n",
@@ -436,18 +601,15 @@
         DPRINTF("%s: invalid write state (wc 7)\n",  __func__);
         goto reset_flash;
     }
-    pfl->wcycle++;
-
     return;
 
     /* Reset flash */
  reset_flash:
-    pfl->bypass = 0;
-    pfl->wcycle = 0;
-    pfl->cmd = 0;
+    pflash_cfi02_core_reset(pfl);
     return;
 
  do_bypass:
+    DPRINTF("Requesting bypass\n");
     pfl->wcycle = 2;
     pfl->cmd = 0;
     return;
@@ -461,14 +623,14 @@
 
 static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr)
 {
-    pflash_t *pfl = opaque;
+    struct pflash_cfi02_t *pfl = opaque;
 
     return pflash_read(pfl, addr, 2);
 }
 
 static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr)
 {
-    pflash_t *pfl = opaque;
+    struct pflash_cfi02_t *pfl = opaque;
 
     return pflash_read(pfl, addr, 4);
 }
@@ -482,7 +644,7 @@
 static void pflash_writew (void *opaque, target_phys_addr_t addr,
                            uint32_t value)
 {
-    pflash_t *pfl = opaque;
+    struct pflash_cfi02_t *pfl = opaque;
 
     pflash_write(pfl, addr, value, 2);
 }
@@ -490,7 +652,7 @@
 static void pflash_writel (void *opaque, target_phys_addr_t addr,
                            uint32_t value)
 {
-    pflash_t *pfl = opaque;
+    struct pflash_cfi02_t *pfl = opaque;
 
     pflash_write(pfl, addr, value, 4);
 }
@@ -507,6 +669,7 @@
     &pflash_readl,
 };
 
+#ifndef USE_SIMPLE_TABLE
 /* Count trailing zeroes of a 32 bits quantity */
 static int ctz32 (uint32_t n)
 {
@@ -540,15 +703,15 @@
 
     return ret;
 }
-
+#endif
 pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
                                 BlockDriverState *bs, uint32_t sector_len,
                                 int nb_blocs, int nb_mappings, int width,
                                 uint16_t id0, uint16_t id1,
                                 uint16_t id2, uint16_t id3,
-                                uint16_t unlock_addr0, uint16_t unlock_addr1)
+                               uint16_t unlock_addr0, uint16_t unlock_addr1)
 {
-    pflash_t *pfl;
+    struct pflash_cfi02_t *pfl;
     int32_t chip_len;
 
     chip_len = sector_len * nb_blocs;
@@ -558,9 +721,11 @@
         total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
         return NULL;
 #endif
-    pfl = qemu_mallocz(sizeof(pflash_t));
+    pfl = qemu_mallocz(sizeof(struct pflash_cfi02_t));
     if (pfl == NULL)
         return NULL;
+
+    /* One time initialization, HOST related. */
     pfl->storage = phys_ram_base + off;
     pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops,
                                          pfl);
@@ -574,7 +739,7 @@
         /* read the initial flash content */
         bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
     }
-#if 0 /* XXX: there should be a bit to set up read-only,
+    #if 0 /* XXX: there should be a bit to set up read-only,
        *      the same way the hardware does (with WP pin).
        */
     pfl->ro = 1;
@@ -593,6 +758,7 @@
     pfl->ident[3] = id3;
     pfl->unlock_addr[0] = unlock_addr0;
     pfl->unlock_addr[1] = unlock_addr1;
+#ifndef USE_SIMPLE_TABLE 
     /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
     pfl->cfi_len = 0x52;
     /* Standard "QRY" string */
@@ -621,22 +787,22 @@
     pfl->cfi_table[0x1E] = 0x00;
     /* Reserved */
     pfl->cfi_table[0x1F] = 0x07;
-    /* Timeout for min size buffer write (NA) */
-    pfl->cfi_table[0x20] = 0x00;
+    /* Timeout for min size buffer write (16 s) */
+    pfl->cfi_table[0x20] = 0x04;
     /* Typical timeout for block erase (512 ms) */
     pfl->cfi_table[0x21] = 0x09;
     /* Typical timeout for full chip erase (4096 ms) */
     pfl->cfi_table[0x22] = 0x0C;
     /* Reserved */
     pfl->cfi_table[0x23] = 0x01;
-    /* Max timeout for buffer write (NA) */
-    pfl->cfi_table[0x24] = 0x00;
+    /* Max timeout for buffer write */
+    pfl->cfi_table[0x24] = 0x04;
     /* Max timeout for block erase */
     pfl->cfi_table[0x25] = 0x0A;
     /* Max timeout for chip erase */
     pfl->cfi_table[0x26] = 0x0D;
     /* Device size */
-    pfl->cfi_table[0x27] = ctz32(chip_len);
+    pfl->cfi_table[0x27] = ctz32(chip_len) + 1;
     /* Flash device interface (8 & 16 bits) */
     pfl->cfi_table[0x28] = 0x02;
     pfl->cfi_table[0x29] = 0x00;
@@ -652,7 +818,7 @@
     pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
     pfl->cfi_table[0x2F] = sector_len >> 8;
     pfl->cfi_table[0x30] = sector_len >> 16;
-
+    
     /* Extended */
     pfl->cfi_table[0x31] = 'P';
     pfl->cfi_table[0x32] = 'R';
@@ -660,7 +826,6 @@
 
     pfl->cfi_table[0x34] = '1';
     pfl->cfi_table[0x35] = '0';
-
     pfl->cfi_table[0x36] = 0x00;
     pfl->cfi_table[0x37] = 0x00;
     pfl->cfi_table[0x38] = 0x00;
@@ -670,6 +835,31 @@
 
     pfl->cfi_table[0x3b] = 0x00;
     pfl->cfi_table[0x3c] = 0x00;
+#else
+    /* Don't know why but driver expect this 
+     * Now this table have !to be 'interpolated' basing on width.
+     * Moreover we were called with width == 4. */
+    pfl->cfi_len = 0x80;
+    pfl->cfi_table[0x21] = 'Q';
+    pfl->cfi_table[0x23] = 'R';
+    pfl->cfi_table[0x25] = 'Y';
+    pfl->cfi_table[0x27] = 2;          /* oam command set */
+    pfl->cfi_table[0x4F] = 25;                 /* size = 2^x Bytes*/
+    pfl->cfi_table[0x59] = 1;          /* num of blocks   */
+    pfl->cfi_table[0x5b] = 255;                /*        sectors  */
+    pfl->cfi_table[0x61] = 2;          /* sector size     */
+#endif
 
-    return pfl;
+#if 0
+    /* Per reset initialization, GUEST related.
+     *
+     * Reset action is needed, since memory attribute is changed over the 
writing process
+     * @reset we address@hidden read from flash.
+     * Actually we stop all started action (reset chip)
+     */
+    pflash_cfi02_reset(pfl);
+    qemu_register_reset(&pflash_cfi02_reset, pfl);
+#endif
+    
+    return (pflash_t*)pfl;
 }
Index: hw/ppc405_uc.c
===================================================================
--- hw/ppc405_uc.c      (revision 5720)
+++ hw/ppc405_uc.c      (working copy)
@@ -21,6 +21,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include <assert.h>
 #include "hw.h"
 #include "ppc.h"
 #include "ppc405.h"
@@ -28,13 +29,17 @@
 #include "qemu-timer.h"
 #include "sysemu.h"
 #include "qemu-log.h"
+#include "net.h" /* To have nd_table.h */
 
+extern int loglevel;
+extern FILE *logfile;
+
 #define DEBUG_OPBA
 #define DEBUG_SDRAM
-#define DEBUG_GPIO
+/*#define DEBUG_GPIO*/
 #define DEBUG_SERIAL
 #define DEBUG_OCM
-//#define DEBUG_I2C
+/*#define DEBUG_I2C*/
 #define DEBUG_GPT
 #define DEBUG_MAL
 #define DEBUG_CLOCKS
@@ -835,6 +840,8 @@
             ret = 0x00000000;
             break;
         }
+       printf("Read ebc[%d]=>%x\n", ebc->addr, ret);
+       break;
     default:
         ret = 0x00000000;
         break;
@@ -853,6 +860,7 @@
         ebc->addr = val;
         break;
     case EBC0_CFGDATA:
+       printf("Write ebc[%d]=>%x\n", ebc->addr, val);
         switch (ebc->addr) {
         case 0x00: /* B0CR */
             break;
@@ -1395,7 +1403,37 @@
 }
 
 /*****************************************************************************/
-/* I2C controller */
+/* 
+ * I2C controller (SEE ALSO IN i2c.h before choice!!!)
+ *
+ * Control many device through uP resource.
+ * User could implement their device linked with this bus,
+ * specializing simple read(offset,value)/writec(offset,value)
+ * Only 7 bit address mode is supported.
+ */
+#define I2C_VER2
+/* Generic function like:
+ * hw/hw.h
+       * These should really be in isa.h, but are here to make pc.h happy.  *
+       typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t 
data);
+       typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
+ *
+ * cpu-all.h
+       typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, 
uint32_t value);
+       typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t 
addr);
+ *
+ * qemu-common.h
+       typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
+       typedef int IOCanRWHandler(void *opaque);
+       typedef void IOHandler(void *opaque);
+
+       typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, 
int size);
+
+   THERE !EXIST SIMPLE int read(int fd, const char* pos, int len), CREATE IT
+ */
+KRHandler* readF=NULL;
+KRHandler* writeF=NULL;
+
 typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
 struct ppc4xx_i2c_t {
     target_phys_addr_t base;
@@ -1415,21 +1453,82 @@
     uint8_t xfrcnt;
     uint8_t xtcntlss;
     uint8_t directcntl;
+
+    /* This is treated like a FIFO with same OPB beat (!implemented) */
+    uint8_t dataLen;
+    uint8_t data[4]; /* This is on PPC405GPr, uP dependent */
+    void* opaque;
 };
 
+/* 
+ * This method simulate the insertion of a byte on the bus,
+ * and acquisition in uP registers.
+ *
+ * Return number of readed bytes
+ * FIX: Should be linked to OPB clock
+ */
+static uint32_t ppc4xx_i2c_pushb (ppc4xx_i2c_t *i2c, uint8_t val)
+{
+       uint32_t ret = 0;
+
+       assert(i2c->dataLen<=sizeof(i2c->data));
+       /* Check if space */
+       if (i2c->dataLen<sizeof(i2c->data)) {
+               i2c->data[i2c->dataLen] = val;
+               i2c->dataLen++;
+               /* Signal to uP that data exist */
+               i2c->sts |= 0x20;
+               ret=1;
+       } else {
+               /* Signal to uP that no more space exist */
+               i2c->sts |= 0x10;
+       }
+       /* Always read a byte, also need different read/write cursor? */
+       return ret;
+}
+
+static uint8_t ppc4xx_i2c_popb (ppc4xx_i2c_t *i2c)
+{
+       uint8_t ret = 0;
+
+       assert(i2c->dataLen<=sizeof(i2c->data));
+       if (i2c->dataLen>0) {
+               uint8_t i;
+               ret = i2c->data[0];
+               i2c->dataLen--;
+               for (i=0; i<(sizeof(i2c->data)-1); i++)
+                       i2c->data[i] = i2c->data[i+1];
+       }
+
+       if (i2c->dataLen<=0) {
+               /* Signal to uP that no more data exist */
+               i2c->sts &= ~0x30;
+       }
+       return ret;
+}
+
 static uint32_t ppc4xx_i2c_readb (void *opaque, target_phys_addr_t addr)
 {
     ppc4xx_i2c_t *i2c;
     uint32_t ret;
 
+#if 0
 #ifdef DEBUG_I2C
     printf("%s: addr " PADDRX "\n", __func__, addr);
 #endif
+#endif
     i2c = opaque;
     switch (addr - i2c->base) {
     case 0x00:
+#ifndef I2C_VER2  
         //        i2c_readbyte(&i2c->mdata);
         ret = i2c->mdata;
+#else
+#ifdef DEBUG_I2C
+       printf("I2C read %x (hnd %p)\n", i2c->mdata, readF);
+#endif
+       ret = ppc4xx_i2c_popb(i2c);
+#endif
         break;
     case 0x02:
         ret = i2c->sdata;
@@ -1477,9 +1576,11 @@
         ret = 0x00;
         break;
     }
+#if 0
 #ifdef DEBUG_I2C
     printf("%s: addr " PADDRX " %02" PRIx32 "\n", __func__, addr, ret);
 #endif
+#endif
 
     return ret;
 }
@@ -1489,14 +1590,20 @@
 {
     ppc4xx_i2c_t *i2c;
 
+#if  0
 #ifdef DEBUG_I2C
     printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value);
 #endif
+#endif
     i2c = opaque;
     switch (addr - i2c->base) {
     case 0x00:
+#ifndef I2C_VER2  
         i2c->mdata = value;
         //        i2c_sendbyte(&i2c->mdata);
+#else
+       ppc4xx_i2c_pushb(i2c, (char)value);
+#endif
         break;
     case 0x02:
         i2c->sdata = value;
@@ -1509,6 +1616,62 @@
         break;
     case 0x06:
         i2c->cntl = value;
+#ifdef I2C_VER2
+       /* IIC0_CNTL (8bits)
+        * -----------------
+        * HMT  0x80    Halt master Transfer
+        * AMD  0x40    Address MoDe
+        * TCT  0x30    Transfer CounT
+        * RPST 0x08    RePeated STart
+        * CHT  0x04    CHain Tranfer
+        * RW   0x02    ReadWrite
+        * PT   0x01    PendingTransfer
+        *
+        * State/Action
+        * HMT RPSP     CHT     PT
+        * 0    -       -       0       No action
+        * 0    0       1       1       Start, Transfer, ACK on last byte, Pause
+        * 0    0       0       1                       NACK             , Stop
+        * 0    1       x       1                                        , Wait
+        * 1    x       x       x       NACK on current byte, Stop
+        */
+       if (value & 0x81) {
+               unsigned char len, lettu, aspe;
+               int addr;
+               size_t ret;
+               len = ((value >> 4) & 3) + 1;
+               lettu = (value & 2);
+               aspe = (value & 1);
+               addr = i2c->lmadr;
+               ret = 0;
+#ifdef DEBUG_I2C
+               printf("(I2C command len %d, %s, start %s pending transfer)\n", 
len, lettu?"READING":"WRITING", aspe?"only if not":"also if");
+#endif
+               assert(len<=sizeof(i2c->data));
+               if (lettu && readF) {
+                       ret = readF(addr, i2c->data, len);
+               }
+               if (!lettu && writeF) {
+                       ret = writeF(addr, i2c->data, len);
+               }
+#ifdef DEBUG_I2C
+               printf("User command return %d\n", ret);
+#endif
+               /* 
+                * on read from device  => Push bytes in uP buffer (simulate 
controller acquiring)
+                * on write ...         => Pop bytes from uP buffer (simulate 
device reading)
+                */
+               {
+                       unsigned int l;
+                       for (l=0; l<ret; l++) {
+                               lettu ?
+                                       ppc4xx_i2c_pushb(i2c, i2c->data[l]) :   
/* Produce data for uP */
+                                       ppc4xx_i2c_popb(i2c) ;                  
/* Consume data for uP */
+                       }
+
+               }
+       }
+#endif
         break;
     case 0x07:
         i2c->mdcntl = value & 0xDF;
@@ -1967,6 +2130,15 @@
     uint32_t rcbs[2];
 };
 
+/* TODO: need interaction between device!
+ * very difficult since all struct is in .c file */
+uint32_t txctpr[4];
+uint32_t rxctpr[2];
+uint32_t rcbs[2];
+uint32_t *rxeobisr;
+uint32_t *txeobisr;
+uint32_t *rxcasr;
+
 static void ppc40x_mal_reset (void *opaque);
 
 static target_ulong dcr_read_mal (void *opaque, int dcrn)
@@ -2067,21 +2239,29 @@
         mal->txcarr = val & 0xF0000000;
         break;
     case MAL0_TXEOBISR:
-        /* Read/clear */
-        mal->txeobisr &= ~val;
+        /* Read/clear TODO SEPARATE CHANNEL */
+       if (mal->txeobisr & val & 0xC0000000) {
+               mal->txeobisr &= ~val;
+               qemu_irq_lower(mal->irqs[0]);
+       }
+       mal->txeobisr &= ~val;
         break;
     case MAL0_TXDEIR:
         /* Read/clear */
         mal->txdeir &= ~val;
         break;
     case MAL0_RXCASR:
-        mal->rxcasr = val & 0xC0000000;
+        mal->rxcasr = val & ~0xC0000000; /* Active Set immediately rx channel 
*/
         break;
     case MAL0_RXCARR:
         mal->rxcarr = val & 0xC0000000;
         break;
     case MAL0_RXEOBISR:
         /* Read/clear */
+       if (mal->rxeobisr & val & 0x80000000) {
+               mal->rxeobisr &= ~val;
+               qemu_irq_lower(mal->irqs[1]);
+       }
         mal->rxeobisr &= ~val;
         break;
     case MAL0_RXDEIR:
@@ -2101,6 +2281,7 @@
         idx = 3;
     update_tx_ptr:
         mal->txctpr[idx] = val;
+       txctpr[idx] = val;
         break;
     case MAL0_RXCTP0R:
         idx = 0;
@@ -2109,6 +2290,7 @@
         idx = 1;
     update_rx_ptr:
         mal->rxctpr[idx] = val;
+        rxctpr[idx] = val;
         break;
     case MAL0_RCBS0:
         idx = 0;
@@ -2117,6 +2299,7 @@
         idx = 1;
     update_rx_size:
         mal->rcbs[idx] = val & 0x000000FF;
+        rcbs[idx] = val & 0x000000FF;
         break;
     }
 }
@@ -2135,6 +2318,10 @@
     mal->txcasr = 0x00000000;
     mal->txdeir = 0x00000000;
     mal->txeobisr = 0x00000000;
+
+    rxeobisr = &(mal->rxeobisr);
+    txeobisr = &(mal->txeobisr);
+    rxcasr = &(mal->rxcasr);
 }
 
 void ppc405_mal_init (CPUState *env, qemu_irq irqs[4])
@@ -2234,6 +2421,7 @@
     qemu_system_reset_request();
 }
 
+/* ->halted=1 seem that loose memory. */
 void store_40x_dbcr0 (CPUState *env, uint32_t val)
 {
     switch ((val >> 28) & 0x3) {
@@ -2891,7 +3079,8 @@
     }
 }
 
-CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
+CPUState *ppc405xp_init (const char* cpu_model,
+                         target_phys_addr_t ram_bases[2],
                          target_phys_addr_t ram_sizes[2],
                          uint32_t sysclk, qemu_irq **picp,
                          ram_addr_t *offsetp, int do_init)
@@ -2906,7 +3095,9 @@
 
     memset(clk_setup, 0, sizeof(clk_setup));
     /* init CPUs */
-    env = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK],
+    if (!cpu_model)
+           cpu_model = "405ep";
+    env = ppc4xx_init(cpu_model, &clk_setup[PPC405EP_CPU_CLK],
                       &tlb_clk_setup, sysclk);
     clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb;
     clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque;
@@ -2970,7 +3161,11 @@
     mal_irqs[2] = pic[13];
     mal_irqs[3] = pic[14];
     ppc405_mal_init(env, mal_irqs);
-    /* Ethernet */
+    /* EMAC (Ethernet Media Access Controller) */
+    {
+       void ppc4xx_emac_init(CPUState *env, ppc4xx_mmio_t *mmio, 
target_phys_addr_t offset, NICInfo* nic, qemu_irq irq[4]);
+       ppc4xx_emac_init(env, mmio, 0x800, &nd_table[0], mal_irqs);
+    }
     /* Uses pic[9], pic[15], pic[17] */
     /* CPU control */
     ppc405ep_cpc_init(env, clk_setup, sysclk);
Index: hw/ppc4xx_devs.c
===================================================================
--- hw/ppc4xx_devs.c    (revision 5720)
+++ hw/ppc4xx_devs.c    (working copy)
@@ -26,6 +26,7 @@
 #include "ppc4xx.h"
 #include "sysemu.h"
 #include "qemu-log.h"
+#include "qemu-timer.h"
 
 //#define DEBUG_MMIO
 //#define DEBUG_UNASSIGNED
@@ -296,10 +297,10 @@
     cr = uic->uicsr & uic->uicer & uic->uiccr;
 #ifdef DEBUG_UIC
     if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "%s: uicsr %08" PRIx32 " uicer %08" PRIx32
+        fprintf(logfile, "%s %" PRIu64 ": uicsr %08" PRIx32 " uicer %08" PRIx32
                 " uiccr %08" PRIx32 "\n"
                 "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
-                __func__, uic->uicsr, uic->uicer, uic->uiccr,
+                __func__, qemu_get_clock(rt_clock), uic->uicsr, uic->uicer, 
uic->uiccr,
                 uic->uicsr & uic->uicer, ir, cr);
     }
 #endif
@@ -366,9 +367,9 @@
     mask = 1 << (31-irq_num);
 #ifdef DEBUG_UIC
     if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "%s: irq %d level %d uicsr %08" PRIx32
+        fprintf(logfile, "%s %" PRIu64 ": irq %d level %d uicsr %08" PRIx32
                 " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
-                __func__, irq_num, level,
+                __func__, qemu_get_clock(rt_clock), irq_num, level,
                 uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
     }
 #endif
Index: hw/ppc405.h
===================================================================
--- hw/ppc405.h (revision 5720)
+++ hw/ppc405.h (working copy)
@@ -97,7 +97,8 @@
                          target_phys_addr_t ram_sizes[4],
                          uint32_t sysclk, qemu_irq **picp,
                          ram_addr_t *offsetp, int do_init);
-CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
+CPUState *ppc405xp_init (const char* cpu_model,
+                        target_phys_addr_t ram_bases[2],
                          target_phys_addr_t ram_sizes[2],
                          uint32_t sysclk, qemu_irq **picp,
                          ram_addr_t *offsetp, int do_init);
Index: hw/boards.h
===================================================================
--- hw/boards.h (revision 5720)
+++ hw/boards.h (working copy)
@@ -38,6 +38,7 @@
 extern QEMUMachine heathrow_machine;
 extern QEMUMachine ref405ep_machine;
 extern QEMUMachine taihu_machine;
+extern QEMUMachine walnut_machine;
 
 /* mips_r4k.c */
 extern QEMUMachine mips_machine;
Index: pc-bios/u-boot.bin
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: pc-bios/u-boot.bin
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream




      Unisciti alla community di Io fotografo e video, il nuovo corso di 
fotografia di Gazzetta dello sport:
http://www.flickr.com/groups/iofotografoevideo

Attachment: u-boot.bin.gz
Description: GNU Zip compressed data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]