From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KuU1q-0007qc-F1 for qemu-devel@nongnu.org; Mon, 27 Oct 2008 11:29:14 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KuU1n-0007pt-Qh for qemu-devel@nongnu.org; Mon, 27 Oct 2008 11:29:12 -0400 Received: from [199.232.76.173] (port=43536 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KuU1n-0007pq-LW for qemu-devel@nongnu.org; Mon, 27 Oct 2008 11:29:11 -0400 Received: from web27202.mail.ukl.yahoo.com ([217.146.182.92]:42296) by monty-python.gnu.org with smtp (Exim 4.60) (envelope-from ) id 1KuU1m-0002oQ-VX for qemu-devel@nongnu.org; Mon, 27 Oct 2008 11:29:11 -0400 Date: Mon, 27 Oct 2008 15:29:08 +0000 (GMT) From: Salvatore Lionetti Subject: Re: [Qemu-devel] TCG on PowerPC arch In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: quoted-printable Message-ID: <210736.85874.qm@web27202.mail.ukl.yahoo.com> Reply-To: salvatorelionetti@yahoo.it, qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: =?iso-8859-1?Q?Andreas_F=E4rber?= Cc: qemu-devel@nongnu.org Sure! since i never created patch, also to reduce integration effort, i split pat= ch 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=3Dqemu_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. =20 PATCH TO INTRODUCE EMAC (hw\emac.c, hw\ppc405_uc.c) --- ../../qemu-0.9.1-orig/hw/emac.c=091970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1/hw/emac.c=092008-10-16 19:14:43.706437000 +0200 @@ -0,0 +1,591 @@ +/* + * 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"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * 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 OT= HER + * 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=20 + +/*=20 + * 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)) || ((!de= fined(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) { +=09return ing; +} +static unsigned short int ntohs(unsigned short int ing) { +=09return ing; +} +#else +static unsigned long int ntohl(unsigned long int ing) { +=09unsigned char tmp; +=09unsigned char* tmpp =3D (unsigned char*)&ing; +=09tmp=3Dtmpp[0]; tmpp[0]=3Dtmpp[3]; tmpp[3]=3Dtmp; +=09tmp=3Dtmpp[1]; tmpp[1]=3Dtmpp[2]; tmpp[2]=3Dtmp; +=09return *(unsigned long int*)tmpp; +} +static unsigned short int ntohs(unsigned short int ing) { +=09return ((ing&0xFF)<<8) | ((ing&0xFF00)>>8); +} +#endif + +/* qemu initialization: + * + * parse command line:=09call net_client_init() for each -net, either for = {if, collision domain} options. + * =09=09=09=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=09=09=09=09=09=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * =09=09=09IF MAC=3D...=09<=3D=3D=3D=3D Vlan{Id,Ptr} =3D=3D=3D=3D>=09COLL= ISION DOMAIN (mean N-1 other IF MAC=3D...) + * =09=09=09=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =09=09=09=09=09=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * =09=09=09=09-net nic[,...]:=09fill field onto nd_table[] {MAC(cl|auto),= model, vlanPtr=3Df(vlanId)} + * =09=09=09=09=09=09vlanPtr=3Df(vlanId)->guest++ + * =09=09=09=09-net tap[,...]: vlanPtr=3Df(vlanId)->host ++ + * =09=09=09=09=09=09tap_win32_init(vlanPtr, "ifname=3Dtap..."): + * =09=09=09=09=09=09=09qemu_new_vlan_client(vlanPtr,tap_receive, tap* opa= que)=09=09RECV + * =09=09=09=09=09=09=09qemu_add_wait_object(tap_sem, tap_w32_send, tap* o= paque)=09SEND + * =09=09=09 + * =09=09=09For each vlan created, + * =09=09=09=09exit if no GUEST & some HOST + * =09=09=09=09warn if some GUEST & no HOST + * =09=09=09=09=09=09=09=09=09=09=09 =20 + * start machine:=09Es ppc (also pc use n2000) call machine->init(): + * =09=09=09isa_ne2000_init(base, irqno, &nd_table[i]) + * =09=09=09=09register_ioport_write(base + ..., ne2000_asic_ioport_write,= opaque NE2000State*);=09SEND + * =09=09=09=09qemu_new_vlan_client(nd->vlan, ne2000_receive, ne2000_can_r= eceive, opaque NE2000State*) RECV + * + * Done!!! + * + * qemu runtime scenario: + * + * packet send from HOST:=09a signal (after exec() cycle) is sent to tap_s= em =3D> tap_w32_send() =3D> tap_win32_read() + * =09=09=09=09if some bytes returned =3D> qemu_send_packet() =3D> send to= all 'client' (better peer) of + * =09=09=09=09such vlan, different from itself =3D> ne2000_receive() + * + * packet send from GUEST:=09in machine code we call qemu_send_packet() = =3D> (prec) =3D> tap_receive() =3D> 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): + * =09[EMAC0_STACR] <=3D (STACR_STAC_R | ind) + *=09[EMAC0_STACR] & STACR_OC must goes to 0 + *=09[EMAC0_STACR] =3D> >>16 =3D> data + * + * Write(ind, data) + * =09[EMAC0_STACR] <=3D (STACR_STAC_W | ind | data<<16) + * =09[EMAC0_STACR] & STACR_OC must goes to 0 + * + * Physical access: + * Read(ind_phy, ind_reg, data) + * =09[EMAC0_STACR] <=3D (STACR_STAC_W | TANTOS_REG_MIIAC | (ind_reg&0x1F = | OP_READ | (ind_phy&0x1F)<<5))>>16 + * =09[EMAC0_STACR] & STACR_OC must goes to 0 + *=09 + *=09Verify: + *=09[EMAC0_STACR] <=3D (STACR_STAC_R | TANTOS_REG_MIIRD) + * =09[EMAC0_STACR] & STACR_OC must goes to 0 + * =09[EMAC0_STACR] =3D> data + * =09data & STACR_PHYE should be 0 + * =09data=3Ddata>>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 address= ing */ +#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 reg= isters +#define TANTOS_REG_MIIWD 0x121 +#define TANTOS_REG_MIIRD 0x122 +#define OP_WRITE=090x0400 +#define OP_READ=09=090x0800 +#define MBUSY =09=090x8000 + +/* WORDS_BIGENDIAN =3D 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 { +=09 struct { /* Mal */ +=09=09 unsigned int emac1_nu=09: 2; +=09=09 unsigned int bit5_intr=09: 1; +=09=09 unsigned int bit4_first=09: 1; +=09=09 unsigned int bit3_last=09: 1; +=09=09 unsigned int bit2_contm=09: 1; +=09=09 unsigned int bit1_wrap=09: 1; +=09=09 unsigned int bit0_empty=09: 1; +=09=09 unsigned int emac2_nu=09: 8;=20 +=09 } __attribute__ ((packed)) mal; +=09 struct { /* Status: Read access, error cause */ +=09=09 unsigned int bit7_pausepacket=09: 1; +=09=09 unsigned int bit6_overrun=09=09: 1; +=09=09 unsigned int mal_nu=09=09=09: 6; +=09=09 unsigned int bit15_inrange=09=09: 1; +=09=09 unsigned int bit14_outrange=09=09: 1; +=09=09 unsigned int bit13_longpacket=09: 1; +=09=09 unsigned int bit12_fcs=09=09: 1; +=09=09 unsigned int bit11_alignment=09: 1; +=09=09 unsigned int bit10_shortevent=09: 1; +=09=09 unsigned int bit9_runtpacket=09: 1; +=09=09 unsigned int bit8_badpacket=09=09: 1; +=09 } __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 { +=09 struct { /* Mal */ +=09=09 unsigned int emac1_nu=09: 2; +=09=09 unsigned int bit5_intr=09: 1; +=09=09 unsigned int bit4_resv=09: 1; +=09=09 unsigned int bit3_last=09: 1; +=09=09 unsigned int bit2_contm=09: 1; +=09=09 unsigned int bit1_wrap=09: 1; +=09=09 unsigned int bit0_ready=09: 1; +=09=09 unsigned int emac2_nu=09: 8;=20 +=09 } __attribute__ ((packed)) mal; +=09 struct { /* Status: Read access, error cause */ +=09=09 unsigned int bit7_badpacket=09=09: 1; +=09=09 unsigned int bit6_badfsc=09=09: 1; +=09=09 unsigned int mal_nu=09=09=09: 6; +=09=09 unsigned int bit15_sqe=09=09: 1; +=09=09 unsigned int bit14_underrun=09=09: 1; +=09=09 unsigned int bit13_singlecoll=09: 1; +=09=09 unsigned int bit12_multiplecoll=09: 1; +=09=09 unsigned int bit11_latecoll=09=09: 1; +=09=09 unsigned int bit10_excessivecoll=09: 1; +=09=09 unsigned int bit9_excessivedeferral : 1; +=09=09 unsigned int bit8_lossofcarrier=09: 1; +=09 } __attribute__ ((packed)) emac_errorstatus; +=09 struct { /* Control: Write access */ +=09=09 unsigned int bit7_generatepad=09: 1; +=09=09 unsigned int bit6_generatefcs=09: 1; +=09=09 unsigned int mal_nu=09=09=09: 6; +=09=09 unsigned int emac_nu=09=09: 4; +=09=09 unsigned int bit11_vlantag_replace=09: 1; +=09=09 unsigned int bit10_vlantag_insert=09: 1; +=09=09 unsigned int bit9_sourceaddr_insert=09: 1; +=09=09 unsigned int bit8_sourceaddr_replace: 1; +=09 } __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 =3D ntohs(guest->status); + host->len =3D ntohs(guest->len); + host->buf =3D htol(guest->buf); +} +void EmacMalDes_writeToTarget(struct EmacMalDes* host, struct EmacMalDes* = guest) { +} +#endif +void EmacMalRxDes_dump(struct EmacMalRxDes* des) { +=09printf("des@0x%p |%2.2X|%2X|%02X|%02X| len %d buf 0x%p\n",des,((char*)d= es)[0], ((char*)des)[1], ((char*)des)[2], ((char*)des)[3], ntohs(des->len),= (unsigned char*)ntohl((unsigned long int)des->buf)); +=09printf("mal: empty%d wrap%d contm %d last%d first%d intr%d\n", +=09=09=09des->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) { +=09printf("des@0x%p |%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); +=09printf("mal: ready%d wrap%d contm %d last%d first%d intr%d\n", +=09=09=09des->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 =3D s->curpag << 8; + boundary =3D s->boundary << 8; + if (index < boundary) + avail =3D boundary - index; + else + avail =3D (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 =3D 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 =3D (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) { +=09 if (emac->rx[emac->rxPos].mal.bit0_empty) { +=09 /* data is allocated with the maximum possible length, on eth =3D 1= 520Bytes +=09 * len field represent packet size.*/ +=09=09 /* We !use Continuos mode, first & last field ignored */ +=09=09 unsigned char* dstG =3D (unsigned char*) ntohl((unsigned long in= t)emac->rx[emac->rxPos].buf); +=09=09 unsigned char* dstH=3D dstG+(unsigned int)phys_ram_base; +=09=09 unsigned short size16 =3D size; +/*=09=09 DPRINT(" Delivery message HOST 0x%p-> GUEST 0x%p,pos%d", dstH,= dstG, emac->rxPos);*/ +=09=09 memcpy(dstH, buf, size);=09 +=09=09 emac->rx[emac->rxPos].len =3D ntohs(size16); +=09=09 emac->rx[emac->rxPos].mal.bit0_empty =3D 0; +=09=09 if (emac->rx[emac->rxPos].mal.bit5_intr) +=09=09=09 qemu_irq_raise(emac->mal_irqs_rxeob); + +=09=09 emac->rxPos +=3D (emac->rx[emac->rxPos].mal.bit1_wrap)? -(emac->= rxPos) : 1; +=09 } else { +=09=09 if (++emac->rxLostNum =3D=3D emac->rxLostLimit) { +=09=09=09 printf(" %d Message lost, board seem hung up!\n", emac->rxLos= tNum); +=09=09=09 emac->rxLostLimit*=3D10; +=09=09 } +=09 } + } else { +=09 printf(" Message load, too long for 1 rx des\n"); + } + } else { +=09 printf(" Driver !ready (buf=3D=3D0)\n"); + } + } else { +=09 /*printf(" Driver !command rx start yet!!!\n");*/ + } +#if 0 + NE2000State *s =3D 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] =3D + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +#if defined(DEBUG_NE2000) + printf("NE2000: received len=3D%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 =3D compute_mcast_idx(buf); + if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) + return; + } else if (s->mem[0] =3D=3D buf[0] && + s->mem[2] =3D=3D buf[1] && + s->mem[4] =3D=3D buf[2] && + s->mem[6] =3D=3D buf[3] && + s->mem[8] =3D=3D buf[4] && + s->mem[10] =3D=3D 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 =3D buf1; + size =3D MIN_BUF_SIZE; + } + + index =3D s->curpag << 8; + /* 4 bytes for header */ + total_len =3D size + 4; + /* address for next packet (4 bytes for CRC) */ + next =3D index + ((total_len + 4 + 255) & ~0xff); + if (next >=3D s->stop) + next -=3D (s->stop - s->start); + /* prepare packet header */ + p =3D s->mem + index; + s->rsr =3D ENRSR_RXOK; /* receive status */ + /* XXX: check this */ + if (buf[0] & 0x01) + s->rsr |=3D ENRSR_PHY; + p[0] =3D s->rsr; + p[1] =3D next >> 8; + p[2] =3D total_len; + p[3] =3D total_len >> 8; + index +=3D 4; + + /* write packet data */ + while (size > 0) { + if (index <=3D s->stop) + avail =3D s->stop - index; + else + avail =3D 0; + len =3D size; + if (len > avail) + len =3D avail; + memcpy(s->mem + index, buf, len); + buf +=3D len; + index +=3D len; + if (index =3D=3D s->stop) + index =3D s->start; + size -=3D len; + } + s->curpag =3D next >> 8; + + /* now we can signal we have received something */ + s->isr |=3D 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 =3D 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=3D%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 =3D opaque; + emac->rx =3D (struct EmacMalRxDes*) (phys_ram_base + 0x0000C000); + emac->tx =3D (struct EmacMalTxDes*) (phys_ram_base + 0x0000C000 + 16*8= ); + emac->txPos =3D emac->rxPos =3D 0; + emac->txNum =3D emac->rxNum =3D 0; + emac->rxStarted =3D emac->txStarted =3D 0; + emac->rxLostNum=3D0; + emac->rxLostLimit=3D1; +} +/* 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) +{ +=09return STACR_OC; +} + +static void emac_writel (void *opaque, target_phys_addr_t addr, uint32_t v= alue) +{ +=09ppc4xx_emac_t* emac =3D (ppc4xx_emac_t*)opaque; + +/*=09printf("%s: " PADDRX " val %x\n",__func__, addr, value);*/ +=09if (addr-emac->base=3D=3D0) { +=09=09/* soft reset */ +=09=09if (value & 0x20000000) { +=09=09=09printf("emac: soft reset commanded!\n"); +=09=09=09ppc4xx_emac_reset(emac); /* Should be protected with a semaphore,= also in emac_receive()? */ +=09=09} +=09=09/* rx enable */ +=09=09if (value & 0x08000000) { +=09=09=09emac->rxStarted=3D1; +=09=09=09printf("emac: rx started!\n"); +=09=09} +=09=09/* tx enable */ +=09=09if (value & 0x10000000) { +=09=09=09emac->txStarted=3D1; +=09=09=09printf("emac: tx started!\n"); +=09=09=09/* A timer that periodically check packet to send=20 +=09=09=09emac->tx_timer =3D qemu_new_timer();*/ +=09=09} +=09} +=09if (addr-emac->base=3D=3D8) { +=09=09if (value & 0x80000000) { +=09=09=09if (emac->txStarted=3D=3D1) { +=09=09=09if (emac->tx[emac->txPos].mal.bit0_ready) { +=09=09=09=09unsigned char* dstG =3D (unsigned char*) ntohl((unsigned long = int)emac->tx[emac->txPos].buf); +=09=09=09=09unsigned char* dstH=3D dstG+(unsigned int)phys_ram_base; +=09=09=09=09unsigned short size16 =3D ntohs(emac->tx[emac->txPos].len); + +=09=09=09=09DPRINT("Sending packet on pos %d\n", emac->txPos); +=09=09=09=09qemu_send_packet(emac->vc, dstH, size16); +=09=09=09=09if (emac->tx[emac->txPos].mal.bit5_intr) +=09=09=09=09=09qemu_irq_raise(emac->mal_irqs_txeob); + +=09=09=09=09/* Clear status */ +=09=09=09=09emac->tx[emac->txPos].mal.bit0_ready =3D 0; +=09=09=09=09/* 0x808 is stucked at STACR_OC */ +=09=09=09=09emac->txPos +=3D (emac->tx[emac->txPos].mal.bit1_wrap)? -(emac= ->txPos) : 1; +=09=09=09} else {printf("Processor goes crazy(ready bit was 0)!!! Stopping= tx\n");emac->txStarted=3D2;} +=09=09=09} else {if (emac->txStarted!=3D2) printf("Tx is disabled\n");} +=09=09} +=09} +} +static uint32_t emac_readw (void *opaque, target_phys_addr_t addr) +{ +=09printf("Lettura a granularita' word su EMAC " PADDRX "\n",addr); +=09return 0; +} + +static void emac_writew (void *opaque, target_phys_addr_t addr, uint32_t v= alue) +{ +=09printf("Scrittura a granularita' word su EMAC " PADDRX "\n",addr); +} + +static uint32_t emac_readb (void *opaque, target_phys_addr_t addr) +{ +=09printf("Lettura a granularita' byte su EMAC " PADDRX "\n",addr); +=09return 0; +} + +static void emac_writeb (void *opaque, target_phys_addr_t addr, uint32_t v= alue) +{ +=09printf("Scrittura a granularita' byte su EMAC " PADDRX "\n",addr); +} + + +static CPUReadMemoryFunc *emac_read[] =3D { + &emac_readb, + &emac_readw, + &emac_readl, +}; + +static CPUWriteMemoryFunc *emac_write[] =3D { + &emac_writeb, + &emac_writew, + &emac_writel, +}; +void ppc4xx_emac_init (CPUState *env, ppc4xx_mmio_t *mmio, target_phys_add= r_t offset, NICInfo *nic, qemu_irq mal_irqs[4]) +{ + ppc4xx_emac_t *emac; + + emac =3D qemu_mallocz(sizeof(ppc4xx_emac_t)); + if (emac !=3D NULL) { + emac->base =3D 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); + +=09/* One time configuration, HOST related */ +=09emac_ppc405_init(emac, nic); + +=09emac->mal_irqs_txeob =3D mal_irqs[3]; +=09emac->mal_irqs_rxeob =3D mal_irqs[2]; +=09emac->mal_irqs_txerr =3D mal_irqs[1]; +=09emac->mal_irqs_rxerr =3D mal_irqs[0]; + +=09/* N Time configuration, GUEST related */ + ppc4xx_emac_reset(emac); + } +} --- ../../qemu-0.9.1-orig/hw/ppc405_uc.c=092008-01-06 19:38:42.000000000 +0= 100 +++ qemu-0.9.1/hw/ppc405_uc.c=092008-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 #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 */ =20 extern int loglevel; extern FILE *logfile; @@ -1994,7 +1996,7 @@ static target_ulong dcr_read_mal (void * ret =3D mal->txcarr; break; case MAL0_TXEOBISR: - ret =3D mal->txeobisr; + ret =3D (target_ulong)-1/*mal->txeobisr TODO RESTORE WHEN EMAC LIN= K WAS INTERACTING WITH MAL */; break; case MAL0_TXDEIR: ret =3D 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;*/ } =20 /*************************************************************************= ****/ @@ -2281,6 +2284,15 @@ enum { PPC405CR_CLK_NB =3D 7, }; =20 +/* Addedum related to 405GPr approximated as 405EP + CR0 */ +static target_ulong dcr_read_cr0 (void *opaque, int dcrn) +{ +=09return 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=20 } } =20 +#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=20 #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 =3D ppcuic_init(env, irqs, 0x0C0, 0, 1); *picp =3D 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 =3D 0; for (i =3D 0; i < 2; i++) offset +=3D ram_sizes[i]; /* External bus controller */ ppc405_ebc_init(env); /* DMA controller */ - dma_irqs[0] =3D pic[26]; - dma_irqs[1] =3D pic[25]; - dma_irqs[2] =3D pic[24]; - dma_irqs[3] =3D pic[23]; + dma_irqs[0] =3D pic[INTN(5)]; + dma_irqs[1] =3D pic[INTN(6)]; + dma_irqs[2] =3D pic[INTN(7)]; + dma_irqs[3] =3D 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] !=3D 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] !=3D 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 +=3D 4096; /* GPT */ - gpt_irqs[0] =3D pic[12]; - gpt_irqs[1] =3D pic[11]; - gpt_irqs[2] =3D pic[10]; - gpt_irqs[3] =3D pic[9]; - gpt_irqs[4] =3D pic[8]; + gpt_irqs[0] =3D pic[INTN(19)]; + gpt_irqs[1] =3D pic[INTN(20)]; + gpt_irqs[2] =3D pic[INTN(21)]; + gpt_irqs[3] =3D pic[INTN(22)]; + gpt_irqs[4] =3D pic[INTN(23)]; ppc4xx_gpt_init(env, mmio, 0x000, gpt_irqs); /* PCI */ /* Uses pic[28], pic[15], pic[13] */ /* MAL */ - mal_irqs[0] =3D pic[20]; - mal_irqs[1] =3D pic[19]; - mal_irqs[2] =3D pic[18]; - mal_irqs[3] =3D pic[17]; + mal_irqs[3] =3D pic[INTN(11)]; + mal_irqs[2] =3D pic[INTN(12)]; + mal_irqs[1] =3D pic[INTN(13)]; + mal_irqs[0] =3D pic[INTN(14)]; + ppc405_mal_init(env, mal_irqs); - /* Ethernet */ + /* EMAC (Ethernet Media Access Controller) */ + { + =09void ppc4xx_emac_init(CPUState *env, ppc4xx_mmio_t *mmio, target_ph= ys_addr_t offset, NICInfo* nic, qemu_irq irq[4]); + =09ppc4xx_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 CPC0_CR0@0xB1 DCR: opaque represent integer of value */ + ppc_dcr_register(env, PPC405CR_CPC0_CR0, NULL, &dcr_read_cr0, &dcr_wri= te_cr0); + /* This is typical of 405GPr. CPC0_ECR =3D 0xAA.*/ + ppc_dcr_register(env, 0xAA/* CPC0_ECR */, NULL, &dcr_read_cr0, &dcr_wr= ite_cr0); + ppc_dcr_register(env, 0xB2/* CPC0_CR1 */, NULL, &dcr_read_cr0, &dcr_wr= ite_cr0); + =20 *offsetp =3D offset; =20 return env; =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D PATCH TO ENHACE FLASH DEVICE (hw\pflash_cfi02.c, cpu-all.h) =3D= =3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- qemu-0.9.1-orig/cpu-all.h=092008-01-06 19:38:42.000000000 +0100 +++ qemu-0.9.1/cpu-all.h=092008-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) =20 /* define log items */ typedef struct CPULogItem { --- qemu-0.9.1-orig/hw/pflash_cfi02.c=092008-01-06 19:38:42.000000000 +0100 +++ qemu-0.9.1/hw/pflash_cfi02.c=092008-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 ch= ips * 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 Wri= teBufferLoad command. + * Use different name for structure, so multiple device could be handed@sa= me time */ =20 #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 */ =20 -//#define PFLASH_DEBUG +#define USE_SIMPLE_TABLE +#define PFLASH_DEBUG #ifdef PFLASH_DEBUG +static int howt=3D0; #define DPRINTF(fmt, args...) \ do { \ - printf("PFLASH: " fmt , ##args); \ + if (loglevel & FLASH_LOG_CFI) {printf("PFLASH: " fmt , ##args);} = \ +=09howt++;=09=09=09=09=09 \ } while (0) #else #define DPRINTF(fmt, args...) do { } while (0) #endif =20 -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 siz= e) + * 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; /*=20 +=09=09=09 =09=09=09=09memory_mapped +=09=09=09 Reset=3D> off|fl_mem|ROMD,=090 +=09=09=09* timer=3D> off|fl_mem|ROMD,=090 +=09=09=09* write=3D> fl_mem=09=091 +=09=09=09* +=09=09=09* off costante +=09=09=09* fl_mem costante (rif all'io costruito, f() di rw...) +=09=09=09*/ }; =20 +static void pflash_cfi02_core_reset (void *opaque) { + struct pflash_cfi02_t *pfl =3D (struct pflash_cfi02_t*)opaque; + + pfl->wcycle =3D 0; + pfl->cmd =3D 0; + pfl->status =3D 0; + + pfl->bytes2write =3D 0; + pfl->buffer_loading =3D 0; + pfl->buffer_loading_start =3D 0; + pfl->buffer_loading_end =3D 0; + +/* pfl->pendingW =3D pfl->fstSector =3D curSector =3D 0; Lost current w= rite? */ + + pfl->how_memory_mapped =3D 0; + =20 + 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 =3D (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 =3D 1; +#else + pfl->ro =3D 0; +#endif + pfl->bypass =3D 0; + pflash_cfi02_core_reset(pfl); + printf("Resetting cfi chip!\n"); +} static void pflash_timer (void *opaque) { - pflash_t *pfl =3D opaque; + struct pflash_cfi02_t *pfl =3D opaque; =20 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 =3D 2; } else { +=09if (pfl->how_memory_mapped) { cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->off | IO_MEM_ROMD | pfl->fl_mem)= ; +=09pfl->how_memory_mapped =3D 0; +=09} pfl->wcycle =3D 0; } pfl->cmd =3D 0; } =20 -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; =20 - DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset); ret =3D -1; offset -=3D pfl->base; - boff =3D offset & 0xFF; + _boff =3D offset & 0xFF; if (pfl->width =3D=3D 2) - boff =3D boff >> 1; + boff =3D _boff >> 1; else if (pfl->width =3D=3D 4) - boff =3D boff >> 2; + boff =3D _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 =3D pfl->storage; +=09p +=3D offset; +common_read: switch (width) { case 1: - ret =3D p[offset]; + ret =3D p[0]; // DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret= ); break; case 2: #if defined(TARGET_WORDS_BIGENDIAN) - ret =3D p[offset] << 8; - ret |=3D p[offset + 1]; + ret =3D p[0] << 8; + ret |=3D p[1]; #else - ret =3D p[offset]; - ret |=3D p[offset + 1] << 8; + ret =3D p[0]; + ret |=3D p[1] << 8; #endif // DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret= ); break; case 4: #if defined(TARGET_WORDS_BIGENDIAN) - ret =3D p[offset] << 24; - ret |=3D p[offset + 1] << 16; - ret |=3D p[offset + 2] << 8; - ret |=3D p[offset + 3]; + ret =3D p[0] << 24; + ret |=3D p[1] << 16; + ret |=3D p[2] << 8; + ret |=3D p[3]; #else - ret =3D p[offset]; - ret |=3D p[offset + 1] << 8; - ret |=3D p[offset + 2] << 16; - ret |=3D p[offset + 3] << 24; + ret =3D p[0]; + ret |=3D p[1] << 8; + ret |=3D p[2] << 16; + ret |=3D 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 =3D 0; - else - ret =3D pfl->cfi_table[boff]; + else { +#ifndef=09USE_SIMPLE_TABLE +=09 ret =3D pfl->cfi_table[_boff]; +#else +=09 p =3D &pfl->cfi_table[_boff]; +=09 goto common_read; +#endif +=09} break; } =20 + DPRINTF("%s: offset " TARGET_FMT_lx " value 0x%x width %d func %x\n", = __func__, _boff, ret, width, pfl->cmd); return ret; } =20 -/* update flash content on disk */ -static void pflash_update(pflash_t *pfl, int offset, +/*=20 + * update flash content on disk=20 + * Act as intermediate between + * - 32B from Driver=20 + * - 512B of device + * Optimize only when length=3D=3D32 & 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=20 + */ +#define PFLASH_512BLOCK 8=09/* 0 -> sector of 512B, 1 -> sector of 1024B, = ... */ +#define PFLASH_XBLOCK=09(9 + PFLASH_512BLOCK) +#define PFLASH_XBOUND=09((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 =3D offset + size; - /* round to sectors */ - offset =3D offset >> 9; - offset_end =3D (offset_end + 511) >> 9; - bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9), - offset_end - offset); - } +=09int offset_end; +=09int grouped =3D 0; /* Current version is linked with internal cache */ +=09int forcefl =3D 0; /* Force flush after all op */ + +=09if (pfl->bs) { +=09=09int _offset =3D offset; +=09=09offset =3D offset >> PFLASH_XBLOCK; + +=09=09/* Try to group sequential write +=09=09 * Stop also if found a sector bound! (so avoid timer for now) */ +=09=09if (size =3D=3D 32) { +=09=09=09forcefl =3D (((_offset+size)&PFLASH_XBOUND/*511*/)=3D=3D0); +=09=09=09if (pfl->pendingW) { +=09=09=09=09/* Try to group with previous write() */ +=09=09=09=09grouped =3D (offset =3D=3D pfl->curSector); +=09=09=09} else { +=09=09=09=09/* First write in this group */ +=09=09=09=09pfl->fstSector =3D offset; +=09=09=09=09pfl->curSector =3D offset; +=09=09=09=09pfl->pendingW =3D 1; +=09=09=09=09grouped =3D 1; +=09=09=09} +=09=09} + +=09=09/* Commit any pending write if the case. */ +=09=09if ((pfl->pendingW && !grouped) || forcefl) { +=09=09=09DPRINTF("%s: flushing sectors " TARGET_FMT_lx " ns %d\n", __func_= _, pfl->fstSector, pfl->curSector - pfl->fstSector + 1); +=09=09=09bdrv_write(pfl->bs, pfl->fstSector<storage= + (pfl->fstSector << (PFLASH_XBLOCK)), (pfl->curSector - pfl->fstSector + = 1)<<(PFLASH_512BLOCK)); +=09=09=09pfl->pendingW =3D 0; +=09=09} + +=09=09/* Current write (!in case we just do it with previous commit) */ +=09=09if (!grouped) { +=09=09=09offset_end =3D _offset + size; +=09=09=09/* round to sectors */ +=09=09=09offset_end =3D (offset_end + 511) >> 9; +=09=09=09DPRINTF("%s: flushing sectors " TARGET_FMT_lx " ns %d\n", __func_= _, offset, offset_end - offset); +=09=09=09bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9), offset_= end - offset); +=09=09} +=09} } - -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, uin= t32_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 =3D value; - if (pfl->cmd !=3D 0xA0 && cmd =3D=3D 0xF0) { -#if 0 - DPRINTF("%s: flash reset asked (%02x %02x)\n", - __func__, pfl->cmd, cmd); + if (pfl->cmd !=3D 0xA0 && pfl->cmd !=3D 0x25 && cmd =3D=3D 0xF0) { +#if 1 + DPRINTF("%s: flash reset asked, cmd(%02x) " TARGET_FMT_lx " %x %d\= n", + __func__, pfl->cmd, (char*)offset-(char*)pfl->storage, val= ue, width); #endif goto reset_flash; } - DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__, - offset, value, width, pfl->wcycle); + if (pfl->wcycle =3D=3D 0) offset -=3D (uint32_t)(long)pfl->storage; - else + else { +=09DPRINTF("PFLASH_WRITE - 0xFE000000:\n"); offset -=3D pfl->base; + } =20 - 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=3D=3D0) { cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem); + pfl->how_memory_mapped =3D 1; + } boff =3D offset & (pfl->sector_len - 1); if (pfl->width =3D=3D 2) boff =3D boff >> 1; else if (pfl->width =3D=3D 4) boff =3D boff >> 2; + + DPRINTF("%s: offset " TARGET_FMT_lx " val %x wid %d wcycle %d\n", __fu= nc__, +=09 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 =3D 0x98; return; } - if (boff !=3D 0x555 || cmd !=3D 0xAA) { + if (!(boff =3D=3D 0x555 || boff =3D=3D 0x5555) || cmd !=3D 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__); +=09pfl->wcycle++; break; case 1: /* We started an unlock sequence */ check_unlock1: - if (boff !=3D 0x2AA || cmd !=3D 0x55) { + if (!(boff =3D=3D 0x2AA || boff =3D=3D 0x2AAA) || cmd !=3D 0x55) { DPRINTF("%s: unlock1 failed " TARGET_FMT_lx " %02x\n", __func_= _, boff, cmd); goto reset_flash; } DPRINTF("%s: unlock sequence done\n", __func__); +=09pfl->wcycle++; break; case 2: +=09/* Command write buffer load. */ +=09if (boff=3D=3D0 && cmd=3D=3D0x25) { +=09=09/* Wait #word - 1 on same addr */ +=09=09DPRINTF("%s: start buffer load, expect len4next write\n", __func__); +=09=09pfl->buffer_loading=3D1; +=09=09pfl->wcycle--; +=09} else if (pfl->buffer_loading) { +=09=09pfl->bytes2write=3D(value+1)<<(width>>1); +=09=09DPRINTF("%s: got %d bytes2write\n", __func__, pfl->bytes2write); +=09=09pfl->wcycle++; +=09=09break; +=09} else=20 /* We finished an unlock sequence */ - if (!pfl->bypass && boff !=3D 0x555) { + if (!pfl->bypass && (boff !=3D 0x555 && boff !=3D 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 =3D 1; + printf("Requesting bypass\n"); goto do_bypass; case 0x80: case 0x90: case 0xA0: - pfl->cmd =3D cmd; - DPRINTF("%s: starting command %02x\n", __func__, cmd); - break; + case 0x25: +=09 pfl->cmd =3D cmd; +=09 DPRINTF("%s: starting command %02x\n", __func__, cmd); +=09 break; default: DPRINTF("%s: unknown command %02x\n", __func__, cmd); goto reset_flash; } - break; +=09pfl->wcycle++; +=09break; case 3: switch (pfl->cmd) { case 0x80: /* We need another unlock sequence */ goto check_unlock0; + case 0x25: +=09 if (pfl->bytes2write=3D=3D0) { +=09=09 printf("%s: buffer mode have 0 bytes2write!\n", __func__); +=09=09 goto reset_flash; +=09 } +=09 if (!pfl->buffer_loading_start) +=09=09 pfl->buffer_loading_start=3Doffset; +=09 pfl->buffer_loading_end=3Doffset+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] &=3D value; - pflash_update(pfl, offset, 1); + if (pfl->cmd!=3D0x25) 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] &=3D value; p[offset + 1] &=3D value >> 8; #endif - pflash_update(pfl, offset, 2); + if (pfl->cmd!=3D0x25) 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] &=3D value >> 16; p[offset + 3] &=3D value >> 24; #endif - pflash_update(pfl, offset, 4); + if (pfl->cmd!=3D0x25) pflash_update(pfl, offset, 4); break; } - pfl->status =3D 0x00 | ~(value & 0x80); - /* Let's pretend write is immediate */ - if (pfl->bypass) - goto do_bypass; - goto reset_flash; +=09 /* In buffer load mode, status is available only after requested by= tes2write */ +=09 if (pfl->cmd!=3D0x25) { +=09=09 pfl->status =3D 0x00 | ~(value & 0x80); +=09=09 /* Let's pretend write is immediate */ +=09=09 if (pfl->bypass) +=09=09=09goto do_bypass; +=09=09 goto reset_flash; +=09 } else { +=09=09 if (pfl->bytes2write>=3Dwidth) +=09=09=09 pfl->bytes2write-=3Dwidth; +=09=09 else { +=09=09=09 printf("%s: buffer mode discarded %d bytes at end of transfer= \n",__func__,width-pfl->bytes2write); +=09=09=09 pfl->bytes2write=3D0; +=09=09 } +=09=09 if (pfl->bytes2write) +=09=09=09 pfl->wcycle--; /* Dangerous if use timer */ +=09 } +=09 break; case 0x90: if (pfl->bypass && cmd =3D=3D 0x00) { /* Unlock bypass reset */ @@ -343,6 +505,8 @@ static void pflash_write (pflash_t *pfl, __func__, pfl->cmd); goto reset_flash; } +=09pfl->wcycle++; +=09break; 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: +=09 DPRINTF("%s: Buffer load terminated %s (%d bytes remaining)\n", __f= unc__, !pfl->bytes2write?"Ok" : "NOK", pfl->bytes2write); +=09 /* Update written sequence */ +=09 pflash_update(pfl, pfl->buffer_loading_start, pfl->buffer_loading_e= nd - pfl->buffer_loading_start); +=09 pfl->buffer_loading =3D 0; +=09 pfl->buffer_loading_start =3D 0; +=09 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 =3D 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))= ;*/ +=09 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; =20 /* Reset flash */ reset_flash: - cpu_register_physical_memory(pfl->base, pfl->total_len, - pfl->off | IO_MEM_ROMD | pfl->fl_mem); - pfl->bypass =3D 0; - pfl->wcycle =3D 0; - pfl->cmd =3D 0; + pflash_cfi02_core_reset(pfl); return; =20 do_bypass: @@ -444,14 +610,14 @@ static uint32_t pflash_readb (void *opaq =20 static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr) { - pflash_t *pfl =3D opaque; + struct pflash_cfi02_t *pfl =3D opaque; =20 return pflash_read(pfl, addr, 2); } =20 static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr) { - pflash_t *pfl =3D opaque; + struct pflash_cfi02_t *pfl =3D opaque; =20 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 =3D opaque; + struct pflash_cfi02_t *pfl =3D opaque; =20 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 =3D opaque; + struct pflash_cfi02_t *pfl =3D opaque; =20 pflash_write(pfl, addr, value, 4); } @@ -490,6 +656,7 @@ static CPUReadMemoryFunc *pflash_read_op &pflash_readl, }; =20 +#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) =20 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; =20 total_len =3D sector_len * nb_blocs; @@ -540,39 +707,31 @@ pflash_t *pflash_cfi02_register(target_p total_len !=3D (32 * 1024 * 1024) && total_len !=3D (64 * 1024 * 1= 024)) return NULL; #endif - pfl =3D qemu_mallocz(sizeof(pflash_t)); + pfl =3D qemu_mallocz(sizeof(struct pflash_cfi02_t)); if (pfl =3D=3D NULL) return NULL; + + /* One time initialization, HOST related. */ pfl->storage =3D phys_ram_base + off; pfl->fl_mem =3D cpu_register_io_memory(0, pflash_read_ops, pflash_writ= e_ops, pfl); pfl->off =3D off; - cpu_register_physical_memory(base, total_len, - off | pfl->fl_mem | IO_MEM_ROMD); - pfl->bs =3D 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 =3D 1; -#else - pfl->ro =3D 0; -#endif pfl->timer =3D qemu_new_timer(vm_clock, pflash_timer, pfl); pfl->base =3D base; pfl->sector_len =3D sector_len; pfl->total_len =3D total_len; pfl->width =3D width; - pfl->wcycle =3D 0; - pfl->cmd =3D 0; - pfl->status =3D 0; + + pfl->bs =3D bs; + if (pfl->bs) { + /* read the initial flash content */ + bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9); + } pfl->ident[0] =3D id0; pfl->ident[1] =3D id1; pfl->ident[2] =3D id2; pfl->ident[3] =3D id3; +#ifndef USE_SIMPLE_TABLE=20 /* Hardcoded CFI table (mostly from SG29 Spansion flash) */ pfl->cfi_len =3D 0x52; /* Standard "QRY" string */ @@ -632,6 +791,29 @@ pflash_t *pflash_cfi02_register(target_p pfl->cfi_table[0x2E] =3D (nb_blocs - 1) >> 8; pfl->cfi_table[0x2F] =3D sector_len >> 8; pfl->cfi_table[0x30] =3D sector_len >> 16; +#else + /* Don't know why but driver expect this=20 + * Now this table have !to be 'interpolated' basing on width. + * Moreover we were called with width =3D=3D 4. */ + pfl->cfi_len =3D 0x80; + pfl->cfi_table[0x21] =3D 'Q'; + pfl->cfi_table[0x23] =3D 'R'; + pfl->cfi_table[0x25] =3D 'Y'; + pfl->cfi_table[0x27] =3D 2;=09=09/* oam command set */ + pfl->cfi_table[0x4F] =3D 25; =09=09/* size =3D 2^x Bytes*/ + pfl->cfi_table[0x59] =3D 1;=09=09/* num of blocks */ + pfl->cfi_table[0x5b] =3D 255;=09=09/* sectors */ + pfl->cfi_table[0x61] =3D 2;=09=09/* sector size=09 */ +#endif =20 + /* 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); + =20 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 LittleEndi= an host. target-ppc\translate.c - Enable some bad access to !existing spr, unassigned memroy region (no mac= hine {data|instruction} exception start yet) Have a good day --- Sab 25/10/08, Andreas F=E4rber ha scritto: > Da: Andreas F=E4rber > Oggetto: Re: [Qemu-devel] TCG on PowerPC arch > A: "Salvatore Lionetti" > Cc: qemu-devel@nongnu.org > Data: Sabato 25 ottobre 2008, 22:51 > Hi, >=20 > Am 22.10.2008 um 10:18 schrieb Salvatore Lionetti: >=20 > > 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. >=20 > What about your previous ppc patch? Have you had time to > rework it > yet, so that it can be applied? >=20 > Regards, > Andreas=0A=0A=0A Scopri il blog di Yahoo! Mail:=0ATrucchi, novit=E0 = e scrivi la tua opinione.=0Ahttp://www.ymailblogit.com/blog