qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] TCG on PowerPC arch


From: Salvatore Lionetti
Subject: Re: [Qemu-devel] TCG on PowerPC arch
Date: Mon, 27 Oct 2008 15:29:08 +0000 (GMT)

Sure!

since i never created patch, also to reduce integration effort, i split patch 
in three activity (starting from 0.9.1):

- Activity [emac device] {hw/emac.c, hw/ppc405_uc.c}
  now ethernet, using vlan driver, work!
  Now ppc405GPr could be used as 405EP
  To test use ./qemu ... -net nic -net tap,ifname=qemu_network ...
- Activity [cfi flash] {hw/pflash_cfi02.c cpu-all.h}
  Intro 'buffer load mode'
- Activity [major fix] {vl.c hw/ppc.c}
  reset: unprogram PIT on chip, core, system reset
  focus: initial focus in monitor when load very great sized elf

I try to attach to svn view.
 
PATCH TO INTRODUCE EMAC (hw\emac.c, hw\ppc405_uc.c)
--- ../../qemu-0.9.1-orig/hw/emac.c     1970-01-01 01:00:00.000000000 +0100
+++ qemu-0.9.1/hw/emac.c        2008-10-16 19:14:43.706437000 +0200
@@ -0,0 +1,591 @@
+/*
+ * 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.
+ */
+#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("%s: " fmt , __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?)
+ */
+// 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 {
+#ifdef WORDS_BIGENDIAN
+#error "Host endianism BUG: To Test!!!"
+#else
+    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));
+#endif
+    unsigned short len;
+    unsigned char* buf;
+} __attribute__ ((packed)); /* Host endianism, to be converted */
+struct EmacMalTxDes {
+#ifdef WORDS_BIGENDIAN
+#error "Host endianism BUG: To Test!!!"
+#else
+    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;
+    };
+#endif
+    unsigned short len;
+    unsigned char* buf;
+}__attribute__ ((packed)); /* Host endianism, to be converted */
+
+
+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 EmacMalTxDes* tx;
+    struct EmacMalRxDes* rx;
+
+    int txPos, rxPos;
+    int txNum, rxNum;
+
+    int rxStarted, txStarted;
+    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) {
+       printf("address@hidden |%2.2X|%2X|%02X|%02X| len %d buf 
0x%p\n",des,((char*)des)[0], ((char*)des)[1], ((char*)des)[2], ((char*)des)[3], 
ntohs(des->len), (unsigned char*)ntohl((unsigned long int)des->buf));
+       printf("mal: empty%d wrap%d contm %d last%d first%d intr%d\n",
+                       des->mal.bit0_empty, des->mal.bit1_wrap, 
des->mal.bit2_contm, des->mal.bit3_last, des->mal.bit4_first, 
des->mal.bit5_intr);
+}
+void EmacMalTxDes_dump(struct EmacMalTxDes* des) {
+       printf("address@hidden |%2.2X|%2.2X|%02X|%02X| len %d buf 
0x%p\n",des,((char*)des)[0], ((char*)des)[1], ((char*)des)[2], ((char*)des)[3], 
des->len, des->buf);
+       printf("mal: ready%d wrap%d contm %d last%d first%d intr%d\n",
+                       des->mal.bit0_ready, des->mal.bit1_wrap, 
des->mal.bit2_contm, des->mal.bit3_last, des->mal.bit4_resv, 
des->mal.bit5_intr);
+}
+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;
+}
+
+#define MIN_BUF_SIZE 60
+
+static void emac_receive(void *opaque, const uint8_t *buf, int size)
+{
+    ppc4xx_emac_t* emac = (ppc4xx_emac_t*) opaque;
+
+#ifdef DEBUG_EMAC
+    EmacMalRxDes_dump(emac->rx);
+#endif
+    DPRINT("%d bytes\n", size);
+    if (emac->rxStarted) {
+    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 0x%p-> GUEST 0x%p,pos%d", 
dstH, dstG, emac->rxPos);*/
+                   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)
+                           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 load, too long for 1 rx des\n");
+    }
+    } else {
+           printf(" Driver !ready (buf==0)\n");
+    }
+    } else {
+           /*printf(" Driver !command rx start yet!!!\n");*/
+    }
+#if 0
+    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]);
+}
+
+static void ppc4xx_emac_reset (void *opaque)
+{
+    ppc4xx_emac_t *emac;
+
+    emac = opaque;
+    emac->rx = (struct EmacMalRxDes*) (phys_ram_base + 0x0000C000);
+    emac->tx = (struct EmacMalTxDes*) (phys_ram_base + 0x0000C000 + 16*8);
+    emac->txPos = emac->rxPos = 0;
+    emac->txNum = emac->rxNum = 0;
+    emac->rxStarted = emac->txStarted = 0;
+    emac->rxLostNum=0;
+    emac->rxLostLimit=1;
+}
+/* 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
+ */
+static uint32_t emac_readl (void *opaque, target_phys_addr_t addr)
+{
+       return STACR_OC;
+}
+
+static void emac_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+       ppc4xx_emac_t* emac = (ppc4xx_emac_t*)opaque;
+
+/*     printf("%s: " PADDRX " val %x\n",__func__, addr, value);*/
+       if (addr-emac->base==0) {
+               /* soft reset */
+               if (value & 0x20000000) {
+                       printf("emac: soft reset commanded!\n");
+                       ppc4xx_emac_reset(emac); /* Should be protected with a 
semaphore, also in emac_receive()? */
+               }
+               /* rx enable */
+               if (value & 0x08000000) {
+                       emac->rxStarted=1;
+                       printf("emac: rx started!\n");
+               }
+               /* tx enable */
+               if (value & 0x10000000) {
+                       emac->txStarted=1;
+                       printf("emac: tx started!\n");
+                       /* A timer that periodically check packet to send 
+                       emac->tx_timer = qemu_new_timer();*/
+               }
+       }
+       if (addr-emac->base==8) {
+               if (value & 0x80000000) {
+                       if (emac->txStarted==1) {
+                       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);
+                               if (emac->tx[emac->txPos].mal.bit5_intr)
+                                       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;
+                       } else {printf("Processor goes crazy(ready bit was 
0)!!! Stopping tx\n");emac->txStarted=2;}
+                       } else {if (emac->txStarted!=2) printf("Tx is 
disabled\n");}
+               }
+       }
+}
+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[3];
+       emac->mal_irqs_rxeob = mal_irqs[2];
+       emac->mal_irqs_txerr = mal_irqs[1];
+       emac->mal_irqs_rxerr = mal_irqs[0];
+
+       /* N Time configuration, GUEST related */
+        ppc4xx_emac_reset(emac);
+    }
+}
--- ../../qemu-0.9.1-orig/hw/ppc405_uc.c        2008-01-06 19:38:42.000000000 
+0100
+++ qemu-0.9.1/hw/ppc405_uc.c   2008-10-27 14:31:30.975942500 +0100
@@ -21,12 +21,14 @@
  * 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"
 #include "pc.h"
 #include "qemu-timer.h"
 #include "sysemu.h"
