qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Salvatore Lionetti <salvatorelionetti@yahoo.it>
To: Hollis Blanchard <hollis@penguinppc.org>
Cc: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] PowerPC 4xx enhacement
Date: Fri, 21 Nov 2008 01:53:20 +0000 (GMT)	[thread overview]
Message-ID: <169263.53603.qm@web27203.mail.ukl.yahoo.com> (raw)
In-Reply-To: <fb412d760811201542i7bcc14a7l919e16764819f73f@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 79205 bytes --]

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 salvatorelionetti@yahoo.it
+ *
+ * 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:
+ *
+ * Register@0xEF600000 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("RXdes@%p={len%d,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("TXdes@%p={len%d,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 handed@same 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 must@least 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 #2: u-boot.bin.gz --]
[-- Type: application/x-gzip, Size: 90030 bytes --]

  reply	other threads:[~2008-11-21  1:53 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-11-20 23:42 [Qemu-devel] PowerPC 4xx EMAC emulation Hollis Blanchard
2008-11-21  1:53 ` Salvatore Lionetti [this message]
2008-11-21 11:40   ` [Qemu-devel] PowerPC 4xx enhacement Jean-Christophe PLAGNIOL-VILLARD
2008-11-21 16:40   ` [Qemu-devel] DHT Walnut board support Hollis Blanchard
2008-11-21 17:09   ` [Qemu-devel] PowerPC 4xx EMAC emulation Hollis Blanchard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=169263.53603.qm@web27203.mail.ukl.yahoo.com \
    --to=salvatorelionetti@yahoo.it \
    --cc=hollis@penguinppc.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).