diff -urN gxemul-0.4.3/src/cpus/cpu_dyntrans.c gxemul-0.4.3.godson/src/cpus/cpu_dyntrans.c --- gxemul-0.4.3/src/cpus/cpu_dyntrans.c 2006-10-28 00:03:01.000000000 +0800 +++ gxemul-0.4.3.godson/src/cpus/cpu_dyntrans.c 2006-11-09 21:34:44.000000000 +0800 @@ -761,7 +761,9 @@ /* If the offset is 0 (or ppp is NULL), then we need to create a new "default" empty translation page. */ - if (ppp == NULL) { + /* if (ppp == NULL) { */ + /* the case of offset being 0. plj */ + if (ppp == NULL || physpage_ofs == 0) { /* fatal("CREATING page %lli (physaddr 0x%"PRIx64"), table " "index %i\n", (long long)pagenr, (uint64_t)physaddr, (int)table_index); */ @@ -1155,6 +1157,49 @@ uint64_t #endif addr_page = addr & ~(DYNTRANS_PAGESIZE - 1); +#ifdef DYNTRANS_MIPS + int i = 0; +#ifdef MODE32 + uint32_t pagesize = DYNTRANS_PAGESIZE; +#else + uint64_t pagesize = DYNTRANS_PAGESIZE; +#endif +#endif + if (flags & INVALIDATE_ALL) { + /* fatal("all\n"); */ + for (r=0; rcd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { + DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd. + DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page, + 0); + cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0; + } + } + return; + } +#ifdef DYNTRANS_MIPS + if (cpu->cd.mips.cpu_type.rev == MIPS_GODSON2) { + switch ((cpu->cd.mips.coproc[0]->reg[COP0_PAGEMASK] & PAGEMASK_MASK) >> PAGEMASK_SHIFT) { + case 0: + pagesize = 1 << 12; + break; + case 3: + pagesize = 1 << 14; + break; + case 0xf: + pagesize = 1 << 16; + break; + case 0x3f: + pagesize = 1 << 18; + break; + default: + pagesize = DYNTRANS_PAGESIZE; + break; + } + } + addr_page = addr & ~(pagesize - 1); + for (i = 0; i*DYNTRANS_PAGESIZE < pagesize; i++) { +#endif /* fatal("invalidate(): "); */ @@ -1216,6 +1261,10 @@ .valid = 0; } } +#ifdef DYNTRANS_MIPS + addr_page += DYNTRANS_PAGESIZE; + } /* End for */ +#endif } #endif /* DYNTRANS_INVALIDATE_TC */ @@ -1237,8 +1286,38 @@ uint64_t #endif vaddr_page, paddr_page; +#ifdef DYNTRANS_MIPS + int i = 0; +#ifdef MODE32 + uint32_t pagesize = DYNTRANS_PAGESIZE; +#else + uint64_t pagesize = DYNTRANS_PAGESIZE; +#endif + if (cpu->cd.mips.cpu_type.rev == MIPS_GODSON2) { + switch ((cpu->cd.mips.coproc[0]->reg[COP0_PAGEMASK] & PAGEMASK_MASK) >> PAGEMASK_SHIFT) { + case 0: + pagesize = 1 << 12; + break; + case 3: + pagesize = 1 << 14; + break; + case 0xf: + pagesize = 1 << 16; + break; + case 0x3f: + pagesize = 1 << 18; + break; + default: + pagesize = DYNTRANS_PAGESIZE; + break; + } + } + addr &= ~(pagesize-1); + for (i = 0; i*DYNTRANS_PAGESIZE < pagesize; i++) { +#else addr &= ~(DYNTRANS_PAGESIZE-1); +#endif /* printf("DYNTRANS_INVALIDATE_TC_CODE addr=0x%08x flags=%i\n", (int)addr, flags); */ @@ -1357,6 +1436,10 @@ } } } +#ifdef DYNTRANS_MIPS + addr += DYNTRANS_PAGESIZE; + } /* End of for */ +#endif } #endif /* DYNTRANS_INVALIDATE_TC_CODE */ @@ -1392,6 +1475,59 @@ " p=0x%016"PRIx64"\n", (uint64_t)vaddr_page, host_page, writeflag, (uint64_t)paddr_page); */ #endif +#ifdef DYNTRANS_MIPS + int i = 0; + unsigned char *memblock; + unsigned char *old_page; + int dyntrans = 0; + int write_flag; +#ifdef MODE32 + uint32_t pagesize = DYNTRANS_PAGESIZE; +#else + uint64_t pagesize = DYNTRANS_PAGESIZE; +#endif + if (cpu->cd.mips.cpu_type.rev == MIPS_GODSON2) { + switch ((cpu->cd.mips.coproc[0]->reg[COP0_PAGEMASK] & PAGEMASK_MASK) >> PAGEMASK_SHIFT) { + case 0: + pagesize = 1 << 12; + break; + case 3: + pagesize = 1 << 14; + break; + case 0xf: + pagesize = 1 << 16; + break; + case 0x3f: + pagesize = 1 << 18; + break; + default: + pagesize = DYNTRANS_PAGESIZE; + break; + } + } + old_page = host_page; + if ((uint32_t)old_page & (DYNTRANS_PAGESIZE - 1) || writeflag & MEM_DYNTRANS) { + dyntrans = 1; /* dynastic device access such as vga */ + debug("vaddr_page %llx paddr_page=%llx host_page %p\n", vaddr_page, paddr_page, host_page); + } else + dyntrans = 0; + write_flag = writeflag | MEM_WRITE; + vaddr_page &= ~(pagesize - 1); + paddr_page &= ~(pagesize - 1); + if (dyntrans) { + host_page = (unsigned char *)(old_page - (vaddr_page & (pagesize - 1))); + } + else + host_page = memory_paddr_to_hostaddr(cpu->mem, paddr_page, write_flag); + i = 0; + + if (dyntrans) + i = pagesize / DYNTRANS_PAGESIZE - 1; + for (; i*DYNTRANS_PAGESIZE < pagesize; i++) { + if (host_page == NULL) { + fatal("[%d] READ ONLY!!, old host page %p\n", i, old_page); + } +#endif assert((vaddr_page & (DYNTRANS_PAGESIZE-1)) == 0); assert((paddr_page & (DYNTRANS_PAGESIZE-1)) == 0); @@ -1590,7 +1726,12 @@ l3->host_store[x3] = NULL; } else { /* Change the entire physical/host mapping: */ -printf("HOST LOAD 2 set to %p\n", host_page); +/*printf("HOST LOAD 2 set to %p\n", host_page);*/ + /* printf("plj debug: |vaddr_page\t|host_load\t|host_store\t|phys_addr\t\n" + " ---old:|%llx\t|%p\t|%p\t|%llx\n" + " ==>new:|\t\t|%p\t|%p\t|%llx\n", + vaddr_page, l3->host_load[x3], l3->host_store[x3], l3->phys_addr[x3], + host_page, writeflag?host_page:NULL, paddr_page);*/ l3->host_load[x3] = host_page; l3->host_store[x3] = writeflag? host_page : NULL; l3->phys_addr[x3] = paddr_page; @@ -1624,6 +1765,15 @@ #endif /* !MODE32 */ } +#ifdef DYNTRANS_MIPS + vaddr_page += DYNTRANS_PAGESIZE; + paddr_page += DYNTRANS_PAGESIZE; + if (dyntrans) + host_page += DYNTRANS_PAGESIZE; + else + host_page = memory_paddr_to_hostaddr(cpu->mem, paddr_page, write_flag); + } /* End for*/ +#endif } #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */ diff -urN gxemul-0.4.3/src/cpus/cpu_mips.c gxemul-0.4.3.godson/src/cpus/cpu_mips.c --- gxemul-0.4.3/src/cpus/cpu_mips.c 2006-10-08 10:29:20.000000000 +0800 +++ gxemul-0.4.3.godson/src/cpus/cpu_mips.c 2006-11-09 21:16:14.000000000 +0800 @@ -2028,10 +2028,21 @@ reg[COP0_CONTEXT] &= ~CONTEXT_BADVPN2_MASK; reg[COP0_CONTEXT] |= ((vaddr_vpn2 << CONTEXT_BADVPN2_SHIFT) & CONTEXT_BADVPN2_MASK); - reg[COP0_XCONTEXT] &= ~XCONTEXT_R_MASK; - reg[COP0_XCONTEXT] &= ~XCONTEXT_BADVPN2_MASK; - reg[COP0_XCONTEXT] |= (vaddr_vpn2 << XCONTEXT_BADVPN2_SHIFT) & XCONTEXT_BADVPN2_MASK; - reg[COP0_XCONTEXT] |= ((vaddr >> 62) & 0x3) << XCONTEXT_R_SHIFT; + /* The follow code seems not be correct to the manual of R10K, so I modified it. plj*/ + /* printf("{plj debug: exception code %x asid %x vaddr %llx => vaddr_vpn2 %llx}\n", + exccode, vaddr_asid, vaddr, vaddr_vpn2);*/ + if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) { + reg[COP0_XCONTEXT] &= ~(XCONTEXT_R_MASK << 4); + reg[COP0_XCONTEXT] &= ~((XCONTEXT_BADVPN2_MASK << 4) | 0xf0) ; + reg[COP0_XCONTEXT] |= (vaddr_vpn2 << XCONTEXT_BADVPN2_SHIFT) & + ((XCONTEXT_BADVPN2_MASK << 4) + 0xf0); + reg[COP0_XCONTEXT] |= ((vaddr >> 62) & 0x3) << (XCONTEXT_R_SHIFT + 4); + } else { + reg[COP0_XCONTEXT] &= ~XCONTEXT_R_MASK; + reg[COP0_XCONTEXT] &= ~XCONTEXT_BADVPN2_MASK; + reg[COP0_XCONTEXT] |= (vaddr_vpn2 << XCONTEXT_BADVPN2_SHIFT) & XCONTEXT_BADVPN2_MASK; + reg[COP0_XCONTEXT] |= ((vaddr >> 62) & 0x3) << XCONTEXT_R_SHIFT; + } /* reg[COP0_PAGEMASK] = cpu->cd.mips.coproc[0]->tlbs[0].mask & PAGEMASK_MASK; */ diff -urN gxemul-0.4.3/src/cpus/cpu_mips_coproc.c gxemul-0.4.3.godson/src/cpus/cpu_mips_coproc.c --- gxemul-0.4.3/src/cpus/cpu_mips_coproc.c 2006-10-17 15:57:31.000000000 +0800 +++ gxemul-0.4.3.godson/src/cpus/cpu_mips_coproc.c 2006-11-09 22:39:57.000000000 +0800 @@ -540,6 +540,26 @@ struct mips_coproc *cp = cpu->cd.mips.coproc[0]; int i, ntlbs = cp->nr_of_tlbs; struct mips_tlb *tlb = cp->tlbs; + /* plj */ + uint64_t pagesize = 1 << 12; + + if (cpu->cd.mips.cpu_type.rev == MIPS_GODSON2) + switch ((cpu->cd.mips.coproc[0]->reg[COP0_PAGEMASK] & PAGEMASK_MASK)>> PAGEMASK_SHIFT) { + case 0: + pagesize = 1 << 12; + break; + case 3: + pagesize = 1 << 14; + break; + case 0xf: + pagesize = 1 << 16; + break; + case 0x3f: + pagesize = 1 << 18; + break; + default: + break; + } if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { for (i=0; icd.mips.coproc[0]; int index, g_bit; uint64_t oldvaddr; + uint64_t pagesize = 0x1000; /* default 4K. plj*/ if (randomflag) { if (cpu->cd.mips.cpu_type.exc_model == EXC3K) { @@ -1705,11 +1727,38 @@ /* * TODO: non-4KB page sizes! */ + /* non-4KB godson2. plj*/ + switch ((cpu->cd.mips.coproc[0]->reg[COP0_PAGEMASK] & PAGEMASK_MASK)>> PAGEMASK_SHIFT) { + case 0: + pagesize = 1 << 12; + break; + case 3: + pagesize = 1 << 14; + break; + case 0xf: + pagesize = 1 << 16; + break; + case 0x3f: + pagesize = 1 << 18; + break; + default: + pagesize = 1 << 12; + break; + } + oldvaddr &= ~(pagesize*2 - 1); + + /* if (cp->tlbs[index].lo0 & ENTRYLO_V) cpu->invalidate_translation_caches(cpu, oldvaddr, INVALIDATE_VADDR); if (cp->tlbs[index].lo1 & ENTRYLO_V) cpu->invalidate_translation_caches(cpu, oldvaddr|0x1000, + INVALIDATE_VADDR); */ + if (cp->tlbs[index].lo0 & ENTRYLO_V) + cpu->invalidate_translation_caches(cpu, oldvaddr, + INVALIDATE_VADDR); + if (cp->tlbs[index].lo1 & ENTRYLO_V) + cpu->invalidate_translation_caches(cpu, oldvaddr | pagesize, INVALIDATE_VADDR); } @@ -1861,7 +1910,9 @@ vaddr0 |= 0x3fffff0000000000ULL; } - vaddr1 = vaddr0 | (1 << vpn_shift); + /* vaddr1 = vaddr0 | (1 << vpn_shift); plj */ + vaddr0 &= ~(pagesize*2 - 1); + vaddr1 = vaddr0 | pagesize; g_bit = (cp->reg[COP0_ENTRYLO0] & cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G; @@ -1883,14 +1934,21 @@ * Invalidate any code translations, if we are writing Dirty * pages to the TLB: (TODO: 4KB hardcoded... ugly) */ - for (ptmp = 0; ptmp < (1 << pfn_shift); ptmp += 0x1000) { + /* plj fix it */ + /* for (ptmp = 0; ptmp < (1 << pfn_shift); ptmp += 0x1000) { if (wf0) cpu->invalidate_code_translation(cpu, paddr0 + ptmp, INVALIDATE_PADDR); if (wf1) cpu->invalidate_code_translation(cpu, paddr1 + ptmp, INVALIDATE_PADDR); - } + } */ + if (wf0) + cpu->invalidate_code_translation(cpu, + paddr0, INVALIDATE_PADDR); + if (wf1) + cpu->invalidate_code_translation(cpu, + paddr1, INVALIDATE_PADDR); /* * If we have a memblock (host page) for the physical page, @@ -1902,6 +1960,9 @@ * be too expensive to add e.g. 16MB pages like * this. */ + /* plj fixed non-4kb godson2 */ + paddr0 &= ~((1 << vpn_shift) - 1); + paddr1 &= ~((1 << vpn_shift) - 1); memblock = memory_paddr_to_hostaddr(cpu->mem, paddr0, 0); if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & ENTRYLO_V) cpu->update_translation_table(cpu, vaddr0, memblock, diff -urN gxemul-0.4.3/src/cpus/cpu_mips_instr.c gxemul-0.4.3.godson/src/cpus/cpu_mips_instr.c --- gxemul-0.4.3/src/cpus/cpu_mips_instr.c 2006-10-29 13:10:27.000000000 +0800 +++ gxemul-0.4.3.godson/src/cpus/cpu_mips_instr.c 2006-11-10 00:26:05.000000000 +0800 @@ -3924,8 +3924,11 @@ /* fatal("TRANSLATION MISS!\n"); */ if (!cpu->memory_rw(cpu, cpu->mem, addr, ib, sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) { + /* do normal exception routing. plj */ + return ; + /* plj fatal("to_be_translated(): read failed: TODO\n"); - goto bad; + goto bad;*/ } } diff -urN gxemul-0.4.3/src/cpus/memory_mips_v2p.c gxemul-0.4.3.godson/src/cpus/memory_mips_v2p.c --- gxemul-0.4.3/src/cpus/memory_mips_v2p.c 2006-10-17 15:57:31.000000000 +0800 +++ gxemul-0.4.3.godson/src/cpus/memory_mips_v2p.c 2006-11-09 21:12:06.000000000 +0800 @@ -64,6 +64,7 @@ int no_exceptions = flags & FLAG_NOEXCEPTIONS; int ksu, use_tlb, status, i; uint64_t vaddr_vpn2=0, vaddr_asid=0; + uint64_t real_vaddr_vpn2=0; int exccode, tlb_refill; struct mips_coproc *cp0; @@ -276,6 +277,7 @@ cached_lo0 = cp0->tlbs[i].lo0; cached_lo1 = cp0->tlbs[i].lo1; + real_vaddr_vpn2 = (vaddr & vpn2_mask) >> pagemask_shift;/* plj */ /* Optimized for minimum page size: */ if (pmask == 0) { pageshift = pagemask_shift - 1; @@ -379,10 +381,22 @@ R2K3K_ENTRYLO_PFN_MASK; paddr = pfn | (vaddr & pmask); #else +/* R10000. plj */ +#ifdef V2P_MMU10K + pfn = ((odd? cached_lo1 : + cached_lo0) + & ENTRYLO_PFN_MASK_R10K) + >> ENTRYLO_PFN_SHIFT; +#else pfn = ((odd? cached_lo1 : cached_lo0) & ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT; +#endif + + /* plj + paddr = (pfn << pfn_shift) | + (vaddr & pmask);*/ paddr = (pfn << pfn_shift) | (vaddr & pmask); #endif @@ -442,8 +456,13 @@ vaddr_vpn2 >>= 12; #endif +#if 0 /* plj */ mips_cpu_exception(cpu, exccode, tlb_refill, vaddr, 0, vaddr_vpn2, vaddr_asid, x_64); +#else + mips_cpu_exception(cpu, exccode, tlb_refill, vaddr, + 0, real_vaddr_vpn2, vaddr_asid, x_64); +#endif /* Return failure: */ return 0; diff -urN gxemul-0.4.3/src/devices/bus_pci_ati.c gxemul-0.4.3.godson/src/devices/bus_pci_ati.c --- gxemul-0.4.3/src/devices/bus_pci_ati.c 1970-01-01 08:00:00.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/bus_pci_ati.c 2006-11-09 21:53:47.000000000 +0800 @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2004-2006 Anders Gavare. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * $Id: bus_pci_ati.c,v 1.6 2006/06/22 08:21:01 cpu Exp $ + * + * Generic PCI bus framework. This is not a normal "device", but is used by + * individual PCI controllers and devices. + * + * + * TODO: + * + */ + + +#include +#include +#include + +#define BUS_PCI_C + +#include "bus_pci.h" +#include "cpu.h" +#include "device.h" +#include "devices.h" +#include "diskimage.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" + + + +/* + * ATI graphics cards + */ + + +#define PCI_VENDOR_ATI 0x1002 +#if 0 +#define PCI_PRODUCT_ATI_RADEON_9200_2 0x5962 + +PCIINIT(ati_radeon_9200_2) +{ + uint64_t port, memaddr; + + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ATI, + PCI_PRODUCT_ATI_RADEON_9200_2)); + + /* TODO: other subclass? */ + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_DISPLAY, + PCI_SUBCLASS_DISPLAY_VGA, 0) + 0x03); + + /* TODO */ + allocate_device_space(pd, 0x1000, 0x400000, &port, &memaddr); +} +#endif + +PCIINIT(ati_radeon_7000m) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ATI, 0x7971)); + + PCI_SET_DATA(PCI_CLASS_REG, + PCI_CLASS_CODE(PCI_CLASS_DISPLAY, + PCI_SUBCLASS_DISPLAY_VGA, 0) + 0x01); + + PCI_SET_DATA(0x10, 0x0); + PCI_SET_DATA_SIZE(0x10, 0xfe000000); + PCI_SET_DATA_SIZE(0x14, 0xffffff01); + PCI_SET_DATA_SIZE(0x18, 0xffff0000); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffffff); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_DISPLAY, + PCI_SUBCLASS_DISPLAY_VGA, 0) + 0x03); + PCI_SET_DATA(PCI_MAPREG_ROM, 0x0); + PCI_SET_DATA_SIZE(PCI_MAPREG_ROM, 0xfffe0000); + + { + dev_vga_init(machine, mem, pd->pcibus->isa_membase + 0xa0000, + pd->pcibus->pci_portbase + 0x3c0, machine->machine_name); +#if 0 + dev_id *dev_id, *p; + dev_id = dev_vga_init(machine, mem, pd->pcibus->isa_membase + 0xa0000, + pd->pcibus->pci_portbase + 0x3c0, machine->machine_name); + for (p = dev_id; p->id != -1; p++) + { + if (p->tag == VIDEOMEM) + { + p->idx = 0x30; + } + else if (p->tag == VGACTRL) + { + p->idx = 0x10; + } + } + pd->dev_id = dev_id; +#endif + } +} diff -urN gxemul-0.4.3/src/devices/bus_pci.c gxemul-0.4.3.godson/src/devices/bus_pci.c --- gxemul-0.4.3/src/devices/bus_pci.c 2006-10-08 10:29:20.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/bus_pci.c 2006-11-10 17:09:41.000000000 +0800 @@ -143,7 +143,9 @@ if (writeflag == MEM_WRITE) { debug("[ bus_pci: write to PCI DATA: data = 0x%08llx ]\n", (long long)idata); - if (idata == 0xffffffffULL && + /* the least bit has nothing with any write. plj + if (idata == 0xffffffffULL &&*/ + if ((idata | 0x1) == 0xffffffffULL && pci_data->cur_reg >= PCI_MAPREG_START && pci_data->cur_reg <= PCI_MAPREG_END - 4) { pci_data->last_was_write_ffffffff = 1; @@ -265,8 +267,12 @@ */ PCI_SET_DATA(PCI_COMMAND_STATUS_REG, PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE); +#if 0 for (ofs = PCI_MAPREG_START; ofs < PCI_MAPREG_END; ofs += 4) PCI_SET_DATA_SIZE(ofs, 0x00100000 - 1); +#endif /* plj */ + for (ofs = PCI_MAPREG_START; ofs < PCI_MAPREG_END; ofs += 4) + PCI_SET_DATA_SIZE(ofs, 0xffffffff); if (init == NULL) { fatal("No init function for PCI device \"%s\"?\n", name); diff -urN gxemul-0.4.3/src/devices/bus_pci_ite.c gxemul-0.4.3.godson/src/devices/bus_pci_ite.c --- gxemul-0.4.3/src/devices/bus_pci_ite.c 1970-01-01 08:00:00.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/bus_pci_ite.c 2006-11-09 21:53:47.000000000 +0800 @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2004-2006 Anders Gavare. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * $Id: bus_pci_ite.c,v 1.6 2006/06/22 08:21:01 cpu Exp $ + * + * Generic PCI bus framework. This is not a normal "device", but is used by + * individual PCI controllers and devices. + * + * + * TODO: + * + */ + +#include +#include +#include + +#define BUS_PCI_C + +#include "bus_pci.h" +#include "cpu.h" +#include "device.h" +#include "devices.h" +#include "diskimage.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" +#include "it8172_int.h" + + +/* + * ITE Technology 8172G PCI controller. + * + * IT8172G Used in Godson-NC machines + * + * NOTE: This works in the opposite way compared to other devices; the PCI + * device is added from the normal device instead of the other way around. + */ + +#define PCI_VENDOR_ITE 0x1283 /* ITE Technology */ +#define PCI_PRODUCT_ITE_8172 0x8172 /* EV8172 System Controller */ +#define PCI_PRODUCT_ITE_AUDIO 0x0801 +PCIINIT(it_cpu_to_pci_bridge) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ITE, + PCI_PRODUCT_ITE_8172)); + + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02000006); + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, + PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x20); /* Revision 2.0 */ + PCI_SET_DATA(0x40, 0x00000002); /* PCI Memory Control */ + + PCI_SET_DATA_SIZE(0x10, 0xffffffff); + PCI_SET_DATA_SIZE(0x14, 0xffffffff); + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffffff); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} +PCIINIT(it_audio_controller) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ITE, + PCI_PRODUCT_ITE_AUDIO)); + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, PCI_STATUS_DEVSEL_MEDIUM | + PCI_STATUS_BACKTOBACK_SUPPORT | PCI_STATUS_CAPLIST_SUPPORT); + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MULTIMEDIA, + PCI_SUBCLASS_MULTIMEDIA_AUDIO, 0) + 0xb1); /* Revision b1h */ + PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0x00,0x00,1,0x00,0x00)); + PCI_SET_DATA(PCI_MAPREG_START, 0x14017001); + PCI_SET_DATA_SIZE(PCI_MAPREG_START, 0xfffff801); /* PMC/NIP/CID*/ + PCI_SET_DATA(PCI_SUBSYS_ID_REG, 0x12831283); + PCI_SET_DATA(PCI_CAPLISTPTR_REG, 0xdc); + PCI_SET_DATA(PCI_INTERRUPT_REG, PCI_INTERRUPT_CODE(0x28,0x04,PCI_INTERRUPT_PIN_A,0x00)); + PCI_SET_DATA(0x40, 0x00000003); /* LAC */ + PCI_SET_DATA(0x98, 0x08011283); /* Device/Vendor ID */ + PCI_SET_DATA(0x9c, 0x12831283); /* Sub-system Vendor ID */ + PCI_SET_DATA(0xdc, 0x04210001); /* PMC/NIP/CID*/ + + PCI_SET_DATA_SIZE(0x14, 0xffffffff); + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffffff); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} +PCIINIT(it_dma_controller) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ITE, + PCI_PRODUCT_ITE_8172)); + + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, PCI_STATUS_DEVSEL_MEDIUM | + PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE); + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_SYSTEM, + PCI_SUBCLASS_SYSTEM_DMA, 0x00) + 0x10); /* Revision 10h */ + PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0x00,0x00,0,0x00,0x00)); + PCI_SET_DATA(PCI_MAPREG_START, 0x14016001); + PCI_SET_DATA_SIZE(PCI_MAPREG_START, 0xfffff801); + PCI_SET_DATA_SIZE(0x14, 0xffffffff); + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffffff); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} +PCIINIT(it_chain_dma_controller) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ITE, + PCI_PRODUCT_ITE_8172)); + + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, PCI_STATUS_DEVSEL_MEDIUM | + PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE); + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_SYSTEM, + PCI_SUBCLASS_SYSTEM_DMA, 0x03) + 0x10); /* Revision 10h */ + PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0x00,0x00,0,0x80,0x00)); + PCI_SET_DATA(PCI_MAPREG_START, 0x14016801); + PCI_SET_DATA_SIZE(PCI_MAPREG_START, 0xfffff801); + PCI_SET_DATA_SIZE(0x14, 0xffffffff); + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffffff); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} +PCIINIT(it_usb_host) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(0x0006,0x0000)); + + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x0); + PCI_SET_DATA(PCI_CLASS_REG, 0); + PCI_SET_DATA(0x34, 0x2edf); + PCI_SET_DATA(0x44, 0x0628); + PCI_SET_DATA(0x48, 0x0002); + PCI_SET_DATA(0x10, 0xffffffff); + PCI_SET_DATA(0x14, 0xffffffff); + PCI_SET_DATA(0x18, 0xffffffff); + PCI_SET_DATA(0x1c, 0xffffffff); + PCI_SET_DATA(0x20, 0xffffffff); + PCI_SET_DATA(0x24, 0xffffffff); +} +PCIINIT(it_pci_to_internal_bridge) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ITE, + PCI_PRODUCT_ITE_8172)); + + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, PCI_STATUS_DEVSEL_MEDIUM | PCI_COMMAND_IO_ENABLE); + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, + PCI_SUBCLASS_BRIDGE_MISC, 0) + 0x11); /* Revision 11h */ + PCI_SET_DATA(0x4c, 0x3f220000); + PCI_SET_DATA(0x50, 0x14010000); /* INTC I/O space control */ + PCI_SET_DATA(0x54, 0x14010800); /* Timer I/O space control */ + PCI_SET_DATA(0x58, 0x14011000); /* CIR0 I/O space control */ + PCI_SET_DATA(0x5c, 0x14011800); /* UART I/O space control */ + PCI_SET_DATA(0x60, 0x14012000); /* SCR0 I/O space control */ + PCI_SET_DATA(0x64, 0x14012800); /* SCR1 I/O space control */ + PCI_SET_DATA(0x68, 0x14013000); /* PP I/O space control */ + PCI_SET_DATA(0x6c, 0x14013800); /* GPIO I/O space control */ + PCI_SET_DATA(0x70, 0x14014000); /* I2C I/O space control */ + PCI_SET_DATA(0x74, 0x14014800); /* RTC I/O space control */ + PCI_SET_DATA(0x78, 0x14015000); /* CIR1 I/O space control */ + PCI_SET_DATA(0x7c, 0x14015800); /* PMU I/O space control */ + PCI_SET_DATA_SIZE(PCI_MAPREG_START, 0xfffff801); + PCI_SET_DATA_SIZE(0x14, 0xffffffff); + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffffff); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} +PCIINIT(it_ide_controller) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ITE, + PCI_PRODUCT_ITE_8172)); + + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, PCI_STATUS_DEVSEL_MEDIUM | + PCI_STATUS_BACKTOBACK_SUPPORT | PCI_COMMAND_MASTER_ENABLE| PCI_COMMAND_IO_ENABLE); + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, + PCI_SUBCLASS_MASS_STORAGE_IDE, 0x85/*0x8a*/) + 0x01); /* Revision 1 */ + PCI_SET_DATA(PCI_MAPREG_START, 0x140179f1); + PCI_SET_DATA(PCI_MAPREG_START + 4, 0x14017bf5); + PCI_SET_DATA(PCI_MAPREG_START + 0x10, 0x14017801); + PCI_SET_DATA(0x40, 0xc000); + PCI_SET_DATA(0x44, 0xffffff00); + PCI_SET_DATA_SIZE(PCI_MAPREG_START, 0xffffffe1); /* 0 */ + PCI_SET_DATA_SIZE(PCI_MAPREG_START + 4, 0xffffffc1); /* 0x4 */ + /* 8 & 12 reserved */ + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(PCI_MAPREG_START + 0x10, 0xfffffe01); /* 0x8 */ + PCI_SET_DATA_SIZE(0x24, 0xffffffff); + + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || + diskimage_exist(machine, 1, DISKIMAGE_IDE)) { + char tmpstr[150]; + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", + (long long)(pd->pcibus->pci_portbase + 0x1800 + 0x1f0), + pd->pcibus->pci_irqbase + IT8172_IDE_IRQ); + device_add(machine, tmpstr); + } +} +PCIINIT(it_68k_controller) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ITE, + PCI_PRODUCT_ITE_8172)); + + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, PCI_STATUS_DEVSEL_MEDIUM | PCI_COMMAND_IO_ENABLE); + PCI_SET_DATA(0x50, 0xf1); /* BUSAR */ + PCI_SET_DATA(0x54, 0x20); /* MBSCR */ + PCI_SET_DATA(0x5c, 0x003f0000); /* BCR/BSR/DTR */ + PCI_SET_DATA(0x60, 0x00fffffa); /* CS0BAR */ + PCI_SET_DATA(0x64, 0x0000003A); /* CS0OR */ + PCI_SET_DATA(0x68, 0x00fffffa); /* CS1BAR */ + PCI_SET_DATA(0x6c, 0x0000003A); /* CS1OR */ + PCI_SET_DATA(0x70, 0x00fffffa); /* CS2BAR */ + PCI_SET_DATA(0x74, 0x0000003A); /* CS2OR */ + PCI_SET_DATA(0x78, 0x00fffffa); /* CS3BAR */ + PCI_SET_DATA(0x7c, 0x0000003A); /* CS3OR */ + PCI_SET_DATA(0x80, 0x00fffffa); /* CS4BAR */ + PCI_SET_DATA(0x84, 0x0000003A); /* CS4OR */ + PCI_SET_DATA(0x88, 0x00fffffa); /* CS5BAR */ + PCI_SET_DATA(0x8c, 0x0000003A); /* CS5OR */ + PCI_SET_DATA(0x90, 0x00fffffa); /* CS6BAR */ + PCI_SET_DATA(0x94, 0x0000003A); /* CS6OR */ + PCI_SET_DATA(0x98, 0x00fffffa); /* CS7BAR */ + PCI_SET_DATA(0x9c, 0x0000003A); /* CS7OR */ + PCI_SET_DATA(0xa0, 0x00fffffa); /* CS8BAR */ + PCI_SET_DATA(0xa4, 0x0000003A); /* CS8OR */ + PCI_SET_DATA(0xa8, 0x00fffffa); /* CS9BAR */ + PCI_SET_DATA(0xac, 0x0000003A); /* CS9OR */ + PCI_SET_DATA(0xb0, 0x00fffffa); /* CS10BAR */ + PCI_SET_DATA(0xb4, 0x0000003A); /* CS10OR */ + PCI_SET_DATA(0xb8, 0x00fffffa); /* CS11BAR */ + PCI_SET_DATA(0xbc, 0x0000003A); /* CS11OR */ + PCI_SET_DATA_SIZE(0x10, 0xffffffff); + PCI_SET_DATA_SIZE(0x14, 0xffffffff); + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffffff); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} + diff -urN gxemul-0.4.3/src/devices/bus_pci_rtl.c gxemul-0.4.3.godson/src/devices/bus_pci_rtl.c --- gxemul-0.4.3/src/devices/bus_pci_rtl.c 1970-01-01 08:00:00.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/bus_pci_rtl.c 2006-11-10 17:12:28.000000000 +0800 @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2004-2006 Anders Gavare. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * $Id: bus_pci_rtl.c,v 1.6 2006/06/22 08:21:01 cpu Exp $ + * + * Generic PCI bus framework. This is not a normal "device", but is used by + * individual PCI controllers and devices. + * + * + * TODO: + * + */ + + +#include +#include +#include + +#define BUS_PCI_C + +#include "bus_pci.h" +#include "cpu.h" +#include "device.h" +#include "devices.h" +#include "diskimage.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" + +#define PCI_VENDOR_RTL 0x10ec + +extern DEVICE_ACCESS(rtl8139); + + +struct rtl8139_cfg_extra{ + struct machine *machine; + int dev_probed; + void *dev_extra; +}; + +int rtl8139_cfg_reg_write(struct pci_device *pd, int reg, uint32_t value) +{ + uint32_t reg_value; + int idex = -1; + struct rtl8139_cfg_extra *d; + struct machine *m; + struct memory *mem; + int size_mask; + int is_io = 0; + uint64_t portbase = 0, membase = 0 , base; + void *rtl8139_extra = NULL; + struct memory_device dev; + + d = (struct rtl8139_cfg_extra *)pd->extra; + m = d->machine; + mem = m->memory; + + portbase = pd->pcibus->pci_portbase; + membase = pd->pcibus->pci_membase; + + switch (reg) { + case PCI_MAPREG_START: + case PCI_MAPREG_START + 4: + if (pd->cfg_mem_size[reg] & 1) + is_io = 1; + if (value == 0 || value == 1) { + fatal("Warning, BAR of pci rtl8139 is writen with wrong value , ignored!!!\n"); + break; + } + base = is_io?portbase:membase; + reg_value = pd->cfg_mem[reg] | + pd->cfg_mem[reg+1] << 8 | + pd->cfg_mem[reg+2] << 16 | + pd->cfg_mem[reg+3] << 24; + reg_value &= 0xffffffff; + + size_mask = pd->cfg_mem_size[reg] | + pd->cfg_mem_size[reg+1] << 8 | + pd->cfg_mem_size[reg+2] << 16 | + pd->cfg_mem_size[reg+3] << 24; + size_mask &= 0xffffffff; + if (reg_value & ~((~size_mask) | 0xf)) { + idex = memory_device_query(mem, (uint64_t)reg_value + base, &dev); + } + if (idex != -1) { + debug("Modify the old device index %d reg %x write %x\n", + idex, reg, value); + dev.baseaddr = base + (value & size_mask & ~0xf); + dev.endaddr = dev.baseaddr + dev.length; + memory_device_modify(mem, &dev, idex); + } + else { + char tmpstr[200]; + debug("reg %x write %x\n", reg, value); + PCI_SET_DATA(reg, value | (is_io?1:0)); + + if (!d->dev_probed) { + debug("Add new device\n"); + snprintf(tmpstr, sizeof(tmpstr), "rtl8139 irq=%d addr=0x%llx", + pd->pcibus->pci_irqbase + 10, + base + (value & size_mask & ~0xf)); + d->dev_extra = device_add(m, tmpstr); + d->dev_probed = 1; + } else { + debug("Add new address space access\n"); + snprintf(tmpstr, sizeof(tmpstr), "rtl8139(%s)", is_io?"io":"mem"); + memory_device_register(mem, tmpstr, + base+(value & size_mask & ~0xf), + ~(size_mask & ~0xf) + 1, + dev_rtl8139_access, d->dev_extra, + DM_DEFAULT, NULL); + } + } + break; + default: + break; + } + return 0; +} + + +PCIINIT(rtl8139) +{ + + struct rtl8139_cfg_extra * extra = malloc(sizeof(struct rtl8139_cfg_extra *)); + if (extra == NULL) + fatal("[ %s(): not enough memory ]\n", __FUNCTION__); + + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_RTL, 0x8139)); + + PCI_SET_DATA(PCI_CLASS_REG, + PCI_CLASS_CODE(PCI_CLASS_NETWORK, + PCI_SUBCLASS_NETWORK_ETHERNET, 0)); + + PCI_SET_DATA(0x10, 0x1); /* IOBAR */ + PCI_SET_DATA_SIZE(0x10, 0xffffff01); + PCI_SET_DATA(0x14, 0x0); /* MEMBAR */ + PCI_SET_DATA_SIZE(0x14, 0xffffff00); + PCI_SET_DATA_SIZE(PCI_MAPREG_ROM, 0xffffff00); + PCI_SET_DATA(0x34, 0x50); /* Cap_Ptr */ + PCI_SET_DATA(0x3c, 0x20200100); /* MXLAT MNGNT IPR ILR */ + PCI_SET_DATA(0x50, 0x01); /* PMC Next_Ptr PMID */ + /* Power manager donnot be supportted here */ + PCI_SET_DATA(0x60, 0x03); /* Flag VPD Address, NextPtr, VPDID */ + + extra->machine = machine; + extra->dev_probed = 0; + extra->dev_extra = NULL; + + pd->extra = extra; + pd->cfg_reg_write = rtl8139_cfg_reg_write; +} + + diff -urN gxemul-0.4.3/src/devices/bus_pci_via.c gxemul-0.4.3.godson/src/devices/bus_pci_via.c --- gxemul-0.4.3/src/devices/bus_pci_via.c 1970-01-01 08:00:00.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/bus_pci_via.c 2006-11-09 21:53:47.000000000 +0800 @@ -0,0 +1,200 @@ +#include +#include +#include + +#define BUS_PCI_C + +#include "bus_pci.h" +#include "cpu.h" +#include "device.h" +#include "devices.h" +#include "diskimage.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" + + +/* + * VIA technology + * Author: Pengliangjin. ICT. 2006.06.19 + * VT82C868B SouthBridge Used in Godson machines + */ + +PCIINIT(via_pci_to_isa_bridge) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(0x1106, 0x0686)); + + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02000087); + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, + PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x40); /* Revision 4.0 */ + PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0x00,0x00,1,0x00,0x00)); + PCI_SET_DATA(PCI_CAPLISTPTR_REG, 0x000000c0); + PCI_SET_DATA(0x48, 0x00040001); /* Miscellaneous Control, Port 70/74 Access Status, + IDE interrupt Routing */ + PCI_SET_DATA(0x4c, 0x03000000); /* DMA/Master Mem Access Control 1/2/3 */ + PCI_SET_DATA(0x50, 0x0000002d); /* PnP DMA Request Control, + PnP Routing for LPT/FDC IRQ + PnP Routing for COM2/COM1 IRQ */ + PCI_SET_DATA(0x58, 0x00040400); + PCI_SET_DATA(0x5c, 0x04000000); + PCI_SET_DATA(0x74, 0x10000000); /* GPIO Control 1/2/3/4 */ + PCI_SET_DATA(0x84, 0x00000010); + + PCI_SET_DATA_SIZE(0x10, 0xffffffff); + PCI_SET_DATA_SIZE(0x14, 0xffffffff); + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffffff); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} + + +PCIINIT(via_ide_controller) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(0x1106, 0x0571)); + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02800080); + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, + PCI_SUBCLASS_MASS_STORAGE_IDE, 0x8a) + 0x06); /* Revision 0.6 */ + PCI_SET_DATA(PCI_MAPREG_START, 0x000001f1); + PCI_SET_DATA(PCI_MAPREG_START + 4, 0x000003f7); + PCI_SET_DATA(PCI_MAPREG_START + 8, 0x00000171); + PCI_SET_DATA(PCI_MAPREG_START + 0xc, 0x00000377); + PCI_SET_DATA(PCI_MAPREG_START + 0x10, 0x0000cc01); + PCI_SET_DATA(PCI_CAPLISTPTR_REG, 0x000000c0); + PCI_SET_DATA(PCI_INTERRUPT_REG, 0x0000010e); + PCI_SET_DATA(0x40, 0x0a090208); + PCI_SET_DATA(0x44, 0x00c00068); + PCI_SET_DATA(0x48, 0xa8a8a8a8); + PCI_SET_DATA(0x4c, 0x000000ff); + PCI_SET_DATA(0x50, 0x07070707); + PCI_SET_DATA(0x54, 0x00000004); + PCI_SET_DATA(0x60, 0x00000200); + PCI_SET_DATA(0x68, 0x00000200); + PCI_SET_DATA(0xc0, 0x00020001); + + PCI_SET_DATA_SIZE(0x10, 0xffffff01); + PCI_SET_DATA_SIZE(0x14, 0xffffff01); + PCI_SET_DATA_SIZE(0x18, 0xffffff01); + PCI_SET_DATA_SIZE(0x1c, 0xffffff01); + PCI_SET_DATA_SIZE(0x20, 0xfffffffd); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); + +#if 0 + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || + diskimage_exist(machine, 1, DISKIMAGE_IDE)) { + char tmpstr[150]; + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", + (long long)(pd->pcibus->pci_portbase + 0x1f0), + pd->pcibus->isa_irqbase+14); + device_add(machine, tmpstr); + } + else { + char tmpstr[150]; + snprintf(tmpstr, sizeof(tmpstr), "nodev addr=0x%llx", + (long long)(pd->pcibus->pci_portbase + 0x1f0)); + device_add(machine, tmpstr); + } +#endif +} + +PCIINIT(via_usb0_controller) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(0x1106, 0x3038)); + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x0210001a); + PCI_SET_DATA(PCI_CLASS_REG, 0x0c030000); + PCI_SET_DATA(0xc, 0x00001600); + PCI_SET_DATA(0x20, 0x00000301); + PCI_SET_DATA(0x34, 0x00000080); + PCI_SET_DATA(0x3c, 0x00000004); + PCI_SET_DATA(0x40, 0x00001000); + PCI_SET_DATA(0x60, 0x00000010); + PCI_SET_DATA(0x80, 0x00020001); + PCI_SET_DATA(0xc0, 0x00002000); + + PCI_SET_DATA_SIZE(0x10, 0xffffffff); + PCI_SET_DATA_SIZE(0x14, 0xffffffff); + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffff01); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} + +PCIINIT(via_usb1_controller) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(0x1106, 0x3038)); + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x0210001a); + PCI_SET_DATA(PCI_CLASS_REG, 0x0c030000); + PCI_SET_DATA(0xc, 0x00001600); + PCI_SET_DATA(0x20, 0x00000301); + PCI_SET_DATA(0x34, 0x00000080); + PCI_SET_DATA(0x3c, 0x00000004); + PCI_SET_DATA(0x40, 0x00001000); + PCI_SET_DATA(0x60, 0x00000010); + PCI_SET_DATA(0x80, 0x00020001); + PCI_SET_DATA(0xc0, 0x00002000); + + PCI_SET_DATA_SIZE(0x10, 0xffffffff); + PCI_SET_DATA_SIZE(0x14, 0xffffffff); + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffff01); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} + +PCIINIT(via_power_management) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(0x1106, 0x3057)); + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02900040); + PCI_SET_DATA(0x34, 0x00000068); + PCI_SET_DATA(0x48, 0x00000001); + PCI_SET_DATA(0x68, 0x00020001); + PCI_SET_DATA(0x70, 0x00000001); + PCI_SET_DATA(0x90, 0x00000001); + + PCI_SET_DATA_SIZE(0x48, 0x100); + PCI_SET_DATA_SIZE(0x70, 0x100); + PCI_SET_DATA_SIZE(0x90, 0x100); + + PCI_SET_DATA_SIZE(0x10, 0xffffffff); + PCI_SET_DATA_SIZE(0x14, 0xffffffff); + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffffff); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} + +PCIINIT(via_ac97_codecs) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(0x1106, 0x3058)); + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02100050); + PCI_SET_DATA(0x08, 0x04010000); + PCI_SET_DATA(0x10, 0x00000001); + PCI_SET_DATA(0x14, 0x00000001); + PCI_SET_DATA(0x3c, 0x00000300); + PCI_SET_DATA(0x40, 0x1c000000); + + PCI_SET_DATA_SIZE(0x10, 0xffffff01); + PCI_SET_DATA_SIZE(0x14, 0xfffffffd); + PCI_SET_DATA_SIZE(0x18, 0xfffffffd); + PCI_SET_DATA_SIZE(0x1c, 0xffffff01); + PCI_SET_DATA_SIZE(0x20, 0xffffffff); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} + +PCIINIT(via_mc97_codecs) +{ + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(0x1106, 0x3068)); + PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02000030); + PCI_SET_DATA(0x08, 0x07800000); + PCI_SET_DATA(0x10, 0x00000001); + PCI_SET_DATA(0x14, 0x00000001); + PCI_SET_DATA(0x3c, 0x00000300); + PCI_SET_DATA(0x40, 0x1c000000); + + PCI_SET_DATA_SIZE(0x10, 0xffffff01); + PCI_SET_DATA_SIZE(0x14, 0xffffffff); + PCI_SET_DATA_SIZE(0x18, 0xffffffff); + PCI_SET_DATA_SIZE(0x1c, 0xffffffff); + PCI_SET_DATA_SIZE(0x20, 0xffffffff); + PCI_SET_DATA_SIZE(0x24, 0xffffffff); +} diff -urN gxemul-0.4.3/src/devices/dev_8253.c gxemul-0.4.3.godson/src/devices/dev_8253.c --- gxemul-0.4.3/src/devices/dev_8253.c 2006-08-22 23:18:39.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/dev_8253.c 2006-11-10 07:43:23.000000000 +0800 @@ -52,7 +52,7 @@ #include "i8253reg.h" -#define debug fatal +//#define debug fatal #define DEV_8253_LENGTH 4 #define TICK_SHIFT 14 @@ -153,7 +153,8 @@ d->timer0, d->hz[0]); break; case 1: fatal("TODO: DMA refresh?\n"); - exit(1); + break; + /* exit(1); */ case 2: fatal("TODO: 8253 tone generation?\n"); break; } diff -urN gxemul-0.4.3/src/devices/dev_bonito.c gxemul-0.4.3.godson/src/devices/dev_bonito.c --- gxemul-0.4.3/src/devices/dev_bonito.c 1970-01-01 08:00:00.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/dev_bonito.c 2006-11-09 21:52:45.000000000 +0800 @@ -0,0 +1,414 @@ + +/* + * Copyright (C) 2003-2006 Anders Gavare. All rights reserved. + * Athor: Pengliangjin. ict. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include "cpu.h" +#include "bus_pci.h" +#include "devices.h" +#include "device.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" + +#include "bonito.h" +#include "irq.h" + +#define TICK_SHIFT 14 + +struct bonito_data { + int irqnr; + int pciirq; + int cur_bus; + int cur_dev; + int cur_func; + + /* Based at 1fe00000, bonito pci configuration space */ + struct pcicnf { + uint32_t pcidid; /* 0 */ + uint32_t pcicmd; /* 4 */ + uint32_t pciclass; /* 8 */ + uint32_t pciltimer; /* c */ + uint32_t pcibase0; /* 10 */ + uint32_t pcibase1; /* 14 */ + uint32_t pcibase2; /* 18 */ + uint32_t resv[5]; /* 1c~2c */ + uint32_t pciexprbase; /* 30 */ + uint32_t resv1[2]; /* 34,38 */ + uint32_t pciint; /* 3c */ + }pcicnf; + /* Based at 1fe00100, bonito local register space */ + struct bonlocal { + uint32_t bonponcfg; /* 0 */ + uint32_t bongencfg; /* 4 */ + uint32_t iodevcfg; /* 8 */ + uint32_t sdcfg; /* c */ + uint32_t pcimap; /* 10 */ + uint32_t pcimembasecfg; /* 14 */ + uint32_t pcimap_cfg; /* 18 */ + uint32_t gpiodata; /* 1c */ + uint32_t gpioie; /* 20 */ + uint32_t intedge; /* 24 */ + uint32_t intsteer; /* 28 */ + uint32_t intpol; /* 2c */ + uint32_t intenset; /* 30 */ + uint32_t intenclr; /* 34 */ + uint32_t inten; /* 38 */ + uint32_t intisr; /* 3c */ + uint32_t pcimail0; /* 40 */ + uint32_t pcimail1; /* 44 */ + uint32_t pcimail2; /* 48 */ + uint32_t pcimail3; /* 4c */ + uint32_t pcicachectrl; /* 50 */ + uint32_t pcicachetag; /* 54 */ + uint32_t pcibadaddr; /* 5c */ + uint32_t timercfg; /* 60 */ + }bonlocal; + /* Based at 1fe00200, bonito IDE DMA */ + struct bonldma { + uint32_t ldmactrl; + uint32_t ldmastat; + uint32_t ldmaaddr; + uint32_t ldmago; + }bonldma; + /* Based at 1fe00300, bonito Copier */ + struct boncop { + uint32_t copctrl; + uint32_t copstat; + uint32_t coppaddr; + uint32_t copgo; + }boncop; + + struct pci_data *pci_data; +}; + + +/* + * Bonito (MIPS) Interrupt Controller. + * + * (Used by the GODSON1/GODSON2 machine.) + */ +void bonito_interrupt(struct machine *m, struct cpu *cpu, int irq_nr, int assrt) +{ + struct bonito_data *d = (struct bonito_data *)m->md_int.priv; + + if (m->isa_pic_data.pic1) { + if (irq_nr >= ISA_IRQ_BASE && irq_nr <= ISA_IRQ_END || irq_nr == REASSERT_IRQ) { + debug("[ bonito_interrupt: irq=%d, assrt=%d ]\n", irq_nr, assrt); + if (irq_nr == REASSERT_IRQ) + debug("[ bonito_interrupt: 8259 interrupt %s ]\n", assrt?"INT":"ACK"); + isa8_interrupt(m, cpu, irq_nr, assrt); + return ; + } + } + + if (irq_nr >= NB_IRQ_BASE && irq_nr <= NB_IRQ_BASE+31) + irq_nr -= NB_IRQ_BASE; + else + fatal("[ %s: Unknown irq %d ]\n", __FUNCTION__, irq_nr); + +// printf("[ 1 bonito_interrupt: irq=%d ]\n", irq_nr); + + /* interrupt from subdevices */ + if (assrt) { + if (d->bonlocal.inten & (1<bonlocal.intisr |= (1<irqnr); + } + } + else { + d->bonlocal.intisr &= ~(1<bonlocal.intisr == 0) && + (d->bonlocal.inten & (1<irqnr); + } + } +} + + + +/*******************************************/ +/* Bonito System config register */ +/* controller */ +/*******************************************/ +/* + * dev_bonito_tick(): + */ +void dev_bonito_tick(struct cpu *cpu, void *extra) +{ +#if 0 + struct it_data *it_data = extra; + + cpu_interrupt(cpu, it_data->irqnr); +#endif +} + +/* + * dev_bonconf_access() + * This is only useful to PCI/Bonito access, and is + * no useful for CPU accessing Bonito. So I reserved + * this access that may be utilized in the future. + */ +DEVICE_ACCESS(bonconf) +{ + uint64_t idata = 0, odata = 0; + int bus, dev, func, reg; + struct bonito_data *d = extra; + + if (writeflag == MEM_WRITE) { + int offset = relative_addr/sizeof(uint32_t); + idata = memory_readmax64(cpu, data, len); + switch (offset) { + case 4: + ((uint32_t *)(&d->pcicnf))[offset] &= ~(idata & 0xffffffff); + break; + default: + break; + } + } + else { + odata = ((uint32_t *)(&d->pcicnf))[relative_addr/sizeof(uint32_t)]; + memory_writemax64(cpu, data, len, odata); + } + return 1; +} + +/* + * dev_bonlocal_access() + * As discribed above, I only concern about the CPU/Local access. + */ +DEVICE_ACCESS(bonlocal) +{ + uint64_t idata = 0, odata = 0; + struct bonito_data *d = extra; + + if (writeflag == MEM_WRITE) { + idata = memory_readmax64(cpu, data, len); + debug("relative_addr=%8llx, idata=%8llx, len=%d\n", relative_addr, idata, len); + switch (relative_addr) { + case 0x38: + case 0x3c: + printf("[ bonlocal: Access to non-writeable register %08llx! ]\n", relative_addr); + break; + case 0x30: + d->bonlocal.intenset = (uint32_t)idata; + d->bonlocal.inten |= d->bonlocal.intenset; + debug("[ bonito interrupt enable register %x ]\n", d->bonlocal.inten); + break; + case 0x34: + d->bonlocal.intenclr = (uint32_t)idata; + d->bonlocal.inten &= ~(d->bonlocal.intenclr); + debug("[ bonito interrupt disable register %x ]\n", d->bonlocal.inten); + if (d->bonlocal.intisr == 0) { + cpu_interrupt_ack(cpu, d->irqnr); + } + break; + default: + ((uint32_t *)(&d->bonlocal))[relative_addr/sizeof(uint32_t)] = idata & 0xffffffff; + break; + } + } + else { + odata = ((uint32_t *)(&d->bonlocal))[relative_addr/sizeof(uint32_t)]; + switch (relative_addr) { + case 0x3c: +// d->bonlocal.intisr = 0; +// ((uint32_t *)(&d->bonlocal))[relative_addr/sizeof(uint32_t)] = 0; + break; + default: + break; + } + memory_writemax64(cpu, data, len, odata); + } + return 1; +} + +/* + * dev_bonldma_access() + */ +DEVICE_ACCESS(bonldma) +{ + uint64_t idata = 0, odata = 0; + struct bonito_data *d = extra; + + if (writeflag == MEM_WRITE) { + idata = memory_readmax64(cpu, data, len); + ((uint32_t *)(&d->bonldma))[relative_addr/sizeof(uint32_t)] = idata & 0xffffffff; + } + else { + odata = ((uint32_t *)(&d->bonldma))[relative_addr/sizeof(uint32_t)]; + memory_writemax64(cpu, data, len, odata); + } + return 1; +} + +/* + * dev_boncop_access() + */ +DEVICE_ACCESS(boncop) +{ + uint64_t idata = 0, odata = 0; + struct bonito_data *d = extra; + + if (writeflag == MEM_WRITE) { + idata = memory_readmax64(cpu, data, len); + ((uint32_t *)(&d->boncop))[relative_addr/sizeof(uint32_t)] = idata & 0xffffffff; + } + else { + odata = ((uint32_t *)(&d->boncop))[relative_addr/sizeof(uint32_t)]; + memory_writemax64(cpu, data, len, odata); + } + return 1; +} + + +/* + * dev_bonpci_access() + * PCI devices configration access to Bonito North bridge + */ +DEVICE_ACCESS(bonpci) +{ + uint64_t idata = 0, odata = 0; + int bus = 0, dev = -1, func = 0, reg = 0; + uint32_t tmp, tmp1 ,tmp2; + struct bonito_data *d = extra; + int found_idsel = 0; + + tmp = relative_addr & 0xfffc; + tmp1 = ((d->bonlocal.pcimap_cfg & 0xffff) << 16) | tmp; + if (d->bonlocal.pcimap_cfg & 0x10000) { + tmp2 = tmp1 >> 24; + bus = (tmp1 >> 16) & 0xff; + } + else { + tmp2 = tmp1 >> 11; + } + if (tmp2 == 0) { + return 1; + fatal("[ bonpci: PCI configration cannot access without chip selects! ]\n"); + } + tmp = tmp2; + while (tmp2) + { + if (tmp2 & 0x1) { + if (found_idsel) { + return 1; + fatal("[ bonpci: Multi access idsel %x! ]\n", tmp); + } + found_idsel = 1; + } + tmp2 >>= 1; + dev++; + } + + func = (tmp1 >> 8) & 0x7; + reg = (tmp1) & 0xfc; + + debug("bus=%d,dev=%d,fun=%d,reg=%x\n", bus, dev, func, reg); + d->cur_bus = bus; + d->cur_dev = dev; + d->cur_func = func; + + bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg); + if (writeflag == MEM_WRITE) { + idata = memory_readmax64(cpu, data, len); + bus_pci_data_access(cpu, d->pci_data, &idata, len, writeflag); // pci data + } + else { + bus_pci_data_access(cpu, d->pci_data, &odata, len, writeflag); // pci data + memory_writemax64(cpu, data, len, odata); + } + return 1; + +} + +/* + * dev_bonito_init(): + * + * Initialize a Bonito devices. Return a pointer to the pci_data used, so that + * the caller may add PCI devices. First, however, we add the bonito device + * itself. + */ +#if 0 +struct pci_data *dev_bonito_init(struct machine *machine) +#endif +NBINIT(bonito) +{ + struct bonito_data *d; + char tmpstr[1000]; + uint64_t pci_portbase = BONITO_PCIIO_BASE; + uint64_t pci_membase = BONITO_PCIHI_BASE; + int pci_irqbase = NB_IRQ_BASE; + uint64_t isa_portbase = BONITO_PCIIO_BASE, isa_membase = 0x10000000; + int isa_irqbase = ISA_IRQ_BASE; + uint64_t pci_io_offset = 0, pci_mem_offset = 0; + + d = malloc(sizeof(struct bonito_data)); + if (d == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + memset(d, 0, sizeof(struct bonito_data)); + + d->irqnr = irq_nr; + d->pciirq = 0; + + d->pci_data = bus_pci_init(machine, + d->pciirq, pci_io_offset, pci_mem_offset, + pci_portbase, pci_membase, pci_irqbase, + isa_portbase, isa_membase, isa_irqbase); + + machine->md_interrupt = bonito_interrupt; + machine->md_int.priv = d; + + machine_add_tickfunction(machine, dev_bonito_tick, d, TICK_SHIFT, 0.0); + + memory_device_register(machine->memory, "bonconf", BONITO_REG_BASE + BONITO_CONFIGBASE, + BONCONF_LENGTH, dev_bonconf_access, d, + DM_DEFAULT, NULL); + memory_device_register(machine->memory, "bonlocal", BONITO_REG_BASE + BONITO_BONITOBASE, + BONLOCAL_LENGTH, dev_bonlocal_access, d, + DM_DEFAULT, NULL); + memory_device_register(machine->memory, "bonldma", BONITO_REG_BASE + BONITO_LDMABASE, + BONLDMA_LENGTH, dev_bonldma_access, d, + DM_DEFAULT, NULL); + memory_device_register(machine->memory, "boncop", BONITO_REG_BASE + BONITO_COPBASE, + BONCOP_LENGTH, dev_boncop_access, d, + DM_DEFAULT, NULL); + memory_device_register(machine->memory, "bonpci", BONITO_PCICFG_BASE, + BONITO_PCICFG_SIZE, dev_bonpci_access, d, + DM_DEFAULT, NULL); + + return d->pci_data; +} + diff -urN gxemul-0.4.3/src/devices/dev_fcr_soc.c gxemul-0.4.3.godson/src/devices/dev_fcr_soc.c --- gxemul-0.4.3/src/devices/dev_fcr_soc.c 1970-01-01 08:00:00.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/dev_fcr_soc.c 2006-11-09 21:52:40.000000000 +0800 @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2003-2006 Anders Gavare. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include "cpu.h" +#include "bus_pci.h" +#include "devices.h" +#include "device.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" + +#include "godson1_soc.h" + +struct fcr_soc_data { + struct ahb_ctl_data { + int ahb_misc; /* 0x00 */ + int intedge; /* 0x04 */ + int intsteer; /* 0x08 */ + int intpol; /* 0x0c */ + int intset; /* 0x10 */ + int intclr; /* 0x14 */ + int inten; /* 0x18 */ + int intstatus; /* 0x1c */ + int gpio_oe19_0; /* 0x20 */ + int gpio_r19_0; /* 0x24 */ + int gpio_w19_0; /* 0x28 */ + }ahb_ctl; + + struct apb_ctl_data { + unsigned char gpio_oe47_20; /* 0x00 */ + unsigned char gpio_oe77_48; /* 0x08 */ + unsigned char gpio_r47_20; /* 0x10 */ + unsigned char gpio_r77_48; /* 0x18 */ + unsigned char gpio_w47_20; /* 0x20 */ + unsigned char gpio_w77_48; /* 0x28 */ + unsigned char reserved[2]; /* 0x30~0x38 */ + unsigned char apb_misc; /* 0x40 */ + }apb_ctl; + + int irqnr; +}; + +DEVICE_ACCESS(fcr_soc_ahb) +{ + struct fcr_soc_data *d = extra; + uint64_t idata, odata; + int off; + + if (relative_addr >= FCR_SOC_AHB_LENGTH) { + fatal("[ FCR SoC (%s): outside register space? relative_addr=" + "0x%llx. bad addrmult? bad device length? ]\n", __FUNCTION__, + (long long)relative_addr); + return 0; + } + + off = relative_addr/4; + if (writeflag == MEM_WRITE) { + idata = memory_readmax64(cpu, data, len); + + switch (relative_addr) { + case 0x00: + case 0x04: + case 0x08: + case 0x0c: + case 0x10: + case 0x14: + break; + case 0x18: + debug("[ %s relative_addr=%llx intstatus=%x idata=%llx]\n", + __FUNCTION__, relative_addr, d->ahb_ctl.intstatus, idata); + d->ahb_ctl.inten = idata; + if (d->ahb_ctl.inten == 0) { + d->ahb_ctl.intstatus = 0; + cpu_interrupt_ack(cpu, d->irqnr); + } + break; + case 0x1c: + case 0x20: + case 0x24: + case 0x28: + break; + default: + fatal("[ FCR SoC (%s): access unregister space? relative_addr=" + "0x%llx. ]\n", __FUNCTION__, (long long)relative_addr); + } + if (relative_addr != 0x18) + *((uint32_t *)(&d->ahb_ctl) + off) = idata; + } + else { + odata = *((uint32_t *)(&d->ahb_ctl) + off); + debug("[ %s relative_addr=%llx intstatus=%x odata=%llx inten=%x ]\n", + __FUNCTION__, relative_addr, d->ahb_ctl.intstatus, odata, d->ahb_ctl.inten); + memory_writemax64(cpu, data, len, odata); + } + + return 1; +} + +DEVICE_ACCESS(fcr_soc_apb) +{ + struct fcr_soc_data *d = extra; + uint64_t idata, odata; + int off; + + if (len != 1) + fatal("[ FCR SoC (%s): len=%i! ]\n", __FUNCTION__, len); + + if (relative_addr >= FCR_SOC_APB_LENGTH) { + fatal("[ FCR SoC (%s): outside register space? relative_addr=" + "0x%llx. bad addrmult? bad device length? ]\n", __FUNCTION__, + (long long)relative_addr); + return 0; + } + + off = relative_addr/8; + if (writeflag == MEM_WRITE) { + idata = memory_readmax64(cpu, data, len); + switch (relative_addr) { + case 0x00: + case 0x08: + case 0x10: + case 0x18: + case 0x20: + case 0x28: + case 0x40: + break; + default: + fatal("[ FCR SoC (%s): access unregister space? relative_addr=" + "0x%llx. ]\n", __FUNCTION__, (long long)relative_addr); + } + *((uint8_t *)(&d->apb_ctl) + off) = idata; + } + else { + odata = *((uint8_t *)(&d->apb_ctl) + off); + memory_writemax64(cpu, data, len, odata); + } + + return 1; +} + +/* + * Fiscal SoC (MIPS) Interrupt Controller. + * + * (Used by the GODSON1/GODSON2 machine.) + */ +void fcr_soc_interrupt(struct machine *m, struct cpu *cpu, int irq_nr, int assrt) +{ + struct fcr_soc_data *d = (struct fcr_soc_data *)m->md_int.priv; + int int_mask = 0; + + + /* interrupt from subdevices */ + if (assrt) { + int_mask = 0; + if (d->ahb_ctl.inten & (1 << irq_nr)) { + d->ahb_ctl.intstatus |= (1 << irq_nr); + int_mask = 1; + } + if (int_mask) + cpu_interrupt(cpu, d->irqnr); + } + else { /* Interrupts ack from subdevices */ + if (d->ahb_ctl.inten & (1 << irq_nr)) { + d->ahb_ctl.intstatus &= ~(1 << irq_nr); + } + if (d->ahb_ctl.intstatus == 0) + cpu_interrupt_ack(cpu, d->irqnr); + } +} + +void dev_fcr_soc_init(struct machine *machine, struct memory *mem) +{ + struct fcr_soc_data *d; + char tmpstr[1000]; + + d = malloc(sizeof(struct fcr_soc_data)); + if (d == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + + memset(d, 0, sizeof(struct fcr_soc_data)); + d->irqnr = 2; + d->ahb_ctl.ahb_misc = 0; + d->ahb_ctl.intedge = 0x0000ffff; + d->ahb_ctl.intsteer = 0; + d->ahb_ctl.intpol = 0; + d->ahb_ctl.intset = 0; + d->ahb_ctl.intclr = 0; + d->ahb_ctl.inten = 0; + d->ahb_ctl.intstatus = 0; + + memory_device_register(mem, "fcr_soc_ahb", FCR_SOC_AHB_MISC_BASE, FCR_SOC_AHB_LENGTH, + dev_fcr_soc_ahb_access, d, DM_DEFAULT, NULL); + memory_device_register(mem, "fcr_soc_apb", FCR_SOC_APB_MISC_BASE, FCR_SOC_APB_LENGTH, + dev_fcr_soc_apb_access, d, DM_DEFAULT, NULL); + + snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=13 addr=0x%x" + " in_use=1 ", FCR_SOC_MODEM_BASE); + machine->main_console_handle = (size_t)device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=11 addr=0x%x" + " in_use=0 ", FCR_SOC_UART0_BASE); + device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=12 addr=0x%x" + " in_use=0 ", FCR_SOC_UART1_BASE); + device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=14 addr=0x%x" + " in_use=0 ", FCR_SOC_IC0_BASE); + device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=15 addr=0x%x" + " in_use=0 ", FCR_SOC_IC1_BASE); + device_add(machine, tmpstr); + + machine->md_interrupt = fcr_soc_interrupt; + machine->md_int.priv =d; +} diff -urN gxemul-0.4.3/src/devices/dev_it8172.c gxemul-0.4.3.godson/src/devices/dev_it8172.c --- gxemul-0.4.3/src/devices/dev_it8172.c 1970-01-01 08:00:00.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/dev_it8172.c 2006-11-09 21:52:31.000000000 +0800 @@ -0,0 +1,905 @@ +/* + * Copyright (C) 2003-2006 Anders Gavare. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include "cpu.h" +#include "bus_pci.h" +#include "devices.h" +#include "device.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" + +#include "mc146818reg.h" +#include "it8172.h" +#include "it8172_int.h" +#include "irq.h" + + +#define to_bcd(x) ( ((x)/10) * 16 + ((x)%10) ) +#define from_bcd(x) ( ((x)>>4) * 10 + ((x)&15) ) +#define to_AM_PM(x) (d->use_bcd?from_bcd(x)>13?to_bcd(from_bcd(x)+80):to_bcd(x):x) + + +#define TICK_SHIFT 14 +#define BANK1_BASE 0x80 +#define ALARM2_BASE 0x100 +#define CENTURY_BASE 0x107 + + +/* Bank0 registers plus Bank1 registers plus Alarm registers */ +#define N_REGISTERS 264 +struct it_rtc_data { + int addrmult; + int access_style; + + int reg[N_REGISTERS]; + int index_bank0; + int if_index_bank0; + int index_bank1; + int if_index_bank1; + int index_alarm2; + int if_index_alarm2; + + int use_bcd; + int hour_12mode; + + int timebase_hz; + int interrupt_hz; + int irq_nr; + + int previous_second; + int n_seconds_elapsed; + int uip_threshold; + + int interrupt_every_x_cycles; + int cycles_left_until_interrupt; +}; + +struct it_intc_data { + /* Interrupt controller register */ + unsigned short lb_req; + unsigned short lb_mask; + unsigned short lb_trigger; + unsigned short lb_level; + unsigned short lpc_req; + unsigned short lpc_mask; + unsigned short lpc_trigger; + unsigned short lpc_level; + unsigned short pci_req; + unsigned short pci_mask; + unsigned short pci_trigger; + unsigned short pci_level; + unsigned short nmi_req; + unsigned short nmi_mask; + unsigned short nmi_trigger; + unsigned short nmi_level; + unsigned short nmi_redir; + unsigned short intstatus; + + int irqnr; +}; + +struct it_data { + int irqnr; + int pciirq; + int cur_bus; + int cur_dev; + int cur_func; + + struct pci_data *pci_data; +}; + + +/**********************************************/ +/* IT8172 RTC Controller */ +/**********************************************/ + +/* + * recalc_interrupt_cycle(): + * + * If automatic_clock_adjustment is turned on, then emulated_hz is modified + * dynamically. We have to recalculate how often interrupts are to be + * triggered. + */ +static void recalc_interrupt_cycle(struct cpu *cpu, struct it_rtc_data *d) +{ + int64_t emulated_hz = cpu->machine->emulated_hz; + if (d->interrupt_hz > 0) + d->interrupt_every_x_cycles = + emulated_hz / d->interrupt_hz; + else + d->interrupt_every_x_cycles = 0; +} + +/* + * it_rtc_update_time(): + * + * This function updates the it_rtc registers by reading + * the host's clock. + */ +static void it_rtc_update_time(struct it_rtc_data *d) +{ + struct tm *tmp; + time_t timet; + + timet = time(NULL); + tmp = gmtime(&timet); + + d->reg[MC_SEC] = tmp->tm_sec; + d->reg[MC_MIN] = tmp->tm_min; + d->reg[MC_HOUR] = tmp->tm_hour; + d->reg[MC_DOW] = tmp->tm_wday + 1; + d->reg[MC_DOM] = tmp->tm_mday; + d->reg[MC_MONTH] = tmp->tm_mon + 1; + d->reg[MC_YEAR] = tmp->tm_year; + + /* + * Special hacks for emulating the behaviour of various machines: + */ + if (d->use_bcd) { + d->reg[MC_SEC] = to_bcd(d->reg[MC_SEC]); + d->reg[MC_MIN] = to_bcd(d->reg[MC_MIN]); +// d->reg[MC_HOUR] = to_bcd(d->reg[MC_HOUR]); + d->reg[MC_DOW] = to_bcd(d->reg[MC_DOW]); + d->reg[MC_DOM] = to_bcd(d->reg[MC_DOM]); + d->reg[MC_MONTH] = to_bcd(d->reg[MC_MONTH]); + d->reg[MC_YEAR] = to_bcd(d->reg[MC_YEAR]); + } + d->reg[MC_HOUR] = to_AM_PM(d->reg[MC_HOUR]); +} + + +/* + * dev_it_rtc_access(): + * + * TODO: This access function only handles 8-bit accesses! + */ +DEVICE_ACCESS(it_rtc) +{ + struct tm *tmp; + time_t timet; + struct it_rtc_data *d = extra; + size_t i; + + relative_addr /= d->addrmult; //plj + +#ifdef MC146818_DEBUG + if (writeflag == MEM_WRITE) { + fatal("[ it_rtc: write to addr=0x%04x (len %i): ", + (int)relative_addr, (int)len); + for (i=0; iindex_bank0, d->reg[d->index_bank0]); + if (d->index_bank0 == MC_REGA || d->index_bank0 == MC_REGC) { + timet = time(NULL); + tmp = gmtime(&timet); + d->reg[MC_REGC] &= ~MC_REGC_UF; + if (tmp->tm_sec == d->previous_second) { + d->reg[MC_REGA] &= ~MC_REGA_UIP; + } + else { + d->previous_second = tmp->tm_sec; + d->reg[MC_REGA] |= MC_REGA_UIP; + + d->reg[MC_REGC] |= MC_REGC_UF; + d->reg[MC_REGC] |= MC_REGC_IRQF; + + d->reg[MC_REGC] |= MC_REGC_PF; + + } + } + + /* RTC data is in either BCD format or binary: */ + if (d->use_bcd) + d->reg[MC_REGB] &= ~(1 << 2); + else + d->reg[MC_REGB] |= (1 << 2); + + /* RTC date/time is always Valid: */ + d->reg[MC_REGD] |= MC_REGD_VRT; + + if (writeflag == MEM_WRITE) { + /* WRITE: */ + switch (relative_addr) { + case INDEX_BANK0: + d->index_bank0 = data[0]; + d->if_index_bank0 = 1; + break; + case TARGET_BANK0: + if (d->if_index_bank0) { + switch (d->index_bank0) { + case MC_SEC: + case MC_ASEC: + case MC_MIN: + case MC_AMIN: + case MC_HOUR: + case MC_AHOUR: + case MC_DOW: + case MC_DOM: + case MC_MONTH: + case MC_YEAR: + if (d->use_bcd) { + d->reg[d->index_bank0] = to_bcd(data[0]); + if (d->hour_12mode) + d->reg[d->index_bank0] = to_AM_PM(data[0]); + } + break; + case MC_REGA: + if ((data[0] & MC_REGA_DVMASK) == MC_BASE_32_KHz) + d->timebase_hz = 32000; + if ((data[0] & MC_REGA_DVMASK) == MC_BASE_1_MHz) + d->timebase_hz = 1000000; + if ((data[0] & MC_REGA_DVMASK) == MC_BASE_4_MHz) + d->timebase_hz = 4000000; + switch (data[0] & MC_REGA_RSMASK) { + case MC_RATE_NONE: + d->interrupt_hz = 0; + break; + case MC_RATE_1: + if (d->timebase_hz == 32000) + d->interrupt_hz = 256; + else + d->interrupt_hz = 32768; + break; + case MC_RATE_2: + if (d->timebase_hz == 32000) + d->interrupt_hz = 128; + else + d->interrupt_hz = 16384; + break; + case MC_RATE_8192_Hz: d->interrupt_hz = 8192; break; + case MC_RATE_4096_Hz: d->interrupt_hz = 4096; break; + case MC_RATE_2048_Hz: d->interrupt_hz = 2048; break; + case MC_RATE_1024_Hz: d->interrupt_hz = 1024; break; + case MC_RATE_512_Hz: d->interrupt_hz = 512; break; + case MC_RATE_256_Hz: d->interrupt_hz = 256; break; + case MC_RATE_128_Hz: d->interrupt_hz = 128; break; + case MC_RATE_64_Hz: d->interrupt_hz = 64; break; + case MC_RATE_32_Hz: d->interrupt_hz = 32; break; + case MC_RATE_16_Hz: d->interrupt_hz = 16; break; + case MC_RATE_8_Hz: d->interrupt_hz = 8; break; + case MC_RATE_4_Hz: d->interrupt_hz = 4; break; + case MC_RATE_2_Hz: d->interrupt_hz = 2; break; + default:/* debug("[ it_rtc: unimplemented " + "MC_REGA RS: %i ]\n", + data[0] & MC_REGA_RSMASK); */ + ; + } + + recalc_interrupt_cycle(cpu, d); + + d->cycles_left_until_interrupt = + d->interrupt_every_x_cycles; + + d->reg[MC_REGA] = + data[0] & (MC_REGA_RSMASK | MC_REGA_DVMASK); + + debug("[ rtc set to interrupt every %i:th cycle ]\n", + d->interrupt_every_x_cycles); + break; + case MC_REGB: + if (((data[0] ^ d->reg[MC_REGB]) & MC_REGB_PIE)) + d->cycles_left_until_interrupt = + d->interrupt_every_x_cycles; + if (data[0] & MC_REGB_24HR) + d->hour_12mode = 0; + else + d->hour_12mode = 1; + if (data[0] & MC_REGB_BINARY) + d->use_bcd = 1; + else + d->use_bcd = 0; + d->reg[MC_REGB] = data[0]; + if (!(data[0] & MC_REGB_PIE)) { + cpu_interrupt_ack(cpu, d->irq_nr); + /* d->cycles_left_until_interrupt = + d->interrupt_every_x_cycles; */ + } + /* debug("[ it_rtc: write to MC_REGB, data[0] " + "= 0x%02x ]\n", data[0]); */ + break; + case MC_REGC: + d->reg[MC_REGC] = data[0]; + debug("[ it_rtc: write to MC_REGC, data[0] = " + "0x%02x ]\n", data[0]); + break; + default: + d->reg[d->index_bank0] = data[0]; + + debug("[ it_rtc: unimplemented write to " + "index of bank0 = %08lx: ", (long)d->index_bank0); + for (i=0; iif_index_bank0 = 0; + break; + case INDEX_BANK1: + d->index_bank1 = data[0]; + d->if_index_bank1 = 1; + break; + case TARGET_BANK1: + if (d->if_index_bank1) + d->reg[d->index_bank1 + BANK1_BASE] = data[0]; + d->if_index_bank1 = 0; + break; + case INDEX_ALARM2: + d->index_alarm2 = data[0]; + d->if_index_alarm2 = 1; + break; + case TARGET_ALARM2: + if (d->if_index_alarm2) + d->reg[d->index_alarm2 + ALARM2_BASE] = data[0]; + d->if_index_alarm2 = 0; + case RTC_CENTURY_REG: + d->reg[CENTURY_BASE] = data[0]; + break; + } + } else { + /* READ: */ + switch (relative_addr) { + case INDEX_BANK0: + data[0] = d->index_bank0; + break; + case TARGET_BANK0: + if (d->if_index_bank0) + data[0] = d->reg[d->index_bank0]; + d->if_index_bank0 = 0; + if (d->reg[d->index_bank0] == MC_REGC) { + cpu_interrupt_ack(cpu, d->irq_nr); + d->reg[MC_REGC] = 0x00; + } + break; + case INDEX_BANK1: + data[0] = d->index_bank1; + break; + case TARGET_BANK1: + if (d->if_index_bank1) + data[0] = d->reg[d->index_bank1 + BANK1_BASE]; + d->if_index_bank1 = 0; + break; + case INDEX_ALARM2: + data[0] = d->index_alarm2; + break; + case TARGET_ALARM2: + if (d->if_index_alarm2) + data[0] = d->reg[d->index_alarm2 + ALARM2_BASE]; + d->if_index_alarm2 = 0; + case RTC_CENTURY_REG: + data[0] = d->reg[CENTURY_BASE]; + break; + } + } + +#ifdef MC146818_DEBUG + if (writeflag == MEM_READ) { + fatal("[ it_rtc: read from addr=0x%04x (len %i): ", + (int)relative_addr, (int)len); + for (i=0; iirq_nr = irq_nr; + d->addrmult = 1; + d->use_bcd = 0; + d->uip_threshold = 0; + d->index_bank0 = 0; + d->if_index_bank0 = 0; + d->index_bank1 = 0; + d->if_index_bank1 = 0; + d->index_alarm2 = 0; + d->if_index_alarm2 = 0; + d->hour_12mode = 0; + dev_len = 9; // ite8172 RTC + + memory_device_register(machine->memory, "it_rtc", addr, + dev_len * d->addrmult, dev_it_rtc_access, d, + DM_DEFAULT, NULL); + it_rtc_update_time(d); + return 1; +} + + +/*********************************************/ +/* IT8172 Interrupt controller */ +/*********************************************/ +/* + * It has no interrupt but will transfer it8172's interrupts + * so it should be assigned the same irqnr with it8172 + */ + +DEVICE_ACCESS(it_intc) +{ + uint64_t idata = 0, odata = 0; + struct it_intc_data *d = extra; + + + if (len != 2) + fatal("[ IT INTC ACCESS : len=%i! ]\n", len); + + if (writeflag == MEM_WRITE) { + idata = memory_readmax64(cpu, data, len); + } + if (writeflag == MEM_WRITE) { + switch (relative_addr) { + case 0x0: + if (idata) + debug("write to Local Bus interrupt request register\n"); + else + d->lb_req &= ~(d->lb_trigger); + break; + case 0x2: + d->lb_mask = (uint16_t)(idata & 0xffff); + if (d->lb_mask == 0xffff) + d->intstatus &= ~0x1; + break; + case 0x4: + d->lb_trigger = (uint16_t)(idata & 0xffff); + break; + case 0x6: + d->lb_level = (uint16_t)(idata & 0xffff); + break; + case 0x10: + if (idata) + debug("write to Serial IRQ interrupt request register\n"); + else + d->lpc_req &= ~(d->lpc_trigger); + break; + case 0x12: + d->lpc_mask = (uint16_t)(idata & 0xffff); + if (d->lpc_mask == 0xffff) + d->intstatus &= ~0x2; + break; + case 0x14: + d->lpc_trigger = (uint16_t)(idata & 0xffff); + break; + case 0x16: + d->lpc_level = (uint16_t)(idata & 0xffff); + break; + case 0x20: + if (idata) + debug("write to PCI interrupt request register\n"); + else + d->pci_req &= ~(d->pci_trigger); + break; + case 0x22: + debug("write to PCI interrupt mask register idata=%x\n", idata & 0xffff); + d->pci_mask = (uint16_t)(idata & 0xffff); + if (d->pci_mask == 0xffff) + d->intstatus &= ~0x4; + break; + case 0x24: + d->pci_trigger = (uint16_t)(idata & 0xffff); + break; + case 0x26: + d->pci_level = (uint16_t)(idata & 0xffff); + break; + case 0x30: + if (idata) + debug("write to NMI interrupt request register\n"); + else + d->nmi_req &= ~(d->nmi_trigger); + break; + case 0x32: + d->nmi_mask = (uint16_t)(idata & 0xffff); + if (d->nmi_mask == 0xffff) + d->intstatus &= ~0x8; + break; + case 0x34: + d->nmi_trigger = (uint16_t)(idata & 0xffff); + break; + case 0x36: + d->nmi_level = (uint16_t)(idata & 0xffff); + break; + case 0x3e: + d->nmi_redir = (uint16_t)(idata & 0xffff); + break; + case 0xfe: + d->intstatus = (uint16_t)(idata & 0xffff); + break; + default: + debug(""); + } + if (d->intstatus == 0) + cpu_interrupt_ack(cpu, d->irqnr); + } + else { + switch (relative_addr) { + case 0x0: + odata = d->lb_req; + break; + case 0x2: + odata = d->lb_mask; + break; + case 0x4: + odata = d->lb_trigger; + break; + case 0x6: + odata = d->lb_level; + break; + case 0x10: + odata = d->lpc_req; + break; + case 0x12: + odata = d->lpc_mask; + break; + case 0x14: + odata = d->lpc_trigger; + break; + case 0x16: + odata = d->lpc_level; + break; + case 0x20: + odata = d->pci_req; + break; + case 0x22: + odata = d->pci_mask; + break; + case 0x24: + odata = d->pci_trigger; + break; + case 0x26: + odata = d->pci_level; + break; + case 0x30: + odata = d->nmi_req; + break; + case 0x32: + odata = d->nmi_mask; + break; + case 0x34: + odata = d->nmi_trigger; + break; + case 0x36: + odata = d->nmi_level; + break; + case 0x3e: + odata = d->nmi_redir; + break; + case 0xfe: + odata = d->intstatus; + break; + default: + debug(""); + } + + memory_writemax64(cpu, data, len, odata); + } + return 1; +} + +/* + * IT8172 (MIPS) Interrupt Controller. + * + * (Used by the GODSON1/GODSON2 machine.) + */ +void it_interrupt(struct machine *m, struct cpu *cpu, int irq_nr, int assrt) +{ + struct it_intc_data *d = (struct it_intc_data *)m->md_int.priv; + int int_mask = 0; + + debug("lpc_mask=%04x lb_mask=%04x pci_mask=%04x nmi_mask=%04x\n", d->lpc_mask, d->lb_mask, d->pci_mask, d->nmi_mask); + + if (irq_nr < NB_IRQ_BASE || irq_nr > NB_IRQ_BASE + 64) + fatal("[ %s:unknown irq %d ]\n", __FUNCTION__, irq_nr); + irq_nr -= NB_IRQ_BASE; + + /* interrupt from subdevices */ + if (assrt) { + int_mask = 0; + if (irq_nr >= IT8172_LPC_IRQ_BASE && irq_nr <= IT8172_SERIRQ_15) { + if (!(d->lpc_mask & (1 << (irq_nr - IT8172_LPC_IRQ_BASE)))) { + d->intstatus |= 0x2; + d->lpc_req |= (1 << (irq_nr - IT8172_LPC_IRQ_BASE)); + int_mask = 1; + } + } + else if (irq_nr >= IT8172_LB_IRQ_BASE && irq_nr <= IT8172_IOCHK_IRQ) { + if (!(d->lb_mask & (1 << (irq_nr - IT8172_LB_IRQ_BASE)))) { + d->intstatus |= 0x1; + d->lb_req |= (1 << (irq_nr - IT8172_LB_IRQ_BASE)); + int_mask = 1; + } + } + else if (irq_nr >= IT8172_PCI_DEV_IRQ_BASE && irq_nr <= IT8172_DMA_IRQ) { + if (!(d->pci_mask & (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)))) { + d->intstatus |= 0x4; + d->pci_req |= (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); + int_mask = 1; + } + } + else if (irq_nr >= IT8172_NMI_IRQ_BASE && irq_nr <= IT8172_POWER_NMI_IRQ) { + if (!(d->nmi_mask & (1 << (irq_nr - IT8172_NMI_IRQ_BASE)))) { + d->intstatus |= 0x8; + d->nmi_req |= (1 << (irq_nr - IT8172_NMI_IRQ_BASE)); + int_mask = 1; + } + } + else { + fatal("it_interrupt: bad irq %d\n", irq_nr); + } + + if (int_mask) + cpu_interrupt(cpu, d->irqnr); // triger the int0 of mips cpu + } + else { /* Interrupts ack from subdevices */ + int_mask = 0; + if (irq_nr >= IT8172_LPC_IRQ_BASE && irq_nr <= IT8172_SERIRQ_15) { + if (!(d->lpc_mask & (1 << (irq_nr - IT8172_LPC_IRQ_BASE)))) { + d->lpc_req &= ~(1 << (irq_nr - IT8172_LPC_IRQ_BASE)); + if (d->lpc_req == 0) + d->intstatus &= ~0x2; + int_mask = 1; + } + } + else if (irq_nr >= IT8172_LB_IRQ_BASE && irq_nr <= IT8172_IOCHK_IRQ) { + if (!(d->lb_mask & (1 << (irq_nr - IT8172_LB_IRQ_BASE)))) { + d->lb_req &= ~(1 << (irq_nr - IT8172_LB_IRQ_BASE)); + if (d->lb_req == 0) + d->intstatus &= ~0x1; + int_mask = 1; + } + } + else if (irq_nr >= IT8172_PCI_DEV_IRQ_BASE && irq_nr <= IT8172_DMA_IRQ) { + if (!(d->pci_mask & (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)))) { + d->pci_req &=~(1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE)); + if (d->pci_req == 0) + d->intstatus &= ~0x4; + int_mask = 1; + } + } + else if (irq_nr >= IT8172_NMI_IRQ_BASE && irq_nr <= IT8172_POWER_NMI_IRQ) { + if (!(d->nmi_mask & (1 << (irq_nr - IT8172_NMI_IRQ_BASE)))) { + d->nmi_req &= ~(1 << (irq_nr - IT8172_NMI_IRQ_BASE)); + if (d->nmi_req == 0) + d->intstatus &= ~0x8; + int_mask = 1; + } + } + else { + fatal("it_interrupt: bad irq %d\n", irq_nr); + } + + /* No pending interrupts, we should send ack to cpu */ +// if (d->intstatus == 0 && int_mask) + if (d->intstatus == 0) + cpu_interrupt_ack(cpu, d->irqnr); // triger the int0 of mips cpu + } +} + + +int devinit_it_intc(struct machine *machine, uint64_t addr, int irq_nr) +{ + struct it_intc_data *d; + + d = malloc(sizeof(struct it_rtc_data)); + if (d == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + memset(d, 0, sizeof(struct it_rtc_data)); + /* set default Interrupt register value */ + d->lb_mask = 0xffff; + d->lpc_mask = 0xffff; + d->pci_mask = 0xffff; + d->nmi_mask = 0xffff; + d->lb_trigger = 0x0801; + d->lpc_trigger = 0xfffb; + d->pci_trigger = 0x0030; + d->nmi_trigger = 0x002b; + d->lb_level = 0xf7ff; + d->lpc_level = 0x0004; + d->pci_level = 0x4036; + d->nmi_level = 0xffec; + d->nmi_redir = 0x0080; + d->intstatus = 0x0000; + d->irqnr = irq_nr; + + /* Interrupt controller */ + /* Initialise interrupt private data */ + machine->md_interrupt = it_interrupt; + machine->md_int.priv = d; + + memory_device_register(machine->memory, "it_intc", addr, + IT_INTC_LENGTH , dev_it_intc_access, d, + DM_DEFAULT, NULL); + return 1; +} + + +/*******************************************/ +/* IT8172 System config register */ +/* controller */ +/*******************************************/ +/* + * dev_it_access(): + */ +DEVICE_ACCESS(it_pci) +{ + uint64_t idata = 0, odata = 0; + int bus, dev, func, reg; + size_t i; + struct it_data *d = extra; + + + if (relative_addr >= 0x0000 && relative_addr < 0x1000) + debug("Access system configuration registers\n"); + else if (relative_addr >= 0x1000 && relative_addr < 0x2000) + debug("Access SDRAM Control registers\n"); + else if (relative_addr >= 0x2000 && relative_addr < 0x3000) + debug("Access Flash/Rom Control registers\n"); + else if ((relative_addr >= 0x3000 && relative_addr < 0x4000) || + (relative_addr >= 0x5000)) + fatal("Access undefined address space\n"); + else { + debug("Access PCI Configuration Registers\n"); + } + + if (writeflag == MEM_WRITE) { + idata = memory_readmax64(cpu, data, len); + if (relative_addr == 0x4000) { + bus_pci_decompose_1(idata, &bus, &dev, &func, ®); + if (dev*8+func > IT_PCI_MAX_NUMBER) { + debug("Exceed the max number of PCI device function, ignore\n"); + return 1; + } + d->cur_bus = bus; + d->cur_dev = dev; + d->cur_func = func; + bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg); // pci addr + } else if (relative_addr == 0x4004) { + bus = d->cur_bus; + dev = d->cur_dev; + func = d->cur_func; + bus_pci_data_access(cpu, d->pci_data, &idata, len, writeflag); // pci data + } + debug("[ it: write to addr 0x%x:", (int)relative_addr); + for (i=0; icur_bus; + dev = d->cur_dev; + func = d->cur_func; + bus_pci_data_access(cpu, d->pci_data, &odata, len, writeflag); // pci data + } + memory_writemax64(cpu, data, len, odata); + debug("[ it: read from addr 0x%x, get %x]\n", + (int)relative_addr, odata); + } + return 1; +} + + +/* + * dev_it_init(): + * + * Initialize a ITE device. Return a pointer to the pci_data used, so that + * the caller may add PCI devices. First, however, we add the ITE device + * itself. + */ +NBINIT(it) +{ + struct it_data *d; + uint64_t pci_portbase = 0x14016000; + uint64_t pci_membase = 14010000; + int pci_irqbase = 32; + uint64_t isa_portbase = 0, isa_membase = 0; + int isa_irqbase = 0; + uint64_t pci_io_offset = 0, pci_mem_offset = 0; + char *it_name[IT_PCI_SELF_NUMBER]; + char tmpstr[1000]; + int i,j; + + d = malloc(sizeof(struct it_data)); + if (d == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + memset(d, 0, sizeof(struct it_data)); + + d->irqnr = irq_nr; + d->pciirq = 8; //plj + + it_name[0] = strdup("it_cpu_to_pci_bridge"); + it_name[1] = strdup("it_audio_controller"); + it_name[2] = strdup("it_dma_controller"); + it_name[3] = strdup("it_chain_dma_controller"); + it_name[4] = strdup("it_usb_host"); + it_name[5] = strdup("it_pci_to_internal_bridge"); + it_name[6] = strdup("it_ide_controller"); + it_name[7] = strdup("it_68k_controller"); + + + d->pci_data = bus_pci_init(machine, d->pciirq, pci_io_offset, + pci_mem_offset, pci_portbase, pci_membase, pci_irqbase, + isa_portbase, isa_membase, isa_irqbase); + /* + * pchb0 at pci0 dev 0 function 0: ITE-8172G + * System Controller, rev 2 + * In fact, ITE-8172G have 8 pci controllers or bridges, we use default value + */ + /* bus 0 device 1 function 4. PCI/internal Bus bridge */ + bus_pci_add(machine, d->pci_data, machine->memory, 0, 0, 0, it_name[0]); + bus_pci_add(machine, d->pci_data, machine->memory, 0, 1, 0, it_name[1]); + bus_pci_add(machine, d->pci_data, machine->memory, 0, 1, 1, it_name[2]); + bus_pci_add(machine, d->pci_data, machine->memory, 0, 1, 2, it_name[3]); + bus_pci_add(machine, d->pci_data, machine->memory, 0, 1, 3, it_name[4]); + bus_pci_add(machine, d->pci_data, machine->memory, 0, 1, 4, it_name[5]); + bus_pci_add(machine, d->pci_data, machine->memory, 0, 1, 5, it_name[6]); + bus_pci_add(machine, d->pci_data, machine->memory, 0, 1, 6, it_name[7]); + + memory_device_register(machine->memory, "it_pci", IT8172_BASE, IT8172_LENGTH, + dev_it_pci_access, d, DM_DEFAULT, NULL); + + snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%d addr=0x%x" + " in_use=%i", NB_IRQ_BASE + IT8172_UART_IRQ, + IT8172_PCI_IO_BASE + IT_UART_BASE, machine->use_x11 ? 0 : 1); + machine->main_console_handle = (size_t)device_add(machine, tmpstr); + + devinit_it_rtc(machine, IT8172_PCI_IO_BASE + IT_RTC_BASE, NB_IRQ_BASE + 26); + devinit_it_intc(machine, IT8172_PCI_IO_BASE + IT_INTC_BASE, d->irqnr); + +// memory_device_register(machine->memory, "it_flash", IT8172_FLASH_BASE, IT8172_FLASH_LENGTH, +// dev_it_flash_access, d, DM_DEFAULT, NULL); + + return d->pci_data; +} + diff -urN gxemul-0.4.3/src/devices/dev_nodev.c gxemul-0.4.3.godson/src/devices/dev_nodev.c --- gxemul-0.4.3/src/devices/dev_nodev.c 1970-01-01 08:00:00.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/dev_nodev.c 2006-11-09 22:56:09.000000000 +0800 @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2004-2006 Anders Gavare. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * + * Access unaddressable space + * * + * TODO: Actually implement this device. So far it's just a fake device + * to allow Linux to print stuff to the console. + */ + +#include +#include +#include + +#include "console.h" +#include "device.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" +#define NO_DEV_LENGTH 0x10 + +struct nodev_data { + char *name; +}; + +DEVICE_ACCESS(nodev) +{ + uint64_t idata = 0, odata = 0; + struct nodev_data *d = extra; + + if (writeflag == MEM_WRITE) { + idata = memory_readmax64(cpu, data, len); + debug("[ %s: cpu write %08llx to device %s addr %08llx ]\n", idata, d->name, relative_addr); + } + else if (writeflag == MEM_READ) { + odata = 0; + memory_writemax64(cpu, data, len, odata); + } + + return 1; +} + +DEVINIT(nodev) +{ + char *name; + struct nodev_data *d; + int nlen = 100; + d = malloc(sizeof(struct nodev_data)); + if (d == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + memset(d, 0, sizeof(struct nodev_data)); + d->name = devinit->name2 != NULL? devinit->name2 : ""; + name = malloc(nlen); + if (name == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + if (devinit->name2 != NULL && devinit->name2[0]) + snprintf(name, nlen, "%s [%s]", devinit->name, devinit->name2); + else + snprintf(name, nlen, "%s", devinit->name); + + /* Ugly, fix me!! */ + memory_device_register(devinit->machine->memory, name, + devinit->addr, NO_DEV_LENGTH, dev_nodev_access, d, DM_DEFAULT, NULL); + return 1; +} diff -urN gxemul-0.4.3/src/devices/dev_pccmos.c gxemul-0.4.3.godson/src/devices/dev_pccmos.c --- gxemul-0.4.3/src/devices/dev_pccmos.c 2006-07-11 12:44:09.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/dev_pccmos.c 2006-11-09 22:58:56.000000000 +0800 @@ -170,6 +170,11 @@ /* TODO */ irq_nr = 32 + 8; break; + /* plj */ + case MACHINE_GODSON1: + case MACHINE_GODSON2: + irq_nr = 8 + 8; + break; default:fatal("devinit_pccmos(): unimplemented machine type" " %i\n", devinit->machine->machine_type); exit(1); diff -urN gxemul-0.4.3/src/devices/dev_rtl8139.c gxemul-0.4.3.godson/src/devices/dev_rtl8139.c --- gxemul-0.4.3/src/devices/dev_rtl8139.c 1970-01-01 08:00:00.000000000 +0800 +++ gxemul-0.4.3.godson/src/devices/dev_rtl8139.c 2006-11-09 23:01:30.000000000 +0800 @@ -0,0 +1,2722 @@ +/* + * Copyright (C) 2004-2006 Anders Gavare. All rights reserved. + * Athor: Pengliangjin. ict. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * $Id: dev_rtl8139.c,v 1.24 2006/10/8 16:55:41 debug Exp $ + * + * rtl8139 ethernet controller. + * + * TODO: + */ + +#include +#include +#include + +#include "device.h" +#include "cpu.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" +#include "net.h" +#include "emul.h" + +/* #define DEBUG_RTL8139 */ + +#define TICK_SHIFT 14 +#define DEV_RTL8139_LENGTH 256 + +#define SET_MASKED(input, mask, curr) \ + ( ( (input) & ~(mask) ) | ( (curr) & (mask) ) ) + +/* arg % size for size which is a power of 2 */ +#define MOD2(input, size) \ + ( ( input ) & ( size - 1 ) ) + +/* Symbolic offsets to registers. */ +enum RTL8139_registers { + MAC0 = 0, /* Ethernet hardware address. */ + MAR0 = 8, /* Multicast filter. */ + TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ + TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ + RxBuf = 0x30, + ChipCmd = 0x37, + RxBufPtr = 0x38, + RxBufAddr = 0x3A, + IntrMask = 0x3C, + IntrStatus = 0x3E, + TxConfig = 0x40, + RxConfig = 0x44, + Timer = 0x48, /* A general-purpose counter. */ + RxMissed = 0x4C, /* 24 bits valid, write clears. */ + Cfg9346 = 0x50, + Config0 = 0x51, + Config1 = 0x52, + FlashReg = 0x54, + MediaStatus = 0x58, + Config3 = 0x59, + Config4 = 0x5A, /* absent on RTL-8139A */ + HltClk = 0x5B, + MultiIntr = 0x5C, + PCIRevisionID = 0x5E, + TxSummary = 0x60, /* TSAD register. Transmit Status of All Descriptors*/ + BasicModeCtrl = 0x62, + BasicModeStatus = 0x64, + NWayAdvert = 0x66, + NWayLPAR = 0x68, + NWayExpansion = 0x6A, + /* Undocumented registers, but required for proper operation. */ + FIFOTMS = 0x70, /* FIFO Control and test. */ + CSCR = 0x74, /* Chip Status and Configuration Register. */ + PARA78 = 0x78, + PARA7c = 0x7c, /* Magic transceiver parameter register. */ + Config5 = 0xD8, /* absent on RTL-8139A */ + /* C+ mode */ + TxPoll = 0xD9, /* Tell chip to check Tx descriptors for work */ + RxMaxSize = 0xDA, /* Max size of an Rx packet (8169 only) */ + CpCmd = 0xE0, /* C+ Command register (C+ mode only) */ + IntrMitigate = 0xE2, /* rx/tx interrupt mitigation control */ + RxRingAddrLO = 0xE4, /* 64-bit start addr of Rx ring */ + RxRingAddrHI = 0xE8, /* 64-bit start addr of Rx ring */ + TxThresh = 0xEC, /* Early Tx threshold */ +}; + +enum ClearBitMasks { + MultiIntrClear = 0xF000, + ChipCmdClear = 0xE2, + Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1), +}; + +enum ChipCmdBits { + CmdReset = 0x10, + CmdRxEnb = 0x08, + CmdTxEnb = 0x04, + RxBufEmpty = 0x01, +}; + +/* C+ mode */ +enum CplusCmdBits { + CPlusRxEnb = 0x0002, + CPlusTxEnb = 0x0001, +}; + +/* Interrupt register bits, using my own meaningful names. */ +enum IntrStatusBits { + PCIErr = 0x8000, + PCSTimeout = 0x4000, + RxFIFOOver = 0x40, + RxUnderrun = 0x20, + RxOverflow = 0x10, + TxErr = 0x08, + TxOK = 0x04, + RxErr = 0x02, + RxOK = 0x01, + + RxAckBits = RxFIFOOver | RxOverflow | RxOK, +}; + +enum TxStatusBits { + TxHostOwns = 0x2000, + TxUnderrun = 0x4000, + TxStatOK = 0x8000, + TxOutOfWindow = 0x20000000, + TxAborted = 0x40000000, + TxCarrierLost = 0x80000000, +}; +enum RxStatusBits { + RxMulticast = 0x8000, + RxPhysical = 0x4000, + RxBroadcast = 0x2000, + RxBadSymbol = 0x0020, + RxRunt = 0x0010, + RxTooLong = 0x0008, + RxCRCErr = 0x0004, + RxBadAlign = 0x0002, + RxStatusOK = 0x0001, +}; + +/* Bits in RxConfig. */ +enum rx_mode_bits { + AcceptErr = 0x20, + AcceptRunt = 0x10, + AcceptBroadcast = 0x08, + AcceptMulticast = 0x04, + AcceptMyPhys = 0x02, + AcceptAllPhys = 0x01, +}; + +/* Bits in TxConfig. */ +enum tx_config_bits { + + /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */ + TxIFGShift = 24, + TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */ + TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */ + TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */ + TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */ + + TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ + TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ + TxClearAbt = (1 << 0), /* Clear abort (WO) */ + TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */ + TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */ + + TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ +}; + + +/* Transmit Status of All Descriptors (TSAD) Register */ +enum TSAD_bits { + TSAD_TOK3 = 1<<15, // TOK bit of Descriptor 3 + TSAD_TOK2 = 1<<14, // TOK bit of Descriptor 2 + TSAD_TOK1 = 1<<13, // TOK bit of Descriptor 1 + TSAD_TOK0 = 1<<12, // TOK bit of Descriptor 0 + TSAD_TUN3 = 1<<11, // TUN bit of Descriptor 3 + TSAD_TUN2 = 1<<10, // TUN bit of Descriptor 2 + TSAD_TUN1 = 1<<9, // TUN bit of Descriptor 1 + TSAD_TUN0 = 1<<8, // TUN bit of Descriptor 0 + TSAD_TABT3 = 1<<07, // TABT bit of Descriptor 3 + TSAD_TABT2 = 1<<06, // TABT bit of Descriptor 2 + TSAD_TABT1 = 1<<05, // TABT bit of Descriptor 1 + TSAD_TABT0 = 1<<04, // TABT bit of Descriptor 0 + TSAD_OWN3 = 1<<03, // OWN bit of Descriptor 3 + TSAD_OWN2 = 1<<02, // OWN bit of Descriptor 2 + TSAD_OWN1 = 1<<01, // OWN bit of Descriptor 1 + TSAD_OWN0 = 1<<00, // OWN bit of Descriptor 0 +}; + + +/* Bits in Config1 */ +enum Config1Bits { + Cfg1_PM_Enable = 0x01, + Cfg1_VPD_Enable = 0x02, + Cfg1_PIO = 0x04, + Cfg1_MMIO = 0x08, + LWAKE = 0x10, /* not on 8139, 8139A */ + Cfg1_Driver_Load = 0x20, + Cfg1_LED0 = 0x40, + Cfg1_LED1 = 0x80, + SLEEP = (1 << 1), /* only on 8139, 8139A */ + PWRDN = (1 << 0), /* only on 8139, 8139A */ +}; + +/* Bits in Config3 */ +enum Config3Bits { + Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */ + Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */ + Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */ + Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */ + Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */ + Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */ + Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */ + Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */ +}; + +/* Bits in Config4 */ +enum Config4Bits { + LWPTN = (1 << 2), /* not on 8139, 8139A */ +}; + +/* Bits in Config5 */ +enum Config5Bits { + Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */ + Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */ + Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */ + Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */ + Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */ + Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */ + Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */ +}; + +enum RxConfigBits { + /* rx fifo threshold */ + RxCfgFIFOShift = 13, + RxCfgFIFONone = (7 << RxCfgFIFOShift), + + /* Max DMA burst */ + RxCfgDMAShift = 8, + RxCfgDMAUnlimited = (7 << RxCfgDMAShift), + + /* rx ring buffer length */ + RxCfgRcv8K = 0, + RxCfgRcv16K = (1 << 11), + RxCfgRcv32K = (1 << 12), + RxCfgRcv64K = (1 << 11) | (1 << 12), + + /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */ + RxNoWrap = (1 << 7), +}; + +/* Twister tuning parameters from RealTek. + Completely undocumented, but required to tune bad links on some boards. */ +/* +enum CSCRBits { + CSCR_LinkOKBit = 0x0400, + CSCR_LinkChangeBit = 0x0800, + CSCR_LinkStatusBits = 0x0f000, + CSCR_LinkDownOffCmd = 0x003c0, + CSCR_LinkDownCmd = 0x0f3c0, +*/ +enum CSCRBits { + CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */ + CSCR_LD = 1<<9, /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/ + CSCR_HEART_BIT = 1<<8, /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/ + CSCR_JBEN = 1<<7, /* 1 = enable jabber function. 0 = disable jabber function, def 1*/ + CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/ + CSCR_F_Connect = 1<<5, /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/ + CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/ + CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/ + CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/ +}; + +enum Cfg9346Bits { + Cfg9346_Lock = 0x00, + Cfg9346_Unlock = 0xC0, +}; + +typedef enum { + CH_8139 = 0, + CH_8139_K, + CH_8139A, + CH_8139A_G, + CH_8139B, + CH_8130, + CH_8139C, + CH_8100, + CH_8100B_8139D, + CH_8101, +} chip_t; + +enum chip_flags { + HasHltClk = (1 << 0), + HasLWake = (1 << 1), +}; + +#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \ + (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22) +#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1) + +/* Size is 64 * 16bit words */ +#define EEPROM_9346_ADDR_BITS 6 +#define EEPROM_9346_SIZE (1 << EEPROM_9346_ADDR_BITS) +#define EEPROM_9346_ADDR_MASK (EEPROM_9346_SIZE - 1) + +enum Chip9346Operation +{ + Chip9346_op_mask = 0xc0, /* 10 zzzzzz */ + Chip9346_op_read = 0x80, /* 10 AAAAAA */ + Chip9346_op_write = 0x40, /* 01 AAAAAA D(15)..D(0) */ + Chip9346_op_ext_mask = 0xf0, /* 11 zzzzzz */ + Chip9346_op_write_enable = 0x30, /* 00 11zzzz */ + Chip9346_op_write_all = 0x10, /* 00 01zzzz */ + Chip9346_op_write_disable = 0x00, /* 00 00zzzz */ +}; + +enum Chip9346Mode +{ + Chip9346_none = 0, + Chip9346_enter_command_mode, + Chip9346_read_command, + Chip9346_data_read, /* from output register */ + Chip9346_data_write, /* to input register, then to contents at specified address */ + Chip9346_data_write_all, /* to input register, then filling contents */ +}; + +typedef struct EEprom9346 +{ + uint16_t contents[EEPROM_9346_SIZE]; + int mode; + uint32_t tick; + uint8_t address; + uint16_t input; + uint16_t output; + + uint8_t eecs; + uint8_t eesk; + uint8_t eedi; + uint8_t eedo; +} EEprom9346; + +typedef struct RTL8139State { + uint8_t phys[8]; /* mac address */ + uint8_t mult[8]; /* multicast mask array */ + + uint32_t TxStatus[4]; /* TxStatus0 */ + uint32_t TxAddr[4]; /* TxAddr0 */ + uint32_t RxBuf; /* Receive buffer */ + uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */ + uint32_t RxBufPtr; + uint32_t RxBufAddr; + + uint16_t IntrStatus; + uint16_t IntrMask; + + uint32_t TxConfig; + uint32_t RxConfig; + uint32_t RxMissed; + + uint16_t CSCR; + + uint8_t Cfg9346; + uint8_t Config0; + uint8_t Config1; + uint8_t Config3; + uint8_t Config4; + uint8_t Config5; + + uint8_t clock_enabled; + uint8_t bChipCmdState; + + uint16_t MultiIntr; + + uint16_t BasicModeCtrl; + uint16_t BasicModeStatus; + uint16_t NWayAdvert; + uint16_t NWayLPAR; + uint16_t NWayExpansion; + + uint16_t CpCmd; + uint8_t TxThresh; + + int irq; + char *name; + struct cpu *cpu; + uint8_t macaddr[6]; + int rtl8139_mmio_io_addr; + + /* C ring mode */ + uint32_t currTxDesc; + + /* C+ mode */ + uint32_t currCPlusRxDesc; + uint32_t currCPlusTxDesc; + + uint32_t RxRingAddrLO; + uint32_t RxRingAddrHI; + + EEprom9346 eeprom; + +} RTL8139State; + + +inline uint32_t le32_to_cpu(uint32_t val) +{ + return val; +} +inline uint32_t be32_to_cpu(uint32_t val) +{ + uint32_t ret; + ret = ((val&0xff)<<24)|((val&0xff00)<<8)|((val&0xff0000)>>8)|((val&0xff000000)>>24); + return ret; +} + +#define cpu_to_le32 le32_to_cpu +#define cpu_to_be32 be32_to_cpu + +void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) +{ +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom command 0x%02x\n", command); +#endif + + switch (command & Chip9346_op_mask) + { + case Chip9346_op_read: + { + eeprom->address = command & EEPROM_9346_ADDR_MASK; + eeprom->output = eeprom->contents[eeprom->address]; + eeprom->eedo = 0; + eeprom->tick = 0; + eeprom->mode = Chip9346_data_read; +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom read from address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output); +#endif + } + break; + + case Chip9346_op_write: + { + eeprom->address = command & EEPROM_9346_ADDR_MASK; + eeprom->input = 0; + eeprom->tick = 0; + eeprom->mode = Chip9346_none; /* Chip9346_data_write */ +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom begin write to address 0x%02x\n", + eeprom->address); +#endif + } + break; + default: + eeprom->mode = Chip9346_none; + switch (command & Chip9346_op_ext_mask) + { + case Chip9346_op_write_enable: +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom write enabled\n"); +#endif + break; + case Chip9346_op_write_all: +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom begin write all\n"); +#endif + break; + case Chip9346_op_write_disable: +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom write disabled\n"); +#endif + break; + } + break; + } +} + +void prom9346_shift_clock(EEprom9346 *eeprom) +{ + int bit = eeprom->eedi?1:0; + + ++ eeprom->tick; + +#if defined(DEBUG_RTL8139) + printf("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo); +#endif + + switch (eeprom->mode) + { + case Chip9346_enter_command_mode: + if (bit) + { + eeprom->mode = Chip9346_read_command; + eeprom->tick = 0; + eeprom->input = 0; +#if defined(DEBUG_RTL8139) + printf("eeprom: +++ synchronized, begin command read\n"); +#endif + } + break; + + case Chip9346_read_command: + eeprom->input = (eeprom->input << 1) | (bit & 1); + if (eeprom->tick == 8) + { + prom9346_decode_command(eeprom, eeprom->input & 0xff); + } + break; + + case Chip9346_data_read: + eeprom->eedo = (eeprom->output & 0x8000)?1:0; + eeprom->output <<= 1; + if (eeprom->tick == 16) + { + ++eeprom->address; + eeprom->address &= EEPROM_9346_ADDR_MASK; + eeprom->output = eeprom->contents[eeprom->address]; + eeprom->tick = 0; + +#if defined(DEBUG_RTL8139) + printf("eeprom: +++ read next address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output); +#endif + } + break; + + case Chip9346_data_write: + eeprom->input = (eeprom->input << 1) | (bit & 1); + if (eeprom->tick == 16) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom write to address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->input); +#endif + eeprom->contents[eeprom->address] = eeprom->input; + eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */ + eeprom->tick = 0; + eeprom->input = 0; + } + break; + + case Chip9346_data_write_all: + eeprom->input = (eeprom->input << 1) | (bit & 1); + if (eeprom->tick == 16) + { + int i; + for (i = 0; i < EEPROM_9346_SIZE; i++) + { + eeprom->contents[i] = eeprom->input; + } +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom filled with data=0x%04x\n", + eeprom->input); +#endif + eeprom->mode = Chip9346_enter_command_mode; + eeprom->tick = 0; + eeprom->input = 0; + } + break; + + default: + break; + } +} + +int prom9346_get_wire(RTL8139State *s) +{ + EEprom9346 *eeprom = &s->eeprom; + if (!eeprom->eecs) + return 0; + + return eeprom->eedo; +} + +void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) +{ + EEprom9346 *eeprom = &s->eeprom; + uint8_t old_eecs = eeprom->eecs; + uint8_t old_eesk = eeprom->eesk; + + eeprom->eecs = eecs; + eeprom->eesk = eesk; + eeprom->eedi = eedi; + +#if defined(DEBUG_RTL8139) + printf("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo); +#endif + + if (!old_eecs && eecs) + { + /* Synchronize start */ + eeprom->tick = 0; + eeprom->input = 0; + eeprom->output = 0; + eeprom->mode = Chip9346_enter_command_mode; + +#if defined(DEBUG_RTL8139) + printf("=== eeprom: begin access, enter command mode\n"); +#endif + + } + + if (!eecs) + { +#if defined(DEBUG_RTL8139) + printf("=== eeprom: end access\n"); +#endif + return; + } + + if (!old_eesk && eesk) + { + /* SK front rules */ + prom9346_shift_clock(eeprom); + } +} + +static void rtl8139_update_irq(RTL8139State *s) +{ + int isr; + isr = (s->IntrStatus & s->IntrMask) & 0xffff; +#if defined(DEBUG_RTL8139) + printf("RTL8139: Set IRQ line %d to %d (%04x %04x)\n", + s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask); +#endif + + if (isr != 0) + cpu_interrupt(s->cpu, s->irq); + else + cpu_interrupt_ack(s->cpu, s->irq); +} + +#define POLYNOMIAL 0x04c11db6 + +/* From FreeBSD */ +/* XXX: optimize */ +static int compute_mcast_idx(const uint8_t *ep) +{ + uint32_t crc; + int carry, i, j; + uint8_t b; + + crc = 0xffffffff; + for (i = 0; i < 6; i++) { + b = *ep++; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); + crc <<= 1; + b >>= 1; + if (carry) + crc = ((crc ^ POLYNOMIAL) | carry); + } + } + return (crc >> 26); +} + +static int rtl8139_RxWrap(RTL8139State *s) +{ + /* wrapping enabled; assume 1.5k more buffer space if size < 65536 */ + return (s->RxConfig & (1 << 7)); +} + +static int rtl8139_receiver_enabled(RTL8139State *s) +{ + return s->bChipCmdState & CmdRxEnb; +} + +static int rtl8139_transmitter_enabled(RTL8139State *s) +{ + return s->bChipCmdState & CmdTxEnb; +} + +static int rtl8139_cp_receiver_enabled(RTL8139State *s) +{ + return s->CpCmd & CPlusRxEnb; +} + +static int rtl8139_cp_transmitter_enabled(RTL8139State *s) +{ + return s->CpCmd & CPlusTxEnb; +} + +static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) +{ + if (s->RxBufAddr + size > s->RxBufferSize) + { + int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize); + + /* write packet data */ + if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s)) + { + #if defined(DEBUG_RTL8139) + printf(">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped); + #endif + + if (size > wrapped) + { + cpu_physical_memory_rw(s->cpu, s->RxBuf + s->RxBufAddr, + buf, size-wrapped, MEM_WRITE); + } + + /* reset buffer pointer */ + s->RxBufAddr = 0; + + cpu_physical_memory_rw(s->cpu, s->RxBuf + s->RxBufAddr, + buf + (size-wrapped), wrapped, MEM_WRITE); + + s->RxBufAddr = wrapped; + + return; + } + } + + /* non-wrapping path or overwrapping enabled */ + cpu_physical_memory_rw(s->cpu, s->RxBuf + s->RxBufAddr, buf, size, MEM_WRITE); + + s->RxBufAddr += size; +} + +typedef uint64_t target_phys_addr_t; +#define MIN_BUF_SIZE 60 +static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high) +{ +#if TARGET_PHYS_ADDR_BITS > 32 + return low | ((target_phys_addr_t)high << 32); +#else + return low; +#endif +} + +static int rtl8139_can_receive(void *opaque) +{ + RTL8139State *s = opaque; + int avail; + + /* Recieve (drop) packets if card is disabled. */ + if (!s->clock_enabled) + return 1; + if (!rtl8139_receiver_enabled(s)) + return 1; + + if (rtl8139_cp_receiver_enabled(s)) { + /* ??? Flow control not implemented in c+ mode. + This is a hack to work around slirp deficiencies anyway. */ + return 1; + } else { + avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, + s->RxBufferSize); + return (avail == 0 || avail >= 1514); + } +} + +#define DEBUG_RTL8139 +static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) +{ + RTL8139State *s = opaque; + + uint32_t packet_header = 0; + + uint8_t buf1[60]; + static const uint8_t broadcast_macaddr[6] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: received len=%d\n", size); +#endif + + printf("clock enabled %d\n", s->clock_enabled); + /* test if board clock is stopped */ + if (!s->clock_enabled) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: stopped ==========================\n"); +#endif + return; + } + + /* first check if receiver is enabled */ + + if (!rtl8139_receiver_enabled(s)) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: receiver disabled ================\n"); +#endif + return; + } + + /* XXX: check this */ + if (s->RxConfig & AcceptAllPhys) { + /* promiscuous: receive all */ +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: packet received in promiscuous mode\n"); +#endif + + } else { + if (!memcmp(buf, broadcast_macaddr, 6)) { + /* broadcast address */ + if (!(s->RxConfig & AcceptBroadcast)) + { +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: broadcast packet rejected\n"); +#endif + return; + } + + packet_header |= RxBroadcast; + +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: broadcast packet received\n"); +#endif + } else if (buf[0] & 0x01) { + /* multicast */ + if (!(s->RxConfig & AcceptMulticast)) + { +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: multicast packet rejected\n"); +#endif + return; + } + + int mcast_idx = compute_mcast_idx(buf); + + if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) + { +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: multicast address mismatch\n"); +#endif + return; + } + + packet_header |= RxMulticast; + +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: multicast packet received\n"); +#endif + } else if (s->phys[0] == buf[0] && + s->phys[1] == buf[1] && + s->phys[2] == buf[2] && + s->phys[3] == buf[3] && + s->phys[4] == buf[4] && + s->phys[5] == buf[5]) { + /* match */ + if (!(s->RxConfig & AcceptMyPhys)) + { +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: rejecting physical address matching packet\n"); +#endif + return; + } + + packet_header |= RxPhysical; + +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: physical address matching packet received\n"); +#endif + + } else { + +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: unknown packet\n"); +#endif + 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; + } + + if (rtl8139_cp_receiver_enabled(s)) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: in C+ Rx mode ================\n"); +#endif + + /* begin C+ receiver mode */ + +/* w0 ownership flag */ +#define CP_RX_OWN (1<<31) +/* w0 end of ring flag */ +#define CP_RX_EOR (1<<30) +/* w0 bits 0...12 : buffer size */ +#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1) +/* w1 tag available flag */ +#define CP_RX_TAVA (1<<16) +/* w1 bits 0...15 : VLAN tag */ +#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1) +/* w2 low 32bit of Rx buffer ptr */ +/* w3 high 32bit of Rx buffer ptr */ + + int descriptor = s->currCPlusRxDesc; + target_phys_addr_t cplus_rx_ring_desc; + + cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI); + cplus_rx_ring_desc += 16 * descriptor; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = 0x%8lx\n", + descriptor, s->RxRingAddrHI, s->RxRingAddrLO, cplus_rx_ring_desc); +#endif + + uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI; + + cpu_physical_memory_rw(s->cpu, cplus_rx_ring_desc, (uint8_t *)&val, 4, MEM_READ); + if (s->cpu->byte_order == EMUL_BIG_ENDIAN) + rxdw0 = be32_to_cpu(val); + else + rxdw0 = le32_to_cpu(val); + cpu_physical_memory_rw(s->cpu, cplus_rx_ring_desc+4, (uint8_t *)&val, 4, MEM_READ); + if (s->cpu->byte_order == EMUL_BIG_ENDIAN) + rxdw1 = be32_to_cpu(val); + else + rxdw1 = le32_to_cpu(val); + cpu_physical_memory_rw(s->cpu, cplus_rx_ring_desc+8, (uint8_t *)&val, 4, MEM_READ); + if (s->cpu->byte_order == EMUL_BIG_ENDIAN) + rxbufLO = be32_to_cpu(val); + else + rxbufLO = le32_to_cpu(val); + cpu_physical_memory_rw(s->cpu, cplus_rx_ring_desc+12, (uint8_t *)&val, 4, MEM_READ); + if (s->cpu->byte_order == EMUL_BIG_ENDIAN) + rxbufHI = be32_to_cpu(val); + else + rxbufHI = le32_to_cpu(val); + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", + descriptor, + rxdw0, rxdw1, rxbufLO, rxbufHI); +#endif + + if (!(rxdw0 & CP_RX_OWN)) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor); +#endif + s->IntrStatus |= RxOverflow; + ++s->RxMissed; + rtl8139_update_irq(s); + return; + } + + uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK; + + if (size+4 > rx_space) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n", + descriptor, rx_space, size); +#endif + s->IntrStatus |= RxOverflow; + ++s->RxMissed; + rtl8139_update_irq(s); + return; + } + + target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI); + + /* receive/copy to target memory */ + cpu_physical_memory_rw(s->cpu, rx_addr, buf, size , MEM_WRITE); + + /* write checksum */ +#if defined (RTL8139_CALCULATE_RXCRC) + val = cpu_to_le32(crc32(~0, buf, size)); + if (s->cpu->byte_order == EMUL_BIG_ENDIAN) + val = cpu_to_be32(val); +#else + val = 0; +#endif + cpu_physical_memory_rw(s->cpu, rx_addr+size, (uint8_t *)&val, 4, MEM_WRITE); + +/* first segment of received packet flag */ +#define CP_RX_STATUS_FS (1<<29) +/* last segment of received packet flag */ +#define CP_RX_STATUS_LS (1<<28) +/* multicast packet flag */ +#define CP_RX_STATUS_MAR (1<<26) +/* physical-matching packet flag */ +#define CP_RX_STATUS_PAM (1<<25) +/* broadcast packet flag */ +#define CP_RX_STATUS_BAR (1<<24) +/* runt packet flag */ +#define CP_RX_STATUS_RUNT (1<<19) +/* crc error flag */ +#define CP_RX_STATUS_CRC (1<<18) +/* IP checksum error flag */ +#define CP_RX_STATUS_IPF (1<<15) +/* UDP checksum error flag */ +#define CP_RX_STATUS_UDPF (1<<14) +/* TCP checksum error flag */ +#define CP_RX_STATUS_TCPF (1<<13) + + /* transfer ownership to target */ + rxdw0 &= ~CP_RX_OWN; + + /* set first segment bit */ + rxdw0 |= CP_RX_STATUS_FS; + + /* set last segment bit */ + rxdw0 |= CP_RX_STATUS_LS; + + /* set received packet type flags */ + if (packet_header & RxBroadcast) + rxdw0 |= CP_RX_STATUS_BAR; + if (packet_header & RxMulticast) + rxdw0 |= CP_RX_STATUS_MAR; + if (packet_header & RxPhysical) + rxdw0 |= CP_RX_STATUS_PAM; + + /* set received size */ + rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK; + rxdw0 |= (size+4); + + /* reset VLAN tag flag */ + rxdw1 &= ~CP_RX_TAVA; + + /* update ring data */ + val = cpu_to_le32(rxdw0); + if (s->cpu->byte_order == EMUL_BIG_ENDIAN) + val = cpu_to_be32(val); + cpu_physical_memory_rw(s->cpu, cplus_rx_ring_desc, (uint8_t *)&val, 4, MEM_WRITE); + val = cpu_to_le32(rxdw1); + if (s->cpu->byte_order == EMUL_BIG_ENDIAN) + val = cpu_to_be32(val); + cpu_physical_memory_rw(s->cpu, cplus_rx_ring_desc+4, (uint8_t *)&val, 4, MEM_WRITE); + + /* seek to next Rx descriptor */ + if (rxdw0 & CP_RX_EOR) + { + s->currCPlusRxDesc = 0; + } + else + { + ++s->currCPlusRxDesc; + } + +#if defined(DEBUG_RTL8139) + printf("RTL8139: done C+ Rx mode ----------------\n"); +#endif + + } + else + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: in ring Rx mode ================\n"); +#endif + /* begin ring receiver mode */ + int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize); + + /* if receiver buffer is empty then avail == 0 */ + + if (avail != 0 && size + 8 >= avail) + { +#if defined(DEBUG_RTL8139) + printf("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8); +#endif + s->IntrStatus |= RxOverflow; + ++s->RxMissed; + rtl8139_update_irq(s); + return; + } + + packet_header |= RxStatusOK; + + packet_header |= (((size+4) << 16) & 0xffff0000); + + /* write header */ + uint32_t val = cpu_to_le32(packet_header); + if (s->cpu->byte_order == EMUL_BIG_ENDIAN) + val = cpu_to_be32(val); + + rtl8139_write_buffer(s, (uint8_t *)&val, 4); + + rtl8139_write_buffer(s, buf, size); + + /* write checksum */ +#if defined (RTL8139_CALCULATE_RXCRC) + val = cpu_to_le32(crc32(~0, buf, size)); + if (s->cpu->byte_order == EMUL_BIG_ENDIAN) + val = cpu_to_be32(val); +#else + val = 0; +#endif + + rtl8139_write_buffer(s, (uint8_t *)&val, 4); + + /* correct buffer write pointer */ + s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize); + + /* now we can signal we have received something */ + +#if defined(DEBUG_RTL8139) + printf(" received: rx buffer length %d head 0x%04x read 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr); +#endif + + } + + s->IntrStatus |= RxOK; + rtl8139_update_irq(s); +} +#undef DEBUG_RTL8139 + +static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) +{ + s->RxBufferSize = bufferSize; + s->RxBufPtr = 0; + s->RxBufAddr = 0; +} + +static void rtl8139_reset(RTL8139State *s) +{ + int i; + + /* restore MAC address */ + memcpy(s->phys, s->macaddr, 6); + + /* reset interrupt mask */ + s->IntrStatus = 0; + s->IntrMask = 0; + + rtl8139_update_irq(s); + + /* prepare eeprom */ + s->eeprom.contents[0] = 0x8129; + memcpy(&s->eeprom.contents[7], s->macaddr, 6); + + /* mark all status registers as owned by host */ + for (i = 0; i < 4; ++i) + { + s->TxStatus[i] = TxHostOwns; + } + + s->currTxDesc = 0; + s->currCPlusRxDesc = 0; + s->currCPlusTxDesc = 0; + + s->RxRingAddrLO = 0; + s->RxRingAddrHI = 0; + + s->RxBuf = 0; + + rtl8139_reset_rxring(s, 8192); + + /* ACK the reset */ + s->TxConfig = 0; + +#if 0 +// s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139 HasHltClk + s->clock_enabled = 0; +#else + s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 0, 0); // RTL-8139C HasLWake + s->clock_enabled = 1; +#endif + + s->bChipCmdState = CmdReset; /* RxBufEmpty bit is calculated on read from ChipCmd */; + + /* set initial state data */ + s->Config0 = 0x0; /* No boot ROM */ + s->Config1 = 0xC; /* IO mapped and MEM mapped registers available */ + s->Config3 = 0x1; /* fast back-to-back compatible */ + s->Config5 = 0x0; + + s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD; + + s->CpCmd = 0x0; /* reset C+ mode */ + +// s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation +// s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex + s->BasicModeCtrl = 0x1000; // autonegotiation + + s->BasicModeStatus = 0x7809; + //s->BasicModeStatus |= 0x0040; /* UTP medium */ + s->BasicModeStatus |= 0x0020; /* autonegotiation completed */ + s->BasicModeStatus |= 0x0004; /* link is up */ + + s->NWayAdvert = 0x05e1; /* all modes, full duplex */ + s->NWayLPAR = 0x05e1; /* all modes, full duplex */ + s->NWayExpansion = 0x0001; /* autonegotiation supported */ +} + +static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) +{ + val &= 0xff; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: ChipCmd write val=0x%08x\n", val); +#endif + + if (val & CmdReset) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: ChipCmd reset\n"); +#endif + rtl8139_reset(s); + } + if (val & CmdRxEnb) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: ChipCmd enable receiver\n"); +#endif + } + if (val & CmdTxEnb) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: ChipCmd enable transmitter\n"); +#endif + } + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0xe3, s->bChipCmdState); + + /* Deassert reset pin before next read */ + val &= ~CmdReset; + + s->bChipCmdState = val; +} + +static int rtl8139_RxBufferEmpty(RTL8139State *s) +{ + int unread = MOD2(s->RxBufferSize + s->RxBufAddr - s->RxBufPtr, s->RxBufferSize); + + if (unread != 0) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: receiver buffer data available 0x%04x\n", unread); +#endif + return 0; + } + +#ifdef DEBUG_RTL8139 + printf("RTL8139: receiver buffer is empty\n"); +#endif + + return 1; +} + +static uint32_t rtl8139_ChipCmd_read(RTL8139State *s) +{ + uint32_t ret = s->bChipCmdState; + + if (rtl8139_RxBufferEmpty(s))