+#include "net.h" /* To have nd_table.h */
 
 extern int loglevel;
 extern FILE *logfile;
@@ -1994,7 +1996,7 @@ static target_ulong dcr_read_mal (void *
         ret = mal->txcarr;
         break;
     case MAL0_TXEOBISR:
-        ret = mal->txeobisr;
+        ret = (target_ulong)-1/*mal->txeobisr TODO RESTORE WHEN EMAC LINK WAS 
INTERACTING WITH MAL */;
         break;
     case MAL0_TXDEIR:
         ret = mal->txdeir;
@@ -2189,6 +2191,7 @@ void ppc405_mal_init (CPUState *env, qem
         ppc_dcr_register(env, MAL0_RCBS1,
                          mal, &dcr_read_mal, &dcr_write_mal);
     }
+/*    return mal;*/
 }
 
 /*****************************************************************************/
@@ -2281,6 +2284,15 @@ enum {
     PPC405CR_CLK_NB    = 7,
 };
 
+/* Addedum related to 405GPr approximated as 405EP + CR0 */
+static target_ulong dcr_read_cr0 (void *opaque, int dcrn)
+{
+       return 0;
+}
+static void dcr_write_cr0 (void *opaque, int dcrn, target_ulong val)
+{
+}
+
 typedef struct ppc405cr_cpc_t ppc405cr_cpc_t;
 struct ppc405cr_cpc_t {
     clk_setup_t clk_setup[PPC405CR_CLK_NB];
@@ -2540,6 +2552,7 @@ static void ppc405cr_cpc_init (CPUState 
     }
 }
 
+#define INTN(a) (31-a)
 CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
                          target_phys_addr_t ram_sizes[4],
                          uint32_t sysclk, qemu_irq **picp,
