* [Qemu-devel] TCG on PowerPC arch
@ 2008-10-22 8:18 Salvatore Lionetti
2008-10-23 15:53 ` Aurelien Jarno
2008-10-25 20:51 ` Andreas Färber
0 siblings, 2 replies; 13+ messages in thread
From: Salvatore Lionetti @ 2008-10-22 8:18 UTC (permalink / raw)
To: qemu-devel
Hi,
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.
In the case, i need info about TCG
Have a good day
Scopri il blog di Yahoo! Mail:
Trucchi, novità e scrivi la tua opinione.
http://www.ymailblogit.com/blog
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
2008-10-22 8:18 [Qemu-devel] TCG on PowerPC arch Salvatore Lionetti
@ 2008-10-23 15:53 ` Aurelien Jarno
2008-10-25 20:51 ` Andreas Färber
1 sibling, 0 replies; 13+ messages in thread
From: Aurelien Jarno @ 2008-10-23 15:53 UTC (permalink / raw)
To: salvatorelionetti, qemu-devel
Salvatore Lionetti a écrit :
> Hi,
>
> 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.
>
I am currently doing the conversion, with a few other sending patches.
You can also send patches to help. Testing is also welcome. I do check
before commiting the changes, but I may miss a few bugs.
--
.''`. Aurelien Jarno | GPG: 1024D/F1BCDB73
: :' : Debian developer | Electrical Engineer
`. `' aurel32@debian.org | aurelien@aurel32.net
`- people.debian.org/~aurel32 | www.aurel32.net
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
2008-10-22 8:18 [Qemu-devel] TCG on PowerPC arch Salvatore Lionetti
2008-10-23 15:53 ` Aurelien Jarno
@ 2008-10-25 20:51 ` Andreas Färber
2008-10-27 15:12 ` Salvatore Lionetti
2008-10-27 15:29 ` Salvatore Lionetti
1 sibling, 2 replies; 13+ messages in thread
From: Andreas Färber @ 2008-10-25 20:51 UTC (permalink / raw)
To: Salvatore Lionetti; +Cc: qemu-devel
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
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
[not found] ` <867CA555-7DB9-4E82-891E-D29FD7BA26C6@hotmail.com>
@ 2008-10-26 21:27 ` C.W. Betts
0 siblings, 0 replies; 13+ messages in thread
From: C.W. Betts @ 2008-10-26 21:27 UTC (permalink / raw)
To: salvatorelionetti, qemu-devel
[-- Attachment #1: Type: text/plain, Size: 1408 bytes --]
Currently TCG is only available on the SVN server.
On Oct 24, 2008, at 4:37 AM, Salvatore Lionetti wrote:
> Hi
> I was working on 0.9.1, so were can i find some doc, apart from svn
> source?
> Have a good day
>
>> Message: 2
>> Date: Thu, 23 Oct 2008 17:53:48 +0200
>> From: Aurelien Jarno <aurelien@aurel32.net>
>> Subject: Re: [Qemu-devel] TCG on PowerPC arch
>> To: salvatorelionetti@yahoo.it, qemu-devel@nongnu.org
>> Message-ID: <49009E0C.2000002@aurel32.net>
>> Content-Type: text/plain; charset=ISO-8859-1
>>
>> Salvatore Lionetti a écrit :
>>> Hi,
>>>
>>> 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.
>>>
>>
>> I am currently doing the conversion, with a few other
>> sending patches.
>> You can also send patches to help. Testing is also welcome.
>> I do check
>> before commiting the changes, but I may miss a few bugs.
>>
>> --
>> .''`. Aurelien Jarno | GPG:
>> 1024D/F1BCDB73
>> : :' : Debian developer | Electrical
>> Engineer
>> `. `' aurel32@debian.org |
>> aurelien@aurel32.net
>> `- people.debian.org/~aurel32 | www.aurel32.net
>>
>
>
> Scopri il blog di Yahoo! Mail:
> Trucchi, novità e scrivi la tua opinione.
> http://www.ymailblogit.com/blog
>
>
[-- Attachment #2: Type: text/html, Size: 3694 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
2008-10-25 20:51 ` Andreas Färber
@ 2008-10-27 15:12 ` Salvatore Lionetti
2008-10-27 15:29 ` Salvatore Lionetti
1 sibling, 0 replies; 13+ messages in thread
From: Salvatore Lionetti @ 2008-10-27 15:12 UTC (permalink / raw)
To: Andreas Färber; +Cc: qemu-devel
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 salvatorelionetti@yahoo.it
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#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:
+ *
+ * Register@0xEF600000 already mapped.
+ * Configuration RW:
+ *
+ * Read(ind, data):
+ * [EMAC0_STACR] <= (STACR_STAC_R | ind)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ * [EMAC0_STACR] => >>16 => data
+ *
+ * Write(ind, data)
+ * [EMAC0_STACR] <= (STACR_STAC_W | ind | data<<16)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ *
+ * Physical access:
+ * Read(ind_phy, ind_reg, data)
+ * [EMAC0_STACR] <= (STACR_STAC_W | TANTOS_REG_MIIAC | (ind_reg&0x1F | OP_READ | (ind_phy&0x1F)<<5))>>16
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ *
+ * Verify:
+ * [EMAC0_STACR] <= (STACR_STAC_R | TANTOS_REG_MIIRD)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ * [EMAC0_STACR] => data
+ * data & STACR_PHYE should be 0
+ * data=data>>16
+ *
+ * Tantos Stub Layer: (needed?)
+ */
+// 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("des@0x%p |%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("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);
+ 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 CPC0_CR0@0xB1 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 handed@same time
*/
#include "hw.h"
#include "flash.h"
#include "qemu-timer.h"
#include "block.h"
+#include "cpu-all.h" /* To have FLASH_LOG_CFI */
+#include "exec-all.h" /* To have loglevel */
-//#define PFLASH_DEBUG
+#define USE_SIMPLE_TABLE
+#define PFLASH_DEBUG
#ifdef PFLASH_DEBUG
+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 must@least 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 <andreas.faerber@web.de> ha scritto:
> Da: Andreas Färber <andreas.faerber@web.de>
> Oggetto: Re: [Qemu-devel] TCG on PowerPC arch
> A: "Salvatore Lionetti" <salvatorelionetti@yahoo.it>
> Cc: qemu-devel@nongnu.org
> 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
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
2008-10-25 20:51 ` Andreas Färber
2008-10-27 15:12 ` Salvatore Lionetti
@ 2008-10-27 15:29 ` Salvatore Lionetti
2008-10-27 23:53 ` Paul Brook
2008-10-28 20:41 ` Andreas Färber
1 sibling, 2 replies; 13+ messages in thread
From: Salvatore Lionetti @ 2008-10-27 15:29 UTC (permalink / raw)
To: Andreas Färber; +Cc: qemu-devel
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 salvatorelionetti@yahoo.it
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#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:
+ *
+ * Register@0xEF600000 already mapped.
+ * Configuration RW:
+ *
+ * Read(ind, data):
+ * [EMAC0_STACR] <= (STACR_STAC_R | ind)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ * [EMAC0_STACR] => >>16 => data
+ *
+ * Write(ind, data)
+ * [EMAC0_STACR] <= (STACR_STAC_W | ind | data<<16)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ *
+ * Physical access:
+ * Read(ind_phy, ind_reg, data)
+ * [EMAC0_STACR] <= (STACR_STAC_W | TANTOS_REG_MIIAC | (ind_reg&0x1F | OP_READ | (ind_phy&0x1F)<<5))>>16
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ *
+ * Verify:
+ * [EMAC0_STACR] <= (STACR_STAC_R | TANTOS_REG_MIIRD)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ * [EMAC0_STACR] => data
+ * data & STACR_PHYE should be 0
+ * data=data>>16
+ *
+ * Tantos Stub Layer: (needed?)
+ */
+// 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("des@0x%p |%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("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);
+ 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 CPC0_CR0@0xB1 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 handed@same time
*/
#include "hw.h"
#include "flash.h"
#include "qemu-timer.h"
#include "block.h"
+#include "cpu-all.h" /* To have FLASH_LOG_CFI */
+#include "exec-all.h" /* To have loglevel */
-//#define PFLASH_DEBUG
+#define USE_SIMPLE_TABLE
+#define PFLASH_DEBUG
#ifdef PFLASH_DEBUG
+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 must@least 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 <andreas.faerber@web.de> ha scritto:
> Da: Andreas Färber <andreas.faerber@web.de>
> Oggetto: Re: [Qemu-devel] TCG on PowerPC arch
> A: "Salvatore Lionetti" <salvatorelionetti@yahoo.it>
> Cc: qemu-devel@nongnu.org
> 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
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
2008-10-27 15:29 ` Salvatore Lionetti
@ 2008-10-27 23:53 ` Paul Brook
2008-10-28 20:41 ` Andreas Färber
1 sibling, 0 replies; 13+ messages in thread
From: Paul Brook @ 2008-10-27 23:53 UTC (permalink / raw)
To: qemu-devel, salvatorelionetti; +Cc: Andreas Färber
> + struct { /* Mal */
> + unsigned int emac1_nu : 2;
Relying on a particular bitfield layout is a really bad idea. Don't do it.
Paul
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
2008-10-27 15:29 ` Salvatore Lionetti
2008-10-27 23:53 ` Paul Brook
@ 2008-10-28 20:41 ` Andreas Färber
2008-10-29 10:48 ` Salvatore Lionetti
2008-10-29 15:15 ` Hollis Blanchard
1 sibling, 2 replies; 13+ messages in thread
From: Andreas Färber @ 2008-10-28 20:41 UTC (permalink / raw)
To: salvatorelionetti; +Cc: qemu-devel
Hi,
Am 27.10.2008 um 16:29 schrieb Salvatore Lionetti:
> - 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.
Not sure I understand correctly, but this last item seems to be
missing here.
It would be good if you could check whether your patches still apply
against the latest SVN version, if that's what you meant with the
latter.
ppc hardware probably hasn't changed so much since 0.9.1 but pflash
might have.
> +static uint32_t emac_readw (void *opaque, target_phys_addr_t addr)
> +{
> + printf("Lettura a granularita' word su EMAC " PADDRX "\n",addr);
> + return 0;
> +}
Some Italian slipped in here, also in some comments.
Is the printf maybe a debug leftover that could be removed?
The split-up of your original patch looks okay, but for future
submissions it would make review easier if you'd send only one of them
at a time (e.g., mail subjects [PATCH 1/3], [PATCH 2/3] etc., see
other examples).
How did you actually use and test your eMac emulation? I assume you
did not use a PReP Linux kernel for that? If you could provide some
details, that might help with testing the TCG conversion too.
Andreas
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
2008-10-28 20:41 ` Andreas Färber
@ 2008-10-29 10:48 ` Salvatore Lionetti
2008-10-29 15:15 ` Hollis Blanchard
1 sibling, 0 replies; 13+ messages in thread
From: Salvatore Lionetti @ 2008-10-29 10:48 UTC (permalink / raw)
To: Andreas Färber; +Cc: qemu-devel
Ok,
thanks for your review!
Perhaps there was a lot of point to change and in the case, do it!
One of this is adding emac module in 'Makefile.target' (i forgot it!), but i think you just patch the patch !#
For the italian comment, if it is necessary behead it, or better: globalize it ;)
Serious speaking we have to see at EBC and emulates hw by composing or filter readed byte from device. Should be useful an on demand warning per device(in my board fw access@width different from the preset in EBC Bank-i configuration register bits 17:18 is considered a bug)
All this action should be done for the ppc4xx world.
In the mainwhile, for me, you can do anything you want about this read/write callback. On demand i'll adapt the code.
For me the main pb, due to my unknowing, is that i'm behind a proxy on Winzozz and svn give me timeout. Is the follow command correct?
->svn co svn://svn.sv.gnu.org/qemu/trunk
Next time i prefer also test latest svn before submit a patch, in the same way we do@work, avoiding unecessary work to this group.
I'm here for any pb related to this module
Thank you for attention
Salvatore
P.S: For the board, it is a commercial product so don't know if can give detail. Moreover i don't thing you need the exact board so, if agree, i create a new board from the previous.
P.P.S: In this board there is a way to configure qemu by file. I'd like to extent such concept, with correct namespace, configuration option.
--- Mar 28/10/08, Andreas Färber <andreas.faerber@web.de> ha scritto:
> Da: Andreas Färber <andreas.faerber@web.de>
> Oggetto: Re: [Qemu-devel] TCG on PowerPC arch
> A: salvatorelionetti@yahoo.it
> Cc: qemu-devel@nongnu.org
> Data: Martedì 28 ottobre 2008, 21:41
> Hi,
>
> Am 27.10.2008 um 16:29 schrieb Salvatore Lionetti:
>
> > - 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.
>
> Not sure I understand correctly, but this last item seems
> to be
> missing here.
> It would be good if you could check whether your patches
> still apply
> against the latest SVN version, if that's what you
> meant with the
> latter.
> ppc hardware probably hasn't changed so much since
> 0.9.1 but pflash
> might have.
>
> > +static uint32_t emac_readw (void *opaque,
> target_phys_addr_t addr)
> > +{
> > + printf("Lettura a granularita' word su EMAC
> " PADDRX "\n",addr);
> > + return 0;
> > +}
>
> Some Italian slipped in here, also in some comments.
> Is the printf maybe a debug leftover that could be removed?
>
> The split-up of your original patch looks okay, but for
> future
> submissions it would make review easier if you'd send
> only one of them
> at a time (e.g., mail subjects [PATCH 1/3], [PATCH 2/3]
> etc., see
> other examples).
>
> How did you actually use and test your eMac emulation? I
> assume you
> did not use a PReP Linux kernel for that? If you could
> provide some
> details, that might help with testing the TCG conversion
> too.
>
> Andreas
Unisciti alla community di Io fotografo e video, il nuovo corso di fotografia di Gazzetta dello sport:
http://www.flickr.com/groups/iofotografoevideo
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
2008-10-28 20:41 ` Andreas Färber
2008-10-29 10:48 ` Salvatore Lionetti
@ 2008-10-29 15:15 ` Hollis Blanchard
2008-10-30 8:53 ` Salvatore Lionetti
1 sibling, 1 reply; 13+ messages in thread
From: Hollis Blanchard @ 2008-10-29 15:15 UTC (permalink / raw)
To: qemu-devel; +Cc: salvatorelionetti
On Tue, Oct 28, 2008 at 3:41 PM, Andreas Färber <andreas.faerber@web.de> wrote:
>
> How did you actually use and test your eMac emulation? I assume you did not
> use a PReP Linux kernel for that? If you could provide some details, that
> might help with testing the TCG conversion too.
(Just in case there's any confusion, EMAC is the name for the ethernet
controller on IBM's 405- and 440-based SoCs, not to be confused with
Apple's eMac product.)
Salvatore, did you use a 405 Linux kernel with the EMAC driver to test
this patch? If so, how exactly did you boot? What did you do for
firmware?
-Hollis
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
2008-10-29 15:15 ` Hollis Blanchard
@ 2008-10-30 8:53 ` Salvatore Lionetti
2008-10-31 14:44 ` Hollis Blanchard
0 siblings, 1 reply; 13+ messages in thread
From: Salvatore Lionetti @ 2008-10-30 8:53 UTC (permalink / raw)
To: qemu-devel, Hollis Blanchard
Hi Hollis,
please excuse me, but i can't release my firmware (based on OSE)
If you agree, i'd like to
- catch svn status to test emac for my 405 based board, custom fw
- compile a linux kernel for ppc405 cpu, with emac driver
(i've trying eCos but no emac driver :(0)
For first step actually have some pb with proxy script.
The second one is not strictly depend on me, but 'm very glad if anybody do it. Moreover emac driver in our custom firmware only used reversed mii, and is not well written code! so however i'd like to use another os.
Moreover the emac device is tested only with such driver so i expect some pb during porting, so excuse in advance if some pb could arise.
Have a good day
Salvatore
--- Mer 29/10/08, Hollis Blanchard <hollis@penguinppc.org> ha scritto:
> Da: Hollis Blanchard <hollis@penguinppc.org>
> Oggetto: Re: [Qemu-devel] TCG on PowerPC arch
> A: qemu-devel@nongnu.org
> Cc: salvatorelionetti@yahoo.it
> Data: Mercoledì 29 ottobre 2008, 16:15
> On Tue, Oct 28, 2008 at 3:41 PM, Andreas Färber
> <andreas.faerber@web.de> wrote:
> >
> > How did you actually use and test your eMac emulation?
> I assume you did not
> > use a PReP Linux kernel for that? If you could provide
> some details, that
> > might help with testing the TCG conversion too.
>
> (Just in case there's any confusion, EMAC is the name
> for the ethernet
> controller on IBM's 405- and 440-based SoCs, not to be
> confused with
> Apple's eMac product.)
>
> Salvatore, did you use a 405 Linux kernel with the EMAC
> driver to test
> this patch? If so, how exactly did you boot? What did you
> do for
> firmware?
>
> -Hollis
Unisciti alla community di Io fotografo e video, il nuovo corso di fotografia di Gazzetta dello sport:
http://www.flickr.com/groups/iofotografoevideo
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
2008-10-30 8:53 ` Salvatore Lionetti
@ 2008-10-31 14:44 ` Hollis Blanchard
2008-11-03 11:02 ` Salvatore Lionetti
0 siblings, 1 reply; 13+ messages in thread
From: Hollis Blanchard @ 2008-10-31 14:44 UTC (permalink / raw)
To: salvatorelionetti; +Cc: qemu-devel
To summarize, you're saying that the only way you're able to test the
EMAC patch is with a custom firmware you can't make public? Obviously
that's not ideal, but I think some EMAC emulation is better than none
at all, so IMHO that shouldn't necessarily block your patch.
The problem I had when trying to test qemu's 405 emulation was that
Linux needed firmware to load it, and no 405 firmware is distributed
with qemu. At the time, Jocelyn claimed we could download a binary
uboot image from AMCC, but that didn't actually work. (I think we
ended up using http://www.amcc.com/Embedded/Downloads/download.html?item=129&start=y).
This was probably a year ago, so details are fuzzy now.
However, if you have access to a 440 board, you could use KVM
(http://kvm.qumranet.com/kvmwiki/PowerPc) to boot a guest kernel with
the EMAC driver and test that way. Qemu's instruction emulation
doesn't support 440, but KVM implements all the instruction emulation
itself and does run on 440.
Anyways, I definitely think it's worthwhile to update your patch to current SVN.
-Hollis
On Thu, Oct 30, 2008 at 3:53 AM, Salvatore Lionetti
<salvatorelionetti@yahoo.it> wrote:
> Hi Hollis,
>
> please excuse me, but i can't release my firmware (based on OSE)
> If you agree, i'd like to
> - catch svn status to test emac for my 405 based board, custom fw
> - compile a linux kernel for ppc405 cpu, with emac driver
> (i've trying eCos but no emac driver :(0)
>
> For first step actually have some pb with proxy script.
> The second one is not strictly depend on me, but 'm very glad if anybody do it. Moreover emac driver in our custom firmware only used reversed mii, and is not well written code! so however i'd like to use another os.
> Moreover the emac device is tested only with such driver so i expect some pb during porting, so excuse in advance if some pb could arise.
>
> Have a good day
> Salvatore
>
> --- Mer 29/10/08, Hollis Blanchard <hollis@penguinppc.org> ha scritto:
>
>> Da: Hollis Blanchard <hollis@penguinppc.org>
>> Oggetto: Re: [Qemu-devel] TCG on PowerPC arch
>> A: qemu-devel@nongnu.org
>> Cc: salvatorelionetti@yahoo.it
>> Data: Mercoledì 29 ottobre 2008, 16:15
>> On Tue, Oct 28, 2008 at 3:41 PM, Andreas Färber
>> <andreas.faerber@web.de> wrote:
>> >
>> > How did you actually use and test your eMac emulation?
>> I assume you did not
>> > use a PReP Linux kernel for that? If you could provide
>> some details, that
>> > might help with testing the TCG conversion too.
>>
>> (Just in case there's any confusion, EMAC is the name
>> for the ethernet
>> controller on IBM's 405- and 440-based SoCs, not to be
>> confused with
>> Apple's eMac product.)
>>
>> Salvatore, did you use a 405 Linux kernel with the EMAC
>> driver to test
>> this patch? If so, how exactly did you boot? What did you
>> do for
>> firmware?
>>
>> -Hollis
>
>
> Unisciti alla community di Io fotografo e video, il nuovo corso di fotografia di Gazzetta dello sport:
> http://www.flickr.com/groups/iofotografoevideo
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] TCG on PowerPC arch
2008-10-31 14:44 ` Hollis Blanchard
@ 2008-11-03 11:02 ` Salvatore Lionetti
0 siblings, 0 replies; 13+ messages in thread
From: Salvatore Lionetti @ 2008-11-03 11:02 UTC (permalink / raw)
To: Hollis Blanchard; +Cc: qemu-devel
Hi,
thanks for trustworth toward me!
As i said in previous email, i decide to test u-boot emac driver.
Actually:
- uboot cross compile and make process generates an image for walnut board
- qemu load such image but stop executing during board init
Next step i'm doing is to build a new board in u-boot (possibly linking the configuration of qemu machine with u-boot, but with low priority) and verify emac/mal layer.
The link you give is about 'Sycamore' board, also support by u-boot.
Thanks for this info, i'll try the most 'simple' board to give feedback ASAP.
Have a good day
--- Ven 31/10/08, Hollis Blanchard <hollis@penguinppc.org> ha scritto:
> Da: Hollis Blanchard <hollis@penguinppc.org>
> Oggetto: Re: [Qemu-devel] TCG on PowerPC arch
> A: salvatorelionetti@yahoo.it
> Cc: qemu-devel@nongnu.org
> Data: Venerdì 31 ottobre 2008, 15:44
> To summarize, you're saying that the only way you're
> able to test the
> EMAC patch is with a custom firmware you can't make
> public? Obviously
> that's not ideal, but I think some EMAC emulation is
> better than none
> at all, so IMHO that shouldn't necessarily block your
> patch.
>
> The problem I had when trying to test qemu's 405
> emulation was that
> Linux needed firmware to load it, and no 405 firmware is
> distributed
> with qemu. At the time, Jocelyn claimed we could download a
> binary
> uboot image from AMCC, but that didn't actually work.
> (I think we
> ended up using
> http://www.amcc.com/Embedded/Downloads/download.html?item=129&start=y).
> This was probably a year ago, so details are fuzzy now.
>
> However, if you have access to a 440 board, you could use
> KVM
> (http://kvm.qumranet.com/kvmwiki/PowerPc) to boot a guest
> kernel with
> the EMAC driver and test that way. Qemu's instruction
> emulation
> doesn't support 440, but KVM implements all the
> instruction emulation
> itself and does run on 440.
>
> Anyways, I definitely think it's worthwhile to update
> your patch to current SVN.
>
> -Hollis
>
> On Thu, Oct 30, 2008 at 3:53 AM, Salvatore Lionetti
> <salvatorelionetti@yahoo.it> wrote:
> > Hi Hollis,
> >
> > please excuse me, but i can't release my firmware
> (based on OSE)
> > If you agree, i'd like to
> > - catch svn status to test emac for my 405 based
> board, custom fw
> > - compile a linux kernel for ppc405 cpu, with emac
> driver
> > (i've trying eCos but no emac driver :(0)
> >
> > For first step actually have some pb with proxy
> script.
> > The second one is not strictly depend on me, but
> 'm very glad if anybody do it. Moreover emac driver in
> our custom firmware only used reversed mii, and is not well
> written code! so however i'd like to use another os.
> > Moreover the emac device is tested only with such
> driver so i expect some pb during porting, so excuse in
> advance if some pb could arise.
> >
> > Have a good day
> > Salvatore
> >
> > --- Mer 29/10/08, Hollis Blanchard
> <hollis@penguinppc.org> ha scritto:
> >
> >> Da: Hollis Blanchard <hollis@penguinppc.org>
> >> Oggetto: Re: [Qemu-devel] TCG on PowerPC arch
> >> A: qemu-devel@nongnu.org
> >> Cc: salvatorelionetti@yahoo.it
> >> Data: Mercoledì 29 ottobre 2008, 16:15
> >> On Tue, Oct 28, 2008 at 3:41 PM, Andreas Färber
> >> <andreas.faerber@web.de> wrote:
> >> >
> >> > How did you actually use and test your eMac
> emulation?
> >> I assume you did not
> >> > use a PReP Linux kernel for that? If you
> could provide
> >> some details, that
> >> > might help with testing the TCG conversion
> too.
> >>
> >> (Just in case there's any confusion, EMAC is
> the name
> >> for the ethernet
> >> controller on IBM's 405- and 440-based SoCs,
> not to be
> >> confused with
> >> Apple's eMac product.)
> >>
> >> Salvatore, did you use a 405 Linux kernel with the
> EMAC
> >> driver to test
> >> this patch? If so, how exactly did you boot? What
> did you
> >> do for
> >> firmware?
> >>
> >> -Hollis
> >
> >
> > Unisciti alla community di Io fotografo e video,
> il nuovo corso di fotografia di Gazzetta dello sport:
> > http://www.flickr.com/groups/iofotografoevideo
> >
Unisciti alla community di Io fotografo e video, il nuovo corso di fotografia di Gazzetta dello sport:
http://www.flickr.com/groups/iofotografoevideo
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2008-11-03 11:02 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-10-22 8:18 [Qemu-devel] TCG on PowerPC arch Salvatore Lionetti
2008-10-23 15:53 ` Aurelien Jarno
2008-10-25 20:51 ` Andreas Färber
2008-10-27 15:12 ` Salvatore Lionetti
2008-10-27 15:29 ` Salvatore Lionetti
2008-10-27 23:53 ` Paul Brook
2008-10-28 20:41 ` Andreas Färber
2008-10-29 10:48 ` Salvatore Lionetti
2008-10-29 15:15 ` Hollis Blanchard
2008-10-30 8:53 ` Salvatore Lionetti
2008-10-31 14:44 ` Hollis Blanchard
2008-11-03 11:02 ` Salvatore Lionetti
-- strict thread matches above, loose matches on Subject: below --
2008-10-24 10:37 Salvatore Lionetti
[not found] ` <867CA555-7DB9-4E82-891E-D29FD7BA26C6@hotmail.com>
2008-10-26 21:27 ` C.W. Betts
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).