[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] TCG on PowerPC arch
From: |
Salvatore Lionetti |
Subject: |
Re: [Qemu-devel] TCG on PowerPC arch |
Date: |
Mon, 27 Oct 2008 15:12:09 +0000 (GMT) |
Sure!
since i never created patch, also to reduce integration effort, i split patch
in three activity (starting from 0.9.1):
- Activity [emac device] {hw/emac.c, hw/ppc405_uc.c}
now ethernet, using vlan driver, work!
Now ppc405GPr could be used as 405EP
To test use ./qemu ... -net nic -net tap,ifname=qemu_network ...
- Activity [cfi flash] {hw/pflash_cfi02.c cpu-all.h}
Intro 'buffer load mode'
- Activity [major fix] {vl.c hw/ppc.c}
reset: unprogram PIT on chip, core, system reset
focus: initial focus in monitor when load very great sized elf
I try to attach to svn view.
PATCH TO INTRODUCE EMAC (hw\emac.c, hw\ppc405_uc.c)
--- ../../qemu-0.9.1-orig/hw/emac.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-0.9.1/hw/emac.c 2008-10-16 19:14:43.706437000 +0200
@@ -0,0 +1,591 @@
+/*
+ * QEMU EMAC emulation
+ *
+ * Copyright (c) 2008, Lionetti Salvatore address@hidden
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "ppc.h"
+#include "ppc405.h"
+#include "pc.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "net.h"
+
+/* #define DEBUG_EMAC */
+#ifdef DEBUG_EMAC
+#define DPRINT(fmt, args...) \
+ do { printf("%s: " fmt , __func__, ##args); } while (0)
+#else
+#define DPRINT(fmt, args...)
+#endif
+
+/*
+ * Redefined because if !exist, linker gives a warning but produce qemu,
+ * but on execution this call cause problem
+ * (could be cygwin & mingw cohesistence?)
+ */
+#if (defined(WORDS_BIGENDIAN) && defined(TARGET_WORDS_BIGENDIAN)) ||
((!defined(WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN)))
+#if 0
+static unsigned long int htonl(unsigned long int hostlong);
+static unsigned short int htons(unsigned short int hostshort);
+#endif
+static unsigned long int ntohl(unsigned long int ing) {
+ return ing;
+}
+static unsigned short int ntohs(unsigned short int ing) {
+ return ing;
+}
+#else
+static unsigned long int ntohl(unsigned long int ing) {
+ unsigned char tmp;
+ unsigned char* tmpp = (unsigned char*)&ing;
+ tmp=tmpp[0]; tmpp[0]=tmpp[3]; tmpp[3]=tmp;
+ tmp=tmpp[1]; tmpp[1]=tmpp[2]; tmpp[2]=tmp;
+ return *(unsigned long int*)tmpp;
+}
+static unsigned short int ntohs(unsigned short int ing) {
+ return ((ing&0xFF)<<8) | ((ing&0xFF00)>>8);
+}
+#endif
+
+/* qemu initialization:
+ *
+ * parse command line: call net_client_init() for each -net, either for {if,
collision domain} options.
+ * ==========
================
+ * IF MAC=... <==== Vlan{Id,Ptr} ====>
COLLISION DOMAIN (mean N-1 other IF MAC=...)
+ * ==========
================
+ * -net nic[,...]: fill field onto nd_table[]
{MAC(cl|auto), model, vlanPtr=f(vlanId)}
+ * vlanPtr=f(vlanId)->guest++
+ * -net tap[,...]: vlanPtr=f(vlanId)->host ++
+ * tap_win32_init(vlanPtr,
"ifname=tap..."):
+ *
qemu_new_vlan_client(vlanPtr,tap_receive, tap* opaque) RECV
+ *
qemu_add_wait_object(tap_sem, tap_w32_send, tap* opaque) SEND
+ *
+ * For each vlan created,
+ * exit if no GUEST & some HOST
+ * warn if some GUEST & no HOST
+ *
+ * start machine: Es ppc (also pc use n2000) call machine->init():
+ * isa_ne2000_init(base, irqno, &nd_table[i])
+ * register_ioport_write(base + ...,
ne2000_asic_ioport_write, opaque NE2000State*); SEND
+ * qemu_new_vlan_client(nd->vlan, ne2000_receive,
ne2000_can_receive, opaque NE2000State*) RECV
+ *
+ * Done!!!
+ *
+ * qemu runtime scenario:
+ *
+ * packet send from HOST: a signal (after exec() cycle) is sent to
tap_sem => tap_w32_send() => tap_win32_read()
+ * if some bytes returned => qemu_send_packet() =>
send to all 'client' (better peer) of
+ * such vlan, different from itself =>
ne2000_receive()
+ *
+ * packet send from GUEST: in machine code we call qemu_send_packet() =>
(prec) => tap_receive() => tap_w32_write()
+ *
+ *
+ * So onto VLAN actors always call qemu_send_packet() that dispatch packet to
all peer attached to same vlan.
+ *
+ */
+/* PPC405 layer 2, reversed MII mode:
+ *
+ * address@hidden already mapped.
+ * Configuration RW:
+ *
+ * Read(ind, data):
+ * [EMAC0_STACR] <= (STACR_STAC_R | ind)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ * [EMAC0_STACR] => >>16 => data
+ *
+ * Write(ind, data)
+ * [EMAC0_STACR] <= (STACR_STAC_W | ind | data<<16)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ *
+ * Physical access:
+ * Read(ind_phy, ind_reg, data)
+ * [EMAC0_STACR] <= (STACR_STAC_W | TANTOS_REG_MIIAC | (ind_reg&0x1F |
OP_READ | (ind_phy&0x1F)<<5))>>16
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ *
+ * Verify:
+ * [EMAC0_STACR] <= (STACR_STAC_R | TANTOS_REG_MIIRD)
+ * [EMAC0_STACR] & STACR_OC must goes to 0
+ * [EMAC0_STACR] => data
+ * data & STACR_PHYE should be 0
+ * data=data>>16
+ *
+ * Tantos Stub Layer: (needed?)
+ */
+// For PPC405
+#define EMAC0_BASE 0xEF600800
+#define EMAC0_STACR_DISP 0x35
+#define EMAC0_STACR (EMAC0_BASE + EMAC0_STACR_DISP) /* 4 byte addressing
*/
+#define STACR_OC 0x00008000 /* Occupied flag */
+#define STACR_PHYE 0x00004000
+#define STACR_STAC_W 0x00002000
+#define STACR_STAC_R 0x00001000
+
+#define TANTOS_REG_MIIAC 0x120 /// TANTOS3G MII indirect acess
registers
+#define TANTOS_REG_MIIWD 0x121
+#define TANTOS_REG_MIIRD 0x122
+#define OP_WRITE 0x0400
+#define OP_READ 0x0800
+#define MBUSY 0x8000
+
+/* WORDS_BIGENDIAN = FALSE su HOST i386, GUEST ppc
+ * per cui e' l'architetura HOST
+ */
+struct EmacMalRxDes {
+#ifdef WORDS_BIGENDIAN
+#error "Host endianism BUG: To Test!!!"
+#else
+ union {
+ struct { /* Mal */
+ unsigned int emac1_nu : 2;
+ unsigned int bit5_intr : 1;
+ unsigned int bit4_first : 1;
+ unsigned int bit3_last : 1;
+ unsigned int bit2_contm : 1;
+ unsigned int bit1_wrap : 1;
+ unsigned int bit0_empty : 1;
+ unsigned int emac2_nu : 8;
+ } __attribute__ ((packed)) mal;
+ struct { /* Status: Read access, error cause */
+ unsigned int bit7_pausepacket : 1;
+ unsigned int bit6_overrun : 1;
+ unsigned int mal_nu : 6;
+ unsigned int bit15_inrange : 1;
+ unsigned int bit14_outrange : 1;
+ unsigned int bit13_longpacket : 1;
+ unsigned int bit12_fcs : 1;
+ unsigned int bit11_alignment : 1;
+ unsigned int bit10_shortevent : 1;
+ unsigned int bit9_runtpacket : 1;
+ unsigned int bit8_badpacket : 1;
+ } __attribute__ ((packed)) emac_errstatus;
+ } __attribute__ ((packed));
+#endif
+ unsigned short len;
+ unsigned char* buf;
+} __attribute__ ((packed)); /* Host endianism, to be converted */
+struct EmacMalTxDes {
+#ifdef WORDS_BIGENDIAN
+#error "Host endianism BUG: To Test!!!"
+#else
+ union {
+ struct { /* Mal */
+ unsigned int emac1_nu : 2;
+ unsigned int bit5_intr : 1;
+ unsigned int bit4_resv : 1;
+ unsigned int bit3_last : 1;
+ unsigned int bit2_contm : 1;
+ unsigned int bit1_wrap : 1;
+ unsigned int bit0_ready : 1;
+ unsigned int emac2_nu : 8;
+ } __attribute__ ((packed)) mal;
+ struct { /* Status: Read access, error cause */
+ unsigned int bit7_badpacket : 1;
+ unsigned int bit6_badfsc : 1;
+ unsigned int mal_nu : 6;
+ unsigned int bit15_sqe : 1;
+ unsigned int bit14_underrun : 1;
+ unsigned int bit13_singlecoll : 1;
+ unsigned int bit12_multiplecoll : 1;
+ unsigned int bit11_latecoll : 1;
+ unsigned int bit10_excessivecoll : 1;
+ unsigned int bit9_excessivedeferral : 1;
+ unsigned int bit8_lossofcarrier : 1;
+ } __attribute__ ((packed)) emac_errorstatus;
+ struct { /* Control: Write access */
+ unsigned int bit7_generatepad : 1;
+ unsigned int bit6_generatefcs : 1;
+ unsigned int mal_nu : 6;
+ unsigned int emac_nu : 4;
+ unsigned int bit11_vlantag_replace : 1;
+ unsigned int bit10_vlantag_insert : 1;
+ unsigned int bit9_sourceaddr_insert : 1;
+ unsigned int bit8_sourceaddr_replace: 1;
+ } __attribute__ ((packed)) emac_control;
+ };
+#endif
+ unsigned short len;
+ unsigned char* buf;
+}__attribute__ ((packed)); /* Host endianism, to be converted */
+
+
+typedef struct ppc4xx_emac_t ppc4xx_emac_t;
+struct ppc4xx_emac_t {
+ /* Guest related */
+ target_phys_addr_t base;
+ NICInfo nic;
+ /* To remove, already defined in mal */
+ qemu_irq mal_irqs_txeob;
+ qemu_irq mal_irqs_rxeob;
+ qemu_irq mal_irqs_txerr;
+ qemu_irq mal_irqs_rxerr;
+ qemu_irq mal_irqs_syserr;
+
+ struct EmacMalTxDes* tx;
+ struct EmacMalRxDes* rx;
+
+ int txPos, rxPos;
+ int txNum, rxNum;
+
+ int rxStarted, txStarted;
+ int rxLostNum, rxLostLimit;
+
+ /* Host related */
+ VLANClientState *vc;
+ QEMUTimer* tx_timer;
+};
+
+#if 0
+#define EMACMAL_EMPTY 0x8000
+#define EMACMAL_WRAP 0x8000
+#define EMACMAL_EMPTY 0x8000
+#define EMACMAL_EMPTY 0x8000
+void EmacMalDes_readFromTarget(struct EmacMalDes* host, struct EmacMalDes*
guest) {
+
+ host->status = ntohs(guest->status);
+ host->len = ntohs(guest->len);
+ host->buf = htol(guest->buf);
+}
+void EmacMalDes_writeToTarget(struct EmacMalDes* host, struct EmacMalDes*
guest) {
+}
+#endif
+void EmacMalRxDes_dump(struct EmacMalRxDes* des) {
+ printf("address@hidden |%2.2X|%2X|%02X|%02X| len %d buf
0x%p\n",des,((char*)des)[0], ((char*)des)[1], ((char*)des)[2], ((char*)des)[3],
ntohs(des->len), (unsigned char*)ntohl((unsigned long int)des->buf));
+ printf("mal: empty%d wrap%d contm %d last%d first%d intr%d\n",
+ des->mal.bit0_empty, des->mal.bit1_wrap,
des->mal.bit2_contm, des->mal.bit3_last, des->mal.bit4_first,
des->mal.bit5_intr);
+}
+void EmacMalTxDes_dump(struct EmacMalTxDes* des) {
+ printf("address@hidden |%2.2X|%2.2X|%02X|%02X| len %d buf
0x%p\n",des,((char*)des)[0], ((char*)des)[1], ((char*)des)[2], ((char*)des)[3],
des->len, des->buf);
+ printf("mal: ready%d wrap%d contm %d last%d first%d intr%d\n",
+ des->mal.bit0_ready, des->mal.bit1_wrap,
des->mal.bit2_contm, des->mal.bit3_last, des->mal.bit4_resv,
des->mal.bit5_intr);
+}
+static int emac_buffer_full(ppc4xx_emac_t *s)
+{
+#if 0
+ int avail, index, boundary;
+
+ index = s->curpag << 8;
+ boundary = s->boundary << 8;
+ if (index < boundary)
+ avail = boundary - index;
+ else
+ avail = (s->stop - s->start) - (index - boundary);
+ if (avail < (MAX_ETH_FRAME_SIZE + 4))
+ return 1;
+#endif
+ return 0;
+}
+
+static int emac_can_receive(void *opaque)
+{
+#if 0
+ NE2000State *s = opaque;
+
+ if (s->cmd & E8390_STOP)
+ return 1;
+ return !ne2000_buffer_full(s);
+#endif
+ return 0;
+}
+
+#define MIN_BUF_SIZE 60
+
+static void emac_receive(void *opaque, const uint8_t *buf, int size)
+{
+ ppc4xx_emac_t* emac = (ppc4xx_emac_t*) opaque;
+
+#ifdef DEBUG_EMAC
+ EmacMalRxDes_dump(emac->rx);
+#endif
+ DPRINT("%d bytes\n", size);
+ if (emac->rxStarted) {
+ if (emac->rx->buf) {
+ if (size<1520) {
+ if (emac->rx[emac->rxPos].mal.bit0_empty) {
+ /* data is allocated with the maximum possible length, on eth =
1520Bytes
+ * len field represent packet size.*/
+ /* We !use Continuos mode, first & last field ignored */
+ unsigned char* dstG = (unsigned char*) ntohl((unsigned long
int)emac->rx[emac->rxPos].buf);
+ unsigned char* dstH= dstG+(unsigned int)phys_ram_base;
+ unsigned short size16 = size;
+/* DPRINT(" Delivery message HOST 0x%p-> GUEST 0x%p,pos%d",
dstH, dstG, emac->rxPos);*/
+ memcpy(dstH, buf, size);
+ emac->rx[emac->rxPos].len = ntohs(size16);
+ emac->rx[emac->rxPos].mal.bit0_empty = 0;
+ if (emac->rx[emac->rxPos].mal.bit5_intr)
+ qemu_irq_raise(emac->mal_irqs_rxeob);
+
+ emac->rxPos += (emac->rx[emac->rxPos].mal.bit1_wrap)?
-(emac->rxPos) : 1;
+ } else {
+ if (++emac->rxLostNum == emac->rxLostLimit) {
+ printf(" %d Message lost, board seem hung up!\n",
emac->rxLostNum);
+ emac->rxLostLimit*=10;
+ }
+ }
+ } else {
+ printf(" Message load, too long for 1 rx des\n");
+ }
+ } else {
+ printf(" Driver !ready (buf==0)\n");
+ }
+ } else {
+ /*printf(" Driver !command rx start yet!!!\n");*/
+ }
+#if 0
+ NE2000State *s = opaque;
+ uint8_t *p;
+ unsigned int total_len, next, avail, len, index, mcast_idx;
+ uint8_t buf1[60];
+ static const uint8_t broadcast_macaddr[6] =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+#if defined(DEBUG_NE2000)
+ printf("NE2000: received len=%d\n", size);
+#endif
+
+ if (s->cmd & E8390_STOP || ne2000_bufstruct mal_emac_bdfer_full(s))
+ return;
+
+ /* XXX: check this */
+ if (s->rxcr & 0x10) {
+ /* promiscuous: receive all */
+ } else {
+ if (!memcmp(buf, broadcast_macaddr, 6)) {
+ /* broadcast address */
+ if (!(s->rxcr & 0x04))
+ return;
+ } else if (buf[0] & 0x01) {
+ /* multicast */
+ if (!(s->rxcr & 0x08))
+ return;
+ mcast_idx = compute_mcast_idx(buf);
+ if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
+ return;
+ } else if (s->mem[0] == buf[0] &&
+ s->mem[2] == buf[1] &&
+ s->mem[4] == buf[2] &&
+ s->mem[6] == buf[3] &&
+ s->mem[8] == buf[4] &&
+ s->mem[10] == buf[5]) {
+ /* match */
+ } else {
+ return;
+ }
+ }
+
+
+ /* if too small buffer, then expand it */
+ if (size < MIN_BUF_SIZE) {
+ memcpy(buf1, buf, size);
+ memset(buf1 + size, 0, MIN_BUF_SIZE - size);
+ buf = buf1;
+ size = MIN_BUF_SIZE;
+ }
+
+ index = s->curpag << 8;
+ /* 4 bytes for header */
+ total_len = size + 4;
+ /* address for next packet (4 bytes for CRC) */
+ next = index + ((total_len + 4 + 255) & ~0xff);
+ if (next >= s->stop)
+ next -= (s->stop - s->start);
+ /* prepare packet header */
+ p = s->mem + index;
+ s->rsr = ENRSR_RXOK; /* receive status */
+ /* XXX: check this */
+ if (buf[0] & 0x01)
+ s->rsr |= ENRSR_PHY;
+ p[0] = s->rsr;
+ p[1] = next >> 8;
+ p[2] = total_len;
+ p[3] = total_len >> 8;
+ index += 4;
+
+ /* write packet data */
+ while (size > 0) {
+ if (index <= s->stop)
+ avail = s->stop - index;
+ else
+ avail = 0;
+ len = size;
+ if (len > avail)
+ len = avail;
+ memcpy(s->mem + index, buf, len);
+ buf += len;
+ index += len;
+ if (index == s->stop)
+ index = s->start;
+ size -= len;
+ }
+ s->curpag = next >> 8;
+
+ /* now we can signal we have received something */
+ s->isr |= ENISR_RX;
+ ne2000_update_irq(s);
+#endif
+}
+
+void emac_ppc405_init(ppc4xx_emac_t* emac, NICInfo *nd)
+{
+ memcpy(&emac->nic, nd, sizeof(NICInfo));
+ /* We are only be able to receive. Sending packet mean receiver action get
up */
+ emac->vc = qemu_new_vlan_client(nd->vlan, emac_receive,
+ NULL/*emac_can_receive*/, emac);
+
+ snprintf(emac->vc->info_str, sizeof(emac->vc->info_str),
+ "emac macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+ emac->nic.macaddr[0],
+ emac->nic.macaddr[1],
+ emac->nic.macaddr[2],
+ emac->nic.macaddr[3],
+ emac->nic.macaddr[4],
+ emac->nic.macaddr[5]);
+}
+
+static void ppc4xx_emac_reset (void *opaque)
+{
+ ppc4xx_emac_t *emac;
+
+ emac = opaque;
+ emac->rx = (struct EmacMalRxDes*) (phys_ram_base + 0x0000C000);
+ emac->tx = (struct EmacMalTxDes*) (phys_ram_base + 0x0000C000 + 16*8);
+ emac->txPos = emac->rxPos = 0;
+ emac->txNum = emac->rxNum = 0;
+ emac->rxStarted = emac->txStarted = 0;
+ emac->rxLostNum=0;
+ emac->rxLostLimit=1;
+}
+/* It looks like a lot of Linux programs assume page size
+ * is 4kB long. This is evil, but we have to deal with it...
+ *
+#define TARGET_PAGE_BITS 12
+ */
+static uint32_t emac_readl (void *opaque, target_phys_addr_t addr)
+{
+ return STACR_OC;
+}
+
+static void emac_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ ppc4xx_emac_t* emac = (ppc4xx_emac_t*)opaque;
+
+/* printf("%s: " PADDRX " val %x\n",__func__, addr, value);*/
+ if (addr-emac->base==0) {
+ /* soft reset */
+ if (value & 0x20000000) {
+ printf("emac: soft reset commanded!\n");
+ ppc4xx_emac_reset(emac); /* Should be protected with a
semaphore, also in emac_receive()? */
+ }
+ /* rx enable */
+ if (value & 0x08000000) {
+ emac->rxStarted=1;
+ printf("emac: rx started!\n");
+ }
+ /* tx enable */
+ if (value & 0x10000000) {
+ emac->txStarted=1;
+ printf("emac: tx started!\n");
+ /* A timer that periodically check packet to send
+ emac->tx_timer = qemu_new_timer();*/
+ }
+ }
+ if (addr-emac->base==8) {
+ if (value & 0x80000000) {
+ if (emac->txStarted==1) {
+ if (emac->tx[emac->txPos].mal.bit0_ready) {
+ unsigned char* dstG = (unsigned char*)
ntohl((unsigned long int)emac->tx[emac->txPos].buf);
+ unsigned char* dstH= dstG+(unsigned
int)phys_ram_base;
+ unsigned short size16 =
ntohs(emac->tx[emac->txPos].len);
+
+ DPRINT("Sending packet on pos %d\n",
emac->txPos);
+ qemu_send_packet(emac->vc, dstH, size16);
+ if (emac->tx[emac->txPos].mal.bit5_intr)
+ qemu_irq_raise(emac->mal_irqs_txeob);
+
+ /* Clear status */
+ emac->tx[emac->txPos].mal.bit0_ready = 0;
+ /* 0x808 is stucked at STACR_OC */
+ emac->txPos +=
(emac->tx[emac->txPos].mal.bit1_wrap)? -(emac->txPos) : 1;
+ } else {printf("Processor goes crazy(ready bit was
0)!!! Stopping tx\n");emac->txStarted=2;}
+ } else {if (emac->txStarted!=2) printf("Tx is
disabled\n");}
+ }
+ }
+}
+static uint32_t emac_readw (void *opaque, target_phys_addr_t addr)
+{
+ printf("Lettura a granularita' word su EMAC " PADDRX "\n",addr);
+ return 0;
+}
+
+static void emac_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ printf("Scrittura a granularita' word su EMAC " PADDRX "\n",addr);
+}
+
+static uint32_t emac_readb (void *opaque, target_phys_addr_t addr)
+{
+ printf("Lettura a granularita' byte su EMAC " PADDRX "\n",addr);
+ return 0;
+}
+
+static void emac_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ printf("Scrittura a granularita' byte su EMAC " PADDRX "\n",addr);
+}
+
+
+static CPUReadMemoryFunc *emac_read[] = {
+ &emac_readb,
+ &emac_readw,
+ &emac_readl,
+};
+
+static CPUWriteMemoryFunc *emac_write[] = {
+ &emac_writeb,
+ &emac_writew,
+ &emac_writel,
+};
+void ppc4xx_emac_init (CPUState *env, ppc4xx_mmio_t *mmio, target_phys_addr_t
offset, NICInfo *nic, qemu_irq mal_irqs[4])
+{
+ ppc4xx_emac_t *emac;
+
+ emac = qemu_mallocz(sizeof(ppc4xx_emac_t));
+ if (emac != NULL) {
+ emac->base = offset;
+#ifdef DEBUG_OPBA
+ printf("%s: offset " PADDRX "\n", __func__, offset);
+#endif
+ ppc4xx_mmio_register(env, mmio, offset, 0x70,
+ emac_read, emac_write, emac);
+ qemu_register_reset(ppc4xx_emac_reset, emac);
+
+ /* One time configuration, HOST related */
+ emac_ppc405_init(emac, nic);
+
+ emac->mal_irqs_txeob = mal_irqs[3];
+ emac->mal_irqs_rxeob = mal_irqs[2];
+ emac->mal_irqs_txerr = mal_irqs[1];
+ emac->mal_irqs_rxerr = mal_irqs[0];
+
+ /* N Time configuration, GUEST related */
+ ppc4xx_emac_reset(emac);
+ }
+}
--- ../../qemu-0.9.1-orig/hw/ppc405_uc.c 2008-01-06 19:38:42.000000000
+0100
+++ qemu-0.9.1/hw/ppc405_uc.c 2008-10-27 14:31:30.975942500 +0100
@@ -21,12 +21,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include <assert.h>
#include "hw.h"
#include "ppc.h"
#include "ppc405.h"
#include "pc.h"
#include "qemu-timer.h"
#include "sysemu.h"
+#include "net.h" /* To have nd_table.h */
extern int loglevel;
extern FILE *logfile;
@@ -1994,7 +1996,7 @@ static target_ulong dcr_read_mal (void *
ret = mal->txcarr;
break;
case MAL0_TXEOBISR:
- ret = mal->txeobisr;
+ ret = (target_ulong)-1/*mal->txeobisr TODO RESTORE WHEN EMAC LINK WAS
INTERACTING WITH MAL */;
break;
case MAL0_TXDEIR:
ret = mal->txdeir;
@@ -2189,6 +2191,7 @@ void ppc405_mal_init (CPUState *env, qem
ppc_dcr_register(env, MAL0_RCBS1,
mal, &dcr_read_mal, &dcr_write_mal);
}
+/* return mal;*/
}
/*****************************************************************************/
@@ -2281,6 +2284,15 @@ enum {
PPC405CR_CLK_NB = 7,
};
+/* Addedum related to 405GPr approximated as 405EP + CR0 */
+static target_ulong dcr_read_cr0 (void *opaque, int dcrn)
+{
+ return 0;
+}
+static void dcr_write_cr0 (void *opaque, int dcrn, target_ulong val)
+{
+}
+
typedef struct ppc405cr_cpc_t ppc405cr_cpc_t;
struct ppc405cr_cpc_t {
clk_setup_t clk_setup[PPC405CR_CLK_NB];
@@ -2540,6 +2552,7 @@ static void ppc405cr_cpc_init (CPUState
}
}
+#define INTN(a) (31-a)
CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
target_phys_addr_t ram_sizes[4],
uint32_t sysclk, qemu_irq **picp,
@@ -2892,7 +2905,7 @@ static void ppc405ep_cpc_init (CPUState
#endif
}
}
-
+qemu_irq _mal_irqs[4];
CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
target_phys_addr_t ram_sizes[2],
uint32_t sysclk, qemu_irq **picp,
@@ -2930,51 +2943,63 @@ CPUState *ppc405ep_init (target_phys_add
pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
*picp = pic;
/* SDRAM controller */
- ppc405_sdram_init(env, pic[14], 2, ram_bases, ram_sizes, do_init);
+ ppc405_sdram_init(env, pic[INTN(17)]/* Ecc?*/, 2, ram_bases, ram_sizes,
do_init);
offset = 0;
for (i = 0; i < 2; i++)
offset += ram_sizes[i];
/* External bus controller */
ppc405_ebc_init(env);
/* DMA controller */
- dma_irqs[0] = pic[26];
- dma_irqs[1] = pic[25];
- dma_irqs[2] = pic[24];
- dma_irqs[3] = pic[23];
+ dma_irqs[0] = pic[INTN(5)];
+ dma_irqs[1] = pic[INTN(6)];
+ dma_irqs[2] = pic[INTN(7)];
+ dma_irqs[3] = pic[INTN(8)];
ppc405_dma_init(env, dma_irqs);
/* IIC controller */
- ppc405_i2c_init(env, mmio, 0x500, pic[29]);
+ ppc405_i2c_init(env, mmio, 0x500, pic[INTN(2)]);
/* GPIO */
ppc405_gpio_init(env, mmio, 0x700);
/* Serial ports */
if (serial_hds[0] != NULL) {
- ppc405_serial_init(env, mmio, 0x300, pic[31], serial_hds[0]);
+ ppc405_serial_init(env, mmio, 0x300, pic[INTN(0)], serial_hds[0]);
}
if (serial_hds[1] != NULL) {
- ppc405_serial_init(env, mmio, 0x400, pic[30], serial_hds[1]);
+ ppc405_serial_init(env, mmio, 0x400, pic[INTN(1)], serial_hds[1]);
}
/* OCM */
ppc405_ocm_init(env, ram_sizes[0] + ram_sizes[1]);
offset += 4096;
/* GPT */
- gpt_irqs[0] = pic[12];
- gpt_irqs[1] = pic[11];
- gpt_irqs[2] = pic[10];
- gpt_irqs[3] = pic[9];
- gpt_irqs[4] = pic[8];
+ gpt_irqs[0] = pic[INTN(19)];
+ gpt_irqs[1] = pic[INTN(20)];
+ gpt_irqs[2] = pic[INTN(21)];
+ gpt_irqs[3] = pic[INTN(22)];
+ gpt_irqs[4] = pic[INTN(23)];
ppc4xx_gpt_init(env, mmio, 0x000, gpt_irqs);
/* PCI */
/* Uses pic[28], pic[15], pic[13] */
/* MAL */
- mal_irqs[0] = pic[20];
- mal_irqs[1] = pic[19];
- mal_irqs[2] = pic[18];
- mal_irqs[3] = pic[17];
+ mal_irqs[3] = pic[INTN(11)];
+ mal_irqs[2] = pic[INTN(12)];
+ mal_irqs[1] = pic[INTN(13)];
+ mal_irqs[0] = pic[INTN(14)];
+
ppc405_mal_init(env, mal_irqs);
- /* Ethernet */
+ /* EMAC (Ethernet Media Access Controller) */
+ {
+ void ppc4xx_emac_init(CPUState *env, ppc4xx_mmio_t *mmio,
target_phys_addr_t offset, NICInfo* nic, qemu_irq irq[4]);
+ ppc4xx_emac_init(env, mmio, 0x800, &nd_table[0], mal_irqs);
+ }
/* Uses pic[22], pic[16], pic[14] */
/* CPU control */
ppc405ep_cpc_init(env, clk_setup, sysclk);
+
+ /* Add address@hidden DCR: opaque represent integer of value */
+ ppc_dcr_register(env, PPC405CR_CPC0_CR0, NULL, &dcr_read_cr0,
&dcr_write_cr0);
+ /* This is typical of 405GPr. CPC0_ECR = 0xAA.*/
+ ppc_dcr_register(env, 0xAA/* CPC0_ECR */, NULL, &dcr_read_cr0,
&dcr_write_cr0);
+ ppc_dcr_register(env, 0xB2/* CPC0_CR1 */, NULL, &dcr_read_cr0,
&dcr_write_cr0);
+
*offsetp = offset;
return env;
===================================================================
=== PATCH TO ENHACE FLASH DEVICE (hw\pflash_cfi02.c, cpu-all.h) ===
===================================================================
--- qemu-0.9.1-orig/cpu-all.h 2008-01-06 19:38:42.000000000 +0100
+++ qemu-0.9.1/cpu-all.h 2008-06-11 13:34:24.222465500 +0200
@@ -773,6 +773,8 @@ target_phys_addr_t cpu_get_phys_page_deb
#define CPU_LOG_PCALL (1 << 6)
#define CPU_LOG_IOPORT (1 << 7)
#define CPU_LOG_TB_CPU (1 << 8)
+#define FLASH_LOG_CFI (1 << 9)
+#define FPGA_LOG_ACCESS (1 << 10)
/* define log items */
typedef struct CPULogItem {
--- qemu-0.9.1-orig/hw/pflash_cfi02.c 2008-01-06 19:38:42.000000000 +0100
+++ qemu-0.9.1/hw/pflash_cfi02.c 2008-10-27 14:51:52.827229100 +0100
@@ -2,6 +2,7 @@
* CFI parallel flash with AMD command set emulation
*
* Copyright (c) 2005 Jocelyn Mayer
+ * Copyright (c) 2008 Lionetti Salvatore
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,7 +23,7 @@
* For now, this code can emulate flashes of 1, 2 or 4 bytes width.
* Supported commands/modes are:
* - flash read
- * - flash write
+ * - flash write (also buffer mode)
* - flash ID read
* - sector erase
* - chip erase
@@ -34,24 +35,33 @@
* It does not implement software data protection as found in many real chips
* It does not implement erase suspend/resume commands
* It does not implement multiple sectors erase
+ *
+ * Revisione done to optimize, (the next'll be mmap()), expecially for
WriteBufferLoad command.
+ * Use different name for structure, so multiple device could be
address@hidden time
*/
#include "hw.h"
#include "flash.h"
#include "qemu-timer.h"
#include "block.h"
+#include "cpu-all.h" /* To have FLASH_LOG_CFI */
+#include "exec-all.h" /* To have loglevel */
-//#define PFLASH_DEBUG
+#define USE_SIMPLE_TABLE
+#define PFLASH_DEBUG
#ifdef PFLASH_DEBUG
+static int howt=0;
#define DPRINTF(fmt, args...) \
do { \
- printf("PFLASH: " fmt , ##args); \
+ if (loglevel & FLASH_LOG_CFI) {printf("PFLASH: " fmt , ##args);}
\
+ howt++; \
} while (0)
#else
#define DPRINTF(fmt, args...) do { } while (0)
#endif
-struct pflash_t {
+#define pflash_cfi02_t pflash_t
+struct pflash_cfi02_t {
BlockDriverState *bs;
target_phys_addr_t base;
uint32_t sector_len;
@@ -59,21 +69,77 @@ struct pflash_t {
int width;
int wcycle; /* if 0, the flash is read normally */
int bypass;
+ uint32_t bytes2write; /* In buffer load mode, must remember the number of
bytes to elaborate */
+ uint8_t buffer_loading; /* For buffer load mode 1 mean read nword-1 &
apply write & apply end command */
+ uint32_t buffer_loading_start;
+ uint32_t buffer_loading_end;
int ro;
uint8_t cmd;
uint8_t status;
uint16_t ident[4];
uint8_t cfi_len;
- uint8_t cfi_table[0x52];
+ uint8_t cfi_table[0x80];
QEMUTimer *timer;
ram_addr_t off;
int fl_mem;
void *storage;
+
+ /* Layer needed to optimize (driver common size) Vs (device common size)
+ * Used by timer() & update(), update() use SIGNED!!!
+ * A simple way to represent a list of number. */
+ int pendingW;
+ int fstSector;
+ int curSector;
+
+ int how_memory_mapped; /*
+ memory_mapped
+ Reset=> off|fl_mem|ROMD, 0
+ * timer=> off|fl_mem|ROMD, 0
+ * write=> fl_mem 1
+ *
+ * off costante
+ * fl_mem costante (rif all'io costruito, f() di rw...)
+ */
};
+static void pflash_cfi02_core_reset (void *opaque) {
+ struct pflash_cfi02_t *pfl = (struct pflash_cfi02_t*)opaque;
+
+ pfl->wcycle = 0;
+ pfl->cmd = 0;
+ pfl->status = 0;
+
+ pfl->bytes2write = 0;
+ pfl->buffer_loading = 0;
+ pfl->buffer_loading_start = 0;
+ pfl->buffer_loading_end = 0;
+
+/* pfl->pendingW = pfl->fstSector = curSector = 0; Lost current write? */
+
+ pfl->how_memory_mapped = 0;
+
+ cpu_register_physical_memory(pfl->base, pfl->total_len,
+ pfl->off | pfl->fl_mem | IO_MEM_ROMD);
+}
+
+static void pflash_cfi02_reset (void *opaque) {
+ struct pflash_cfi02_t *pfl = (struct pflash_cfi02_t*)opaque;
+
+ qemu_del_timer(pfl->timer);
+#if 0 /* XXX: there should be a bit to set up read-only,
+ * the same way the hardware does (with WP pin).
+ */
+ pfl->ro = 1;
+#else
+ pfl->ro = 0;
+#endif
+ pfl->bypass = 0;
+ pflash_cfi02_core_reset(pfl);
+ printf("Resetting cfi chip!\n");
+}
static void pflash_timer (void *opaque)
{
- pflash_t *pfl = opaque;
+ struct pflash_cfi02_t *pfl = opaque;
DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
/* Reset flash */
@@ -81,27 +147,29 @@ static void pflash_timer (void *opaque)
if (pfl->bypass) {
pfl->wcycle = 2;
} else {
+ if (pfl->how_memory_mapped) {
cpu_register_physical_memory(pfl->base, pfl->total_len,
pfl->off | IO_MEM_ROMD | pfl->fl_mem);
+ pfl->how_memory_mapped = 0;
+ }
pfl->wcycle = 0;
}
pfl->cmd = 0;
}
-static uint32_t pflash_read (pflash_t *pfl, uint32_t offset, int width)
+static uint32_t pflash_read (struct pflash_cfi02_t *pfl, uint32_t offset, int
width)
{
- uint32_t boff;
+ uint32_t boff, _boff;
uint32_t ret;
uint8_t *p;
- DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset);
ret = -1;
offset -= pfl->base;
- boff = offset & 0xFF;
+ _boff = offset & 0xFF;
if (pfl->width == 2)
- boff = boff >> 1;
+ boff = _boff >> 1;
else if (pfl->width == 4)
- boff = boff >> 2;
+ boff = _boff >> 2;
switch (pfl->cmd) {
default:
/* This should never happen : reset state & treat it as a read*/
@@ -114,32 +182,34 @@ static uint32_t pflash_read (pflash_t *p
flash_read:
/* Flash area read */
p = pfl->storage;
+ p += offset;
+common_read:
switch (width) {
case 1:
- ret = p[offset];
+ ret = p[0];
// DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
break;
case 2:
#if defined(TARGET_WORDS_BIGENDIAN)
- ret = p[offset] << 8;
- ret |= p[offset + 1];
+ ret = p[0] << 8;
+ ret |= p[1];
#else
- ret = p[offset];
- ret |= p[offset + 1] << 8;
+ ret = p[0];
+ ret |= p[1] << 8;
#endif
// DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
break;
case 4:
#if defined(TARGET_WORDS_BIGENDIAN)
- ret = p[offset] << 24;
- ret |= p[offset + 1] << 16;
- ret |= p[offset + 2] << 8;
- ret |= p[offset + 3];
+ ret = p[0] << 24;
+ ret |= p[1] << 16;
+ ret |= p[2] << 8;
+ ret |= p[3];
#else
- ret = p[offset];
- ret |= p[offset + 1] << 8;
- ret |= p[offset + 2] << 16;
- ret |= p[offset + 3] << 24;
+ ret = p[0];
+ ret |= p[1] << 8;
+ ret |= p[2] << 16;
+ ret |= p[3] << 24;
#endif
// DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
break;
@@ -177,32 +247,80 @@ static uint32_t pflash_read (pflash_t *p
break;
case 0x98:
/* CFI query mode */
- if (boff > pfl->cfi_len)
+ if (_boff > pfl->cfi_len)
ret = 0;
- else
- ret = pfl->cfi_table[boff];
+ else {
+#ifndef USE_SIMPLE_TABLE
+ ret = pfl->cfi_table[_boff];
+#else
+ p = &pfl->cfi_table[_boff];
+ goto common_read;
+#endif
+ }
break;
}
+ DPRINTF("%s: offset " TARGET_FMT_lx " value 0x%x width %d func %x\n",
__func__, _boff, ret, width, pfl->cmd);
return ret;
}
-/* update flash content on disk */
-static void pflash_update(pflash_t *pfl, int offset,
+/*
+ * update flash content on disk
+ * Act as intermediate between
+ * - 32B from Driver
+ * - 512B of device
+ * Optimize only when length==32 & Write only when sector is crossed
+ * Need a timer that commit if no more write? No if we write every 512B
+ * RAM is always updated
+ */
+#define PFLASH_512BLOCK 8 /* 0 -> sector of 512B, 1 -> sector of 1024B,
... */
+#define PFLASH_XBLOCK (9 + PFLASH_512BLOCK)
+#define PFLASH_XBOUND ((1 << PFLASH_XBLOCK)-1)
+static inline void pflash_update(struct pflash_cfi02_t *pfl, int offset,
int size)
{
- int offset_end;
- if (pfl->bs) {
- offset_end = offset + size;
- /* round to sectors */
- offset = offset >> 9;
- offset_end = (offset_end + 511) >> 9;
- bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
- offset_end - offset);
- }
+ int offset_end;
+ int grouped = 0; /* Current version is linked with internal cache */
+ int forcefl = 0; /* Force flush after all op */
+
+ if (pfl->bs) {
+ int _offset = offset;
+ offset = offset >> PFLASH_XBLOCK;
+
+ /* Try to group sequential write
+ * Stop also if found a sector bound! (so avoid timer for now)
*/
+ if (size == 32) {
+ forcefl = (((_offset+size)&PFLASH_XBOUND/*511*/)==0);
+ if (pfl->pendingW) {
+ /* Try to group with previous write() */
+ grouped = (offset == pfl->curSector);
+ } else {
+ /* First write in this group */
+ pfl->fstSector = offset;
+ pfl->curSector = offset;
+ pfl->pendingW = 1;
+ grouped = 1;
+ }
+ }
+
+ /* Commit any pending write if the case. */
+ if ((pfl->pendingW && !grouped) || forcefl) {
+ DPRINTF("%s: flushing sectors " TARGET_FMT_lx " ns
%d\n", __func__, pfl->fstSector, pfl->curSector - pfl->fstSector + 1);
+ bdrv_write(pfl->bs, pfl->fstSector<<PFLASH_512BLOCK,
pfl->storage + (pfl->fstSector << (PFLASH_XBLOCK)), (pfl->curSector -
pfl->fstSector + 1)<<(PFLASH_512BLOCK));
+ pfl->pendingW = 0;
+ }
+
+ /* Current write (!in case we just do it with previous commit)
*/
+ if (!grouped) {
+ offset_end = _offset + size;
+ /* round to sectors */
+ offset_end = (offset_end + 511) >> 9;
+ DPRINTF("%s: flushing sectors " TARGET_FMT_lx " ns
%d\n", __func__, offset, offset_end - offset);
+ bdrv_write(pfl->bs, offset, pfl->storage + (offset <<
9), offset_end - offset);
+ }
+ }
}
-
-static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value,
+static void pflash_write (struct pflash_cfi02_t *pfl, uint32_t offset,
uint32_t value,
int width)
{
uint32_t boff;
@@ -212,29 +330,35 @@ static void pflash_write (pflash_t *pfl,
/* WARNING: when the memory area is in ROMD mode, the offset is a
ram offset, not a physical address */
cmd = value;
- if (pfl->cmd != 0xA0 && cmd == 0xF0) {
-#if 0
- DPRINTF("%s: flash reset asked (%02x %02x)\n",
- __func__, pfl->cmd, cmd);
+ if (pfl->cmd != 0xA0 && pfl->cmd != 0x25 && cmd == 0xF0) {
+#if 1
+ DPRINTF("%s: flash reset asked, cmd(%02x) " TARGET_FMT_lx " %x %d\n",
+ __func__, pfl->cmd, (char*)offset-(char*)pfl->storage, value,
width);
#endif
goto reset_flash;
}
- DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__,
- offset, value, width, pfl->wcycle);
+
if (pfl->wcycle == 0)
offset -= (uint32_t)(long)pfl->storage;
- else
+ else {
+ DPRINTF("PFLASH_WRITE - 0xFE000000:\n");
offset -= pfl->base;
+ }
- DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__,
- offset, value, width);
/* Set the device in I/O access mode */
+ if (pfl->how_memory_mapped==0) {
cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
+ pfl->how_memory_mapped = 1;
+ }
boff = offset & (pfl->sector_len - 1);
if (pfl->width == 2)
boff = boff >> 1;
else if (pfl->width == 4)
boff = boff >> 2;
+
+ DPRINTF("%s: offset " TARGET_FMT_lx " val %x wid %d wcycle %d\n", __func__,
+ boff, value, width, pfl->wcycle);
+
switch (pfl->wcycle) {
case 0:
/* We're in read mode */
@@ -246,26 +370,40 @@ static void pflash_write (pflash_t *pfl,
pfl->cmd = 0x98;
return;
}
- if (boff != 0x555 || cmd != 0xAA) {
+ if (!(boff == 0x555 || boff == 0x5555) || cmd != 0xAA) {
DPRINTF("%s: unlock0 failed " TARGET_FMT_lx " %02x %04x\n",
__func__, boff, cmd, 0x555);
goto reset_flash;
}
DPRINTF("%s: unlock sequence started\n", __func__);
+ pfl->wcycle++;
break;
case 1:
/* We started an unlock sequence */
check_unlock1:
- if (boff != 0x2AA || cmd != 0x55) {
+ if (!(boff == 0x2AA || boff == 0x2AAA) || cmd != 0x55) {
DPRINTF("%s: unlock1 failed " TARGET_FMT_lx " %02x\n", __func__,
boff, cmd);
goto reset_flash;
}
DPRINTF("%s: unlock sequence done\n", __func__);
+ pfl->wcycle++;
break;
case 2:
+ /* Command write buffer load. */
+ if (boff==0 && cmd==0x25) {
+ /* Wait #word - 1 on same addr */
+ DPRINTF("%s: start buffer load, expect len4next write\n",
__func__);
+ pfl->buffer_loading=1;
+ pfl->wcycle--;
+ } else if (pfl->buffer_loading) {
+ pfl->bytes2write=(value+1)<<(width>>1);
+ DPRINTF("%s: got %d bytes2write\n", __func__, pfl->bytes2write);
+ pfl->wcycle++;
+ break;
+ } else
/* We finished an unlock sequence */
- if (!pfl->bypass && boff != 0x555) {
+ if (!pfl->bypass && (boff != 0x555 && boff != 0x5555)) {
DPRINTF("%s: command failed " TARGET_FMT_lx " %02x\n", __func__,
boff, cmd);
goto reset_flash;
@@ -273,23 +411,34 @@ static void pflash_write (pflash_t *pfl,
switch (cmd) {
case 0x20:
pfl->bypass = 1;
+ printf("Requesting bypass\n");
goto do_bypass;
case 0x80:
case 0x90:
case 0xA0:
- pfl->cmd = cmd;
- DPRINTF("%s: starting command %02x\n", __func__, cmd);
- break;
+ case 0x25:
+ pfl->cmd = cmd;
+ DPRINTF("%s: starting command %02x\n", __func__, cmd);
+ break;
default:
DPRINTF("%s: unknown command %02x\n", __func__, cmd);
goto reset_flash;
}
- break;
+ pfl->wcycle++;
+ break;
case 3:
switch (pfl->cmd) {
case 0x80:
/* We need another unlock sequence */
goto check_unlock0;
+ case 0x25:
+ if (pfl->bytes2write==0) {
+ printf("%s: buffer mode have 0 bytes2write!\n", __func__);
+ goto reset_flash;
+ }
+ if (!pfl->buffer_loading_start)
+ pfl->buffer_loading_start=offset;
+ pfl->buffer_loading_end=offset+width;
case 0xA0:
DPRINTF("%s: write data offset " TARGET_FMT_lx " %08x %d\n",
__func__, offset, value, width);
@@ -297,7 +446,7 @@ static void pflash_write (pflash_t *pfl,
switch (width) {
case 1:
p[offset] &= value;
- pflash_update(pfl, offset, 1);
+ if (pfl->cmd!=0x25) pflash_update(pfl, offset, 1);
break;
case 2:
#if defined(TARGET_WORDS_BIGENDIAN)
@@ -307,7 +456,7 @@ static void pflash_write (pflash_t *pfl,
p[offset] &= value;
p[offset + 1] &= value >> 8;
#endif
- pflash_update(pfl, offset, 2);
+ if (pfl->cmd!=0x25) pflash_update(pfl, offset, 2);
break;
case 4:
#if defined(TARGET_WORDS_BIGENDIAN)
@@ -321,14 +470,27 @@ static void pflash_write (pflash_t *pfl,
p[offset + 2] &= value >> 16;
p[offset + 3] &= value >> 24;
#endif
- pflash_update(pfl, offset, 4);
+ if (pfl->cmd!=0x25) pflash_update(pfl, offset, 4);
break;
}
- pfl->status = 0x00 | ~(value & 0x80);
- /* Let's pretend write is immediate */
- if (pfl->bypass)
- goto do_bypass;
- goto reset_flash;
+ /* In buffer load mode, status is available only after requested
bytes2write */
+ if (pfl->cmd!=0x25) {
+ pfl->status = 0x00 | ~(value & 0x80);
+ /* Let's pretend write is immediate */
+ if (pfl->bypass)
+ goto do_bypass;
+ goto reset_flash;
+ } else {
+ if (pfl->bytes2write>=width)
+ pfl->bytes2write-=width;
+ else {
+ printf("%s: buffer mode discarded %d bytes at end
of transfer\n",__func__,width-pfl->bytes2write);
+ pfl->bytes2write=0;
+ }
+ if (pfl->bytes2write)
+ pfl->wcycle--; /* Dangerous if use timer */
+ }
+ break;
case 0x90:
if (pfl->bypass && cmd == 0x00) {
/* Unlock bypass reset */
@@ -343,6 +505,8 @@ static void pflash_write (pflash_t *pfl,
__func__, pfl->cmd);
goto reset_flash;
}
+ pfl->wcycle++;
+ break;
case 4:
switch (pfl->cmd) {
case 0xA0:
@@ -351,6 +515,13 @@ static void pflash_write (pflash_t *pfl,
return;
case 0x80:
goto check_unlock1;
+ case 0x25:
+ DPRINTF("%s: Buffer load terminated %s (%d bytes remaining)\n",
__func__, !pfl->bytes2write?"Ok" : "NOK", pfl->bytes2write);
+ /* Update written sequence */
+ pflash_update(pfl, pfl->buffer_loading_start,
pfl->buffer_loading_end - pfl->buffer_loading_start);
+ pfl->buffer_loading = 0;
+ pfl->buffer_loading_start = 0;
+ goto reset_flash;
default:
/* Should never happen */
DPRINTF("%s: invalid command state %02x (wc 4)\n",
@@ -384,9 +555,10 @@ static void pflash_write (pflash_t *pfl,
memset(p + offset, 0xFF, pfl->sector_len);
pflash_update(pfl, offset, pfl->sector_len);
pfl->status = 0x00;
- /* Let's wait 1/2 second before sector erase is done */
+ /* Let's wait 1/2 second before sector erase is done
qemu_mod_timer(pfl->timer,
- qemu_get_clock(vm_clock) + (ticks_per_sec / 2));
+ qemu_get_clock(vm_clock) + (ticks_per_sec / 2));*/
+ pflash_timer(pfl);
break;
default:
DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
@@ -417,17 +589,11 @@ static void pflash_write (pflash_t *pfl,
DPRINTF("%s: invalid write state (wc 7)\n", __func__);
goto reset_flash;
}
- pfl->wcycle++;
-
return;
/* Reset flash */
reset_flash:
- cpu_register_physical_memory(pfl->base, pfl->total_len,
- pfl->off | IO_MEM_ROMD | pfl->fl_mem);
- pfl->bypass = 0;
- pfl->wcycle = 0;
- pfl->cmd = 0;
+ pflash_cfi02_core_reset(pfl);
return;
do_bypass:
@@ -444,14 +610,14 @@ static uint32_t pflash_readb (void *opaq
static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr)
{
- pflash_t *pfl = opaque;
+ struct pflash_cfi02_t *pfl = opaque;
return pflash_read(pfl, addr, 2);
}
static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr)
{
- pflash_t *pfl = opaque;
+ struct pflash_cfi02_t *pfl = opaque;
return pflash_read(pfl, addr, 4);
}
@@ -465,7 +631,7 @@ static void pflash_writeb (void *opaque,
static void pflash_writew (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
- pflash_t *pfl = opaque;
+ struct pflash_cfi02_t *pfl = opaque;
pflash_write(pfl, addr, value, 2);
}
@@ -473,7 +639,7 @@ static void pflash_writew (void *opaque,
static void pflash_writel (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
- pflash_t *pfl = opaque;
+ struct pflash_cfi02_t *pfl = opaque;
pflash_write(pfl, addr, value, 4);
}
@@ -490,6 +656,7 @@ static CPUReadMemoryFunc *pflash_read_op
&pflash_readl,
};
+#ifndef USE_SIMPLE_TABLE
/* Count trailing zeroes of a 32 bits quantity */
static int ctz32 (uint32_t n)
{
@@ -523,14 +690,14 @@ static int ctz32 (uint32_t n)
return ret;
}
-
-pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
+#endif
+void *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
BlockDriverState *bs, uint32_t sector_len,
int nb_blocs, int width,
uint16_t id0, uint16_t id1,
uint16_t id2, uint16_t id3)
{
- pflash_t *pfl;
+ struct pflash_cfi02_t *pfl;
int32_t total_len;
total_len = sector_len * nb_blocs;
@@ -540,39 +707,31 @@ pflash_t *pflash_cfi02_register(target_p
total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
return NULL;
#endif
- pfl = qemu_mallocz(sizeof(pflash_t));
+ pfl = qemu_mallocz(sizeof(struct pflash_cfi02_t));
if (pfl == NULL)
return NULL;
+
+ /* One time initialization, HOST related. */
pfl->storage = phys_ram_base + off;
pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops,
pfl);
pfl->off = off;
- cpu_register_physical_memory(base, total_len,
- off | pfl->fl_mem | IO_MEM_ROMD);
- pfl->bs = bs;
- if (pfl->bs) {
- /* read the initial flash content */
- bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
- }
-#if 0 /* XXX: there should be a bit to set up read-only,
- * the same way the hardware does (with WP pin).
- */
- pfl->ro = 1;
-#else
- pfl->ro = 0;
-#endif
pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
pfl->base = base;
pfl->sector_len = sector_len;
pfl->total_len = total_len;
pfl->width = width;
- pfl->wcycle = 0;
- pfl->cmd = 0;
- pfl->status = 0;
+
+ pfl->bs = bs;
+ if (pfl->bs) {
+ /* read the initial flash content */
+ bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
+ }
pfl->ident[0] = id0;
pfl->ident[1] = id1;
pfl->ident[2] = id2;
pfl->ident[3] = id3;
+#ifndef USE_SIMPLE_TABLE
/* Hardcoded CFI table (mostly from SG29 Spansion flash) */
pfl->cfi_len = 0x52;
/* Standard "QRY" string */
@@ -632,6 +791,29 @@ pflash_t *pflash_cfi02_register(target_p
pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
pfl->cfi_table[0x2F] = sector_len >> 8;
pfl->cfi_table[0x30] = sector_len >> 16;
+#else
+ /* Don't know why but driver expect this
+ * Now this table have !to be 'interpolated' basing on width.
+ * Moreover we were called with width == 4. */
+ pfl->cfi_len = 0x80;
+ pfl->cfi_table[0x21] = 'Q';
+ pfl->cfi_table[0x23] = 'R';
+ pfl->cfi_table[0x25] = 'Y';
+ pfl->cfi_table[0x27] = 2; /* oam command set */
+ pfl->cfi_table[0x4F] = 25; /* size = 2^x Bytes*/
+ pfl->cfi_table[0x59] = 1; /* num of blocks */
+ pfl->cfi_table[0x5b] = 255; /* sectors */
+ pfl->cfi_table[0x61] = 2; /* sector size */
+#endif
+ /* Per reset initialization, GUEST related.
+ *
+ * Reset action is needed, since memory attribute is changed over the
writing process
+ * @reset we address@hidden read from flash.
+ * Actually we stop all started action (reset chip)
+ */
+ pflash_cfi02_reset(pfl);
+ qemu_register_reset(&pflash_cfi02_reset, pfl);
+
return pfl;
}
This is a list of all file modified, just to describe all modification done.
Modified file in private view:
cpu-all.h
- Add flag
exec.c
- Change in log filename
- help message for new flag
exec-all.h
- Add logfilename as extern
vl.c
- change /tmp/... in (char*)logfilename
hw/pflash_cfi02.c
- Add 'buffer load mode'
- Some optimization in write
hw/ppc.c
- On uP reset, cancel any pending WDT, PIT, FIT
hw/ppc405_uc.c
- Change in bcr from FFE28000 -> FE0A2000
- Change ocm from qemu code
- I2C controller now have hook to call board specific behaviour
- 405GPr approximated as 405EP + CR0
- ppc405cr_init() now return a list of created device,
so in qemu code one can interact with they (es ocm, bcr)
- in ppc405ep_init() start EMAC layer, to have networking
hw\emac.c
- Simulate EMAC, a 'FastEthController' for ppc405GPr uP, only on LittleEndian
host.
target-ppc\translate.c
- Enable some bad access to !existing spr, unassigned memroy region (no machine
{data|instruction} exception start yet)
Have a good day
--- Sab 25/10/08, Andreas Färber <address@hidden> ha scritto:
> Da: Andreas Färber <address@hidden>
> Oggetto: Re: [Qemu-devel] TCG on PowerPC arch
> A: "Salvatore Lionetti" <address@hidden>
> Cc: address@hidden
> Data: Sabato 25 ottobre 2008, 22:51
> Hi,
>
> Am 22.10.2008 um 10:18 schrieb Salvatore Lionetti:
>
> > There need help about TCG porting on PowerPC?
> > I'm moderating skilled on PowerPC ASM, expecially
> on PPC405GPr
> > For this last uP, i've build a board so could also
> test result.
>
> What about your previous ppc patch? Have you had time to
> rework it
> yet, so that it can be applied?
>
> Regards,
> Andreas
Scopri il blog di Yahoo! Mail:
Trucchi, novità e scrivi la tua opinione.
http://www.ymailblogit.com/blog
- [Qemu-devel] TCG on PowerPC arch, Salvatore Lionetti, 2008/10/22
- Re: [Qemu-devel] TCG on PowerPC arch, Aurelien Jarno, 2008/10/23
- Re: [Qemu-devel] TCG on PowerPC arch, Andreas Färber, 2008/10/25
- Re: [Qemu-devel] TCG on PowerPC arch,
Salvatore Lionetti <=
- Re: [Qemu-devel] TCG on PowerPC arch, Salvatore Lionetti, 2008/10/27
- Re: [Qemu-devel] TCG on PowerPC arch, Paul Brook, 2008/10/27
- Re: [Qemu-devel] TCG on PowerPC arch, Andreas Färber, 2008/10/28
- Re: [Qemu-devel] TCG on PowerPC arch, Salvatore Lionetti, 2008/10/29
- Re: [Qemu-devel] TCG on PowerPC arch, Hollis Blanchard, 2008/10/29
- Re: [Qemu-devel] TCG on PowerPC arch, Salvatore Lionetti, 2008/10/30
- Re: [Qemu-devel] TCG on PowerPC arch, Hollis Blanchard, 2008/10/31