@@ -2892,7 +2905,7 @@ static void ppc405ep_cpc_init (CPUState 
 #endif
     }
 }
-
+qemu_irq _mal_irqs[4];
 CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
                          target_phys_addr_t ram_sizes[2],
                          uint32_t sysclk, qemu_irq **picp,
@@ -2930,51 +2943,63 @@ CPUState *ppc405ep_init (target_phys_add
     pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
     *picp = pic;
     /* SDRAM controller */
-    ppc405_sdram_init(env, pic[14], 2, ram_bases, ram_sizes, do_init);
+    ppc405_sdram_init(env, pic[INTN(17)]/* Ecc?*/, 2, ram_bases, ram_sizes, 
do_init);
     offset = 0;
     for (i = 0; i < 2; i++)
         offset += ram_sizes[i];
     /* External bus controller */
     ppc405_ebc_init(env);
     /* DMA controller */
-    dma_irqs[0] = pic[26];
-    dma_irqs[1] = pic[25];
-    dma_irqs[2] = pic[24];
-    dma_irqs[3] = pic[23];
+    dma_irqs[0] = pic[INTN(5)];
+    dma_irqs[1] = pic[INTN(6)];
+    dma_irqs[2] = pic[INTN(7)];
+    dma_irqs[3] = pic[INTN(8)];
     ppc405_dma_init(env, dma_irqs);
     /* IIC controller */
-    ppc405_i2c_init(env, mmio, 0x500, pic[29]);
+    ppc405_i2c_init(env, mmio, 0x500, pic[INTN(2)]);
     /* GPIO */
     ppc405_gpio_init(env, mmio, 0x700);
     /* Serial ports */
     if (serial_hds[0] != NULL) {
-        ppc405_serial_init(env, mmio, 0x300, pic[31], serial_hds[0]);
+        ppc405_serial_init(env, mmio, 0x300, pic[INTN(0)], serial_hds[0]);
     }
     if (serial_hds[1] != NULL) {
-        ppc405_serial_init(env, mmio, 0x400, pic[30], serial_hds[1]);
+        ppc405_serial_init(env, mmio, 0x400, pic[INTN(1)], serial_hds[1]);
     }
     /* OCM */
     ppc405_ocm_init(env, ram_sizes[0] + ram_sizes[1]);
     offset += 4096;
     /* GPT */
-    gpt_irqs[0] = pic[12];
-    gpt_irqs[1] = pic[11];
-    gpt_irqs[2] = pic[10];
-    gpt_irqs[3] = pic[9];
-    gpt_irqs[4] = pic[8];
+    gpt_irqs[0] = pic[INTN(19)];
+    gpt_irqs[1] = pic[INTN(20)];
+    gpt_irqs[2] = pic[INTN(21)];
+    gpt_irqs[3] = pic[INTN(22)];
+    gpt_irqs[4] = pic[INTN(23)];
     ppc4xx_gpt_init(env, mmio, 0x000, gpt_irqs);
     /* PCI */
     /* Uses pic[28], pic[15], pic[13] */
     /* MAL */
-    mal_irqs[0] = pic[20];
-    mal_irqs[1] = pic[19];
-    mal_irqs[2] = pic[18];
-    mal_irqs[3] = pic[17];
+    mal_irqs[3] = pic[INTN(11)];
+    mal_irqs[2] = pic[INTN(12)];
+    mal_irqs[1] = pic[INTN(13)];
+    mal_irqs[0] = pic[INTN(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[22], pic[16], pic[14] */
     /* CPU control */
     ppc405ep_cpc_init(env, clk_setup, sysclk);
+
+    /* Add address@hidden DCR: opaque represent integer of value */
+    ppc_dcr_register(env, PPC405CR_CPC0_CR0, NULL, &dcr_read_cr0, 
&dcr_write_cr0);
+    /* This is typical of 405GPr. CPC0_ECR = 0xAA.*/
+    ppc_dcr_register(env, 0xAA/* CPC0_ECR */, NULL, &dcr_read_cr0, 
&dcr_write_cr0);
+    ppc_dcr_register(env, 0xB2/* CPC0_CR1 */, NULL, &dcr_read_cr0, 
&dcr_write_cr0);
+    
     *offsetp = offset;
 
     return env;

===================================================================
=== PATCH TO ENHACE FLASH DEVICE (hw\pflash_cfi02.c, cpu-all.h) ===
===================================================================

--- qemu-0.9.1-orig/cpu-all.h   2008-01-06 19:38:42.000000000 +0100
+++ qemu-0.9.1/cpu-all.h        2008-06-11 13:34:24.222465500 +0200
@@ -773,6 +773,8 @@ target_phys_addr_t cpu_get_phys_page_deb
 #define CPU_LOG_PCALL      (1 << 6)
 #define CPU_LOG_IOPORT     (1 << 7)
 #define CPU_LOG_TB_CPU     (1 << 8)
+#define FLASH_LOG_CFI      (1 << 9)
+#define FPGA_LOG_ACCESS    (1 << 10)
 
 /* define log items */
 typedef struct CPULogItem {
--- qemu-0.9.1-orig/hw/pflash_cfi02.c   2008-01-06 19:38:42.000000000 +0100
+++ qemu-0.9.1/hw/pflash_cfi02.c        2008-10-27 14:51:52.827229100 +0100
@@ -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,24 +35,33 @@
  * 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
+static int howt=0;
 #define DPRINTF(fmt, args...)                      \
 do {                                               \
-        printf("PFLASH: " fmt , ##args);           \
+        if (loglevel & FLASH_LOG_CFI) {printf("PFLASH: " fmt , ##args);}       
    \
+       howt++;                                    \
 } while (0)
 #else
 #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;
@@ -59,21 +69,77 @@ struct pflash_t {
     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];
     uint8_t cfi_len;
-    uint8_t cfi_table[0x52];
+    uint8_t cfi_table[0x80];
     QEMUTimer *timer;
     ram_addr_t off;
     int fl_mem;
     void *storage;
+
+    /* 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;
+
+    int how_memory_mapped; /* 
+                                                       memory_mapped
+                         Reset=> off|fl_mem|ROMD,      0
+                       * timer=> off|fl_mem|ROMD,      0
+                       * write=>     fl_mem            1
+                       *
+                       * off costante
+                       * fl_mem costante (rif all'io costruito, f() di rw...)
+                       */
 };
 
+static void pflash_cfi02_core_reset (void *opaque) {
+    struct pflash_cfi02_t *pfl = (struct pflash_cfi02_t*)opaque;
+
+    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? */
+
+    pfl->how_memory_mapped = 0;
+    
+    cpu_register_physical_memory(pfl->base, pfl->total_len,
+                                 pfl->off | pfl->fl_mem | IO_MEM_ROMD);
+}
+
+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
+    pfl->bypass = 0;
+    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 */
@@ -81,27 +147,29 @@ static void pflash_timer (void *opaque)
     if (pfl->bypass) {
         pfl->wcycle = 2;
     } else {
+       if (pfl->how_memory_mapped) {
         cpu_register_physical_memory(pfl->base, pfl->total_len,
                                      pfl->off | IO_MEM_ROMD | pfl->fl_mem);
+       pfl->how_memory_mapped = 0;
+       }
         pfl->wcycle = 0;
     }
     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;
-    boff = offset & 0xFF;
+    _boff = offset & 0xFF;
     if (pfl->width == 2)
-        boff = boff >> 1;
+        boff = _boff >> 1;
     else if (pfl->width == 4)
-        boff = boff >> 2;
+        boff = _boff >> 2;
     switch (pfl->cmd) {
     default:
         /* This should never happen : reset state & treat it as a read*/
@@ -114,32 +182,34 @@ static uint32_t pflash_read (pflash_t *p
     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;
@@ -177,32 +247,80 @@ static uint32_t pflash_read (pflash_t *p
         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;
 }
 
-/* update flash content on disk */
-static void pflash_update(pflash_t *pfl, int offset,
+/* 
+ * 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;
-    if (pfl->bs) {
-        offset_end = offset + size;
-        /* round to sectors */
-        offset = offset >> 9;
-        offset_end = (offset_end + 511) >> 9;
-        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
-                   offset_end - offset);
-    }
+       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);
+               }
+       }
 }
-
-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;
@@ -212,29 +330,35 @@ static void pflash_write (pflash_t *pfl,
     /* WARNING: when the memory area is in ROMD mode, the offset is a
        ram offset, not a physical address */
     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);
+
     if (pfl->wcycle == 0)
         offset -= (uint32_t)(long)pfl->storage;
-    else
+    else {
+       DPRINTF("PFLASH_WRITE - 0xFE000000:\n");
         offset -= pfl->base;
+    }
 
-    DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__,
-            offset, value, width);
     /* Set the device in I/O access mode */
+    if (pfl->how_memory_mapped==0) {
     cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
+    pfl->how_memory_mapped = 1;
+    }
     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:
         /* We're in read mode */
@@ -246,26 +370,40 @@ static void pflash_write (pflash_t *pfl,
             pfl->cmd = 0x98;
             return;
         }
-        if (boff != 0x555 || cmd != 0xAA) {
+        if (!(boff == 0x555 || boff == 0x5555) || cmd != 0xAA) {
             DPRINTF("%s: unlock0 failed " TARGET_FMT_lx " %02x %04x\n",
                     __func__, boff, cmd, 0x555);
             goto reset_flash;
         }
         DPRINTF("%s: unlock sequence started\n", __func__);
+       pfl->wcycle++;
         break;
     case 1:
         /* We started an unlock sequence */
     check_unlock1:
-        if (boff != 0x2AA || cmd != 0x55) {
+        if (!(boff == 0x2AA || 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 != 0x555) {
+        if (!pfl->bypass && (boff != 0x555 && boff != 0x5555)) {
             DPRINTF("%s: command failed " TARGET_FMT_lx " %02x\n", __func__,
                     boff, cmd);
             goto reset_flash;
@@ -273,23 +411,34 @@ static void pflash_write (pflash_t *pfl,
         switch (cmd) {
         case 0x20:
             pfl->bypass = 1;
+            printf("Requesting bypass\n");
             goto do_bypass;
         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);
@@ -297,7 +446,7 @@ static void pflash_write (pflash_t *pfl,
             switch (width) {
             case 1:
                 p[offset] &= value;
-                pflash_update(pfl, offset, 1);
+                if (pfl->cmd!=0x25) pflash_update(pfl, offset, 1);
                 break;
             case 2:
 #if defined(TARGET_WORDS_BIGENDIAN)
@@ -307,7 +456,7 @@ static void pflash_write (pflash_t *pfl,
                 p[offset] &= value;
                 p[offset + 1] &= value >> 8;
 #endif
-                pflash_update(pfl, offset, 2);
+                if (pfl->cmd!=0x25) pflash_update(pfl, offset, 2);
                 break;
             case 4:
 #if defined(TARGET_WORDS_BIGENDIAN)
@@ -321,14 +470,27 @@ static void pflash_write (pflash_t *pfl,
                 p[offset + 2] &= value >> 16;
                 p[offset + 3] &= value >> 24;
 #endif
-                pflash_update(pfl, offset, 4);
+                if (pfl->cmd!=0x25) 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 */
@@ -343,6 +505,8 @@ static void pflash_write (pflash_t *pfl,
                     __func__, pfl->cmd);
             goto reset_flash;
         }
+       pfl->wcycle++;
+       break;
     case 4:
         switch (pfl->cmd) {
         case 0xA0:
@@ -351,6 +515,13 @@ static void pflash_write (pflash_t *pfl,
             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",
@@ -384,9 +555,10 @@ static void pflash_write (pflash_t *pfl,
             memset(p + offset, 0xFF, pfl->sector_len);
             pflash_update(pfl, offset, pfl->sector_len);
             pfl->status = 0x00;
-            /* Let's wait 1/2 second before sector erase is done */
+            /* Let's wait 1/2 second before sector erase is done
             qemu_mod_timer(pfl->timer,
-                           qemu_get_clock(vm_clock) + (ticks_per_sec / 2));
+                           qemu_get_clock(vm_clock) + (ticks_per_sec / 2));*/
+           pflash_timer(pfl);
             break;
         default:
             DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
@@ -417,17 +589,11 @@ static void pflash_write (pflash_t *pfl,
         DPRINTF("%s: invalid write state (wc 7)\n",  __func__);
         goto reset_flash;
     }
-    pfl->wcycle++;
-
     return;
 
     /* Reset flash */
  reset_flash:
-    cpu_register_physical_memory(pfl->base, pfl->total_len,
-                                 pfl->off | IO_MEM_ROMD | pfl->fl_mem);
-    pfl->bypass = 0;
-    pfl->wcycle = 0;
-    pfl->cmd = 0;
+    pflash_cfi02_core_reset(pfl);
     return;
 
  do_bypass:
@@ -444,14 +610,14 @@ static uint32_t pflash_readb (void *opaq
 
 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);
 }
@@ -465,7 +631,7 @@ static void pflash_writeb (void *opaque,
 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);
 }
@@ -473,7 +639,7 @@ static void pflash_writew (void *opaque,
 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);
 }
@@ -490,6 +656,7 @@ static CPUReadMemoryFunc *pflash_read_op
     &pflash_readl,
 };
 
+#ifndef USE_SIMPLE_TABLE
 /* Count trailing zeroes of a 32 bits quantity */
 static int ctz32 (uint32_t n)
 {
@@ -523,14 +690,14 @@ static int ctz32 (uint32_t n)
 
     return ret;
 }
-
-pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
+#endif
+void *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
                                 BlockDriverState *bs, uint32_t sector_len,
                                 int nb_blocs, int width,
                                 uint16_t id0, uint16_t id1,
                                 uint16_t id2, uint16_t id3)
 {
-    pflash_t *pfl;
+    struct pflash_cfi02_t *pfl;
     int32_t total_len;
 
     total_len = sector_len * nb_blocs;
@@ -540,39 +707,31 @@ pflash_t *pflash_cfi02_register(target_p
         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);
     pfl->off = off;
-    cpu_register_physical_memory(base, total_len,
-                                 off | pfl->fl_mem | IO_MEM_ROMD);
-    pfl->bs = bs;
-    if (pfl->bs) {
-        /* read the initial flash content */
-        bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
-    }
-#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
     pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
     pfl->base = base;
     pfl->sector_len = sector_len;
     pfl->total_len = total_len;
     pfl->width = width;
-    pfl->wcycle = 0;
-    pfl->cmd = 0;
-    pfl->status = 0;
+
+    pfl->bs = bs;
+    if (pfl->bs) {
+        /* read the initial flash content */
+        bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
+    }
     pfl->ident[0] = id0;
     pfl->ident[1] = id1;
     pfl->ident[2] = id2;
     pfl->ident[3] = id3;
+#ifndef USE_SIMPLE_TABLE 
     /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
     pfl->cfi_len = 0x52;
     /* Standard "QRY" string */
@@ -632,6 +791,29 @@ pflash_t *pflash_cfi02_register(target_p
     pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
     pfl->cfi_table[0x2F] = sector_len >> 8;
     pfl->cfi_table[0x30] = sector_len >> 16;
+#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
 
+    /* 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);
+    
     return pfl;
 }


This is a list of all file modified, just to describe all modification done.

Modified file in private view:
cpu-all.h
- Add flag

exec.c
- Change in log filename
- help message for new flag

exec-all.h
- Add logfilename as extern

vl.c
- change /tmp/... in (char*)logfilename

hw/pflash_cfi02.c
- Add 'buffer load mode'
- Some optimization in write

hw/ppc.c
- On uP reset, cancel any pending WDT, PIT, FIT

hw/ppc405_uc.c
- Change in bcr from FFE28000 -> FE0A2000
- Change ocm from qemu code
- I2C controller now have hook to call board specific behaviour
- 405GPr approximated as 405EP + CR0
- ppc405cr_init() now return a list of created device,
  so in qemu code one can interact with they (es ocm, bcr)
- in ppc405ep_init() start EMAC layer, to have networking

hw\emac.c
- Simulate EMAC, a 'FastEthController' for ppc405GPr uP, only on LittleEndian 
host.

target-ppc\translate.c
- Enable some bad access to !existing spr, unassigned memroy region (no machine 
{data|instruction} exception start yet)

Have a good day

--- Sab 25/10/08, Andreas Färber <address@hidden> ha scritto:

> Da: Andreas Färber <address@hidden>
> Oggetto: Re: [Qemu-devel] TCG on PowerPC arch
> A: "Salvatore Lionetti" <address@hidden>
> Cc: address@hidden
> Data: Sabato 25 ottobre 2008, 22:51
> Hi,
> 
> Am 22.10.2008 um 10:18 schrieb Salvatore Lionetti:
> 
> > There need help about TCG porting on PowerPC?
> > I'm moderating skilled on PowerPC ASM, expecially
> on PPC405GPr
> > For this last uP, i've build a board so could also
> test result.
> 
> What about your previous ppc patch? Have you had time to
> rework it
> yet, so that it can be applied?
> 
> Regards,
> Andreas


      Scopri il blog di Yahoo! Mail:
Trucchi, novità e scrivi la tua opinione.
http://www.ymailblogit.com/blog




reply via email to

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