URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [tags/] [nog_patch_47/] [or1ksim/] [cpu/] [common/] [abstract.c] - Rev 494
Go to most recent revision | Compare with Previous | Blame | View Log
/* abstract.c -- Abstract entities Copyright (C) 1999 Damjan Lampret, lampret@opencores.org This file is part of OpenRISC 1000 Architectural Simulator. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Abstract memory and routines that go with this. I need to add all sorts of other abstract entities. Currently we have only memory. */ #include <stdlib.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include "config.h" #include "sim-config.h" #include "parse.h" #include "abstract.h" #include "labels.h" #include "arch.h" #include "execute.h" #include "sprs.h" #include "stats.h" #include "except.h" #include "debug_unit.h" #include "opcode/or32.h" extern unsigned long reg[]; extern char *disassembled; /* This is an abstract+physical memory array rather than only physical memory array */ static struct mem_entry *simmem; /* Pointer to memory area descriptions that are assigned to individual peripheral devices. */ struct dev_memarea *dev_list; /* Temporary variable to increase speed. */ struct dev_memarea *cur_area; /* It returns physical address. */ inline unsigned long translate_vrt_to_phy_add(unsigned long virtaddr, int write_access) { if (config.ic.tagtype == CT_NONE) return virtaddr; else if (config.ic.tagtype == CT_VIRTUAL) { return immu_translate(virtaddr, write_access); } else if (config.dc.tagtype == CT_PHYSICAL) { unsigned long phyaddr = immu_translate(virtaddr, write_access); return phyaddr; } else { printf("INTERNAL ERROR: Unknown insn cache type.\n"); cont_run = 0; } return -1; } /* Calls IMMU translation routines before simulating insn cache for virtually indexed insn cache or after simulating insn cache for physically indexed insn cache. It returns physical address. */ unsigned long simulate_ic_mmu_fetch(unsigned long virtaddr) { unsigned long phyaddr; if ((phyaddr = translate_vrt_to_phy_add(virtaddr, 0)) != -1) { ic_simulate_fetch(phyaddr); return phyaddr; } else { printf("INTERNAL ERROR: Unknown insn cache type.\n"); cont_run = 0; } return -1; } /* Calls DMMU translation routines (load cycles) before simulating data cache for virtually indexed data cache or after simulating data cache for physically indexed data cache. It returns physical address. */ unsigned long simulate_dc_mmu_load(unsigned long virtaddr) { if (config.dc.tagtype == CT_NONE) return virtaddr; else if (config.dc.tagtype == CT_VIRTUAL) { dc_simulate_read(virtaddr); return dmmu_translate(virtaddr, 0); } else if (config.dc.tagtype == CT_PHYSICAL) { unsigned long phyaddr = dmmu_translate(virtaddr, 0); dc_simulate_read(phyaddr); return phyaddr; } else { printf("INTERNAL ERROR: Unknown data cache type.\n"); cont_run = 0; } return -1; } /* Calls DMMU translation routines (store cycles) before simulating data cache for virtually indexed data cache or after simulating data cache for physically indexed data cache. It returns physical address. */ unsigned long simulate_dc_mmu_store(unsigned long virtaddr) { if (config.dc.tagtype == CT_NONE) return virtaddr; else if (config.dc.tagtype == CT_VIRTUAL) { dc_simulate_write(virtaddr); return dmmu_translate(virtaddr, 1); } else if (config.dc.tagtype == CT_PHYSICAL) { unsigned long phyaddr = dmmu_translate(virtaddr, 1); dc_simulate_write(phyaddr); return phyaddr; } else { printf("INTERNAL ERROR: Unknown data cache type.\n"); cont_run = 0; } return -1; } /* Calculates bit mask to fit the data */ unsigned long bit_mask (unsigned long data) { int i = 0; data--; while (data >> i) data |= 1 << i++; return data; } /* Register read and write function for a memory area. addr is inside the area, if addr & addr_mask == addr_compare (used also by peripheral devices like 16450 UART etc.) */ void register_memoryarea_mask(unsigned long addr_mask, unsigned long addr_compare, unsigned long size, unsigned granularity, unsigned long (readfunc)(unsigned long), void (writefunc)(unsigned long, unsigned long)) { struct dev_memarea **pptmp; unsigned long size_mask = bit_mask (size); int found_error = 0; addr_compare &= addr_mask; debug(5, "addr & %08x == %08x to %08x, size %08x, gran %iB\n", addr_mask, addr_compare, addr_compare | bit_mask (size), size, granularity); /* Go to the end of the list. */ for(pptmp = &dev_list; *pptmp; pptmp = &(*pptmp)->next) if ((addr_compare >= (*pptmp)->addr_compare) && (addr_compare < (*pptmp)->addr_compare + (*pptmp)->size) || (addr_compare + size > (*pptmp)->addr_compare) && (addr_compare < (*pptmp)->addr_compare + (*pptmp)->size)) { if (!found_error) { fprintf (stderr, "ERROR: Overlapping memory area(s):\n"); fprintf (stderr, "\taddr & %08x == %08x to %08x, size %08x, gran %iB\n", addr_mask, addr_compare, addr_compare | bit_mask (size), size, granularity); } found_error = 1; fprintf (stderr, "and\taddr & %08x == %08x to %08x, size %08x, gran %iB\n", (*pptmp)->addr_mask, (*pptmp)->addr_compare, (*pptmp)->addr_compare | (*pptmp)->size_mask, (*pptmp)->size, (*pptmp)->granularity); } if (found_error) exit (-1); cur_area = *pptmp = (struct dev_memarea *)malloc(sizeof(struct dev_memarea)); (*pptmp)->addr_mask = addr_mask; (*pptmp)->addr_compare = addr_compare; (*pptmp)->size = size; (*pptmp)->size_mask = size_mask; (*pptmp)->granularity = granularity; (*pptmp)->readfunc = readfunc; (*pptmp)->writefunc = writefunc; (*pptmp)->log = 0; (*pptmp)->next = NULL; } /* Register read and write function for a memory area. Memory areas should be aligned. Memory area is rounded up to fit the nearest 2^n aligment. (used also by peripheral devices like 16450 UART etc.) */ void register_memoryarea(unsigned long addr, unsigned long size, unsigned granularity, unsigned long (readfunc)(unsigned long), void (writefunc)(unsigned long, unsigned long)) { unsigned long size_mask = bit_mask (size); unsigned long addr_mask = ~size_mask; register_memoryarea_mask (addr_mask, addr & addr_mask, size_mask + 1, granularity, readfunc, writefunc); } /* Check if access is to registered area of memory. */ struct dev_memarea *verify_memoryarea(unsigned long addr) { struct dev_memarea *ptmp; /* Check list of registered devices. */ for(ptmp = dev_list; ptmp; ptmp = ptmp->next) if ((addr & ptmp->addr_mask) == ptmp->addr_compare) return cur_area = ptmp; return cur_area = NULL; } /* Returns 32-bit values from mem array. Big endian version. */ unsigned long read_mem(unsigned long memaddr,int* breakpoint) { unsigned long temp; struct dev_memarea *dev; slp_checkaccess(memaddr, SLP_MEMREAD); if (DEBUG_ENABLED) *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */ temp = evalsim_mem32(memaddr); if (DEBUG_ENABLED) *breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */ return temp; } /* Returns 32-bit values from mem array. Big endian version. */ unsigned long eval_mem32(unsigned long memaddr,int* breakpoint) { unsigned long temp; struct dev_memarea *dev; slp_checkaccess(memaddr, SLP_MEMREAD); memaddr = simulate_dc_mmu_load(memaddr); if (pending.valid) return 0; if (DEBUG_ENABLED) *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */ temp = evalsim_mem32(memaddr); if (DEBUG_ENABLED) *breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */ return temp; } /* Returns 32-bit values from mem array. Big endian version. */ unsigned long eval_insn(unsigned long memaddr,int* breakpoint) { unsigned long temp; struct dev_memarea *dev; slp_checkaccess(memaddr, SLP_MEMREAD); // memaddr = simulate_ic_mmu_fetch(memaddr); ic_simulate_fetch(memaddr); if (DEBUG_ENABLED) *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */ temp = evalsim_mem32(memaddr); if (DEBUG_ENABLED) *breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */ return temp; } unsigned long evalsim_mem32(unsigned long memaddr) { unsigned long temp; if (verify_memoryarea(memaddr)) { switch(cur_area->granularity) { case 1: temp = cur_area->readfunc(memaddr) << 24; temp |= cur_area->readfunc(memaddr + 1) << 16; temp |= cur_area->readfunc(memaddr + 2) << 8; temp |= cur_area->readfunc(memaddr + 3); break; case 2: temp = cur_area->readfunc(memaddr) << 16; temp |= cur_area->readfunc(memaddr + 2); break; case 4: temp = cur_area->readfunc(memaddr); break; } if (cur_area->log) fprintf (cur_area->log, "[%08x] -> read %08x\n", memaddr, temp); } else { printf("EXCEPTION: read out of memory (32-bit access to %.8lx)\n", memaddr); except_handle(EXCEPT_BUSERR, memaddr); temp = 0; } return temp; } /* Returns 16-bit values from mem array. Big endian version. */ unsigned short eval_mem16(unsigned long memaddr,int* breakpoint) { unsigned short temp; memaddr = simulate_dc_mmu_load(memaddr); if (pending.valid) return 0; if (DEBUG_ENABLED) *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */ temp = evalsim_mem16(memaddr); if (DEBUG_ENABLED) *breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */ return temp; } unsigned short evalsim_mem16(unsigned long memaddr) { unsigned short temp; if (verify_memoryarea(memaddr)) { switch(cur_area->granularity) { case 1: temp = cur_area->readfunc(memaddr) << 8; temp |= cur_area->readfunc(memaddr + 1); break; case 2: temp = cur_area->readfunc(memaddr); break; case 4: printf("EXCEPTION: read 16-bit value from 32-bit region (address 0x%08lX)\n", cur_area->granularity * 8, memaddr); cont_run = 0; break; } if (cur_area->log) fprintf (cur_area->log, "[%08x] -> read %08x\n", memaddr, temp); } else { printf("EXCEPTION: read out of memory (16-bit access to %.8lx)\n", memaddr); except_handle(EXCEPT_BUSERR, memaddr); temp = 0; } return temp; } /* Returns 8-bit values from mem array. */ unsigned char eval_mem8(unsigned long memaddr,int* breakpoint) { unsigned char temp; memaddr = simulate_dc_mmu_load(memaddr); if (pending.valid) return 0; if (DEBUG_ENABLED) *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */ temp = evalsim_mem8(memaddr); if (DEBUG_ENABLED) *breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */ return temp; } unsigned char evalsim_mem8(unsigned long memaddr) { unsigned char temp; if (verify_memoryarea(memaddr)) { switch(cur_area->granularity) { case 1: temp = cur_area->readfunc(memaddr); break; case 2: case 4: printf("EXCEPTION: read 8-bit value from %u-bit region (address 0x%08lX)\n", cur_area->granularity * 8, memaddr); cont_run = 0; break; } if (cur_area->log) fprintf (cur_area->log, "[%08x] -> read %08x\n", memaddr, temp); } else { printf("EXCEPTION: read out of memory (8-bit access to %.8lx)\n", memaddr); except_handle(EXCEPT_BUSERR, memaddr); temp = 0; } return temp; } /* Set mem, 32-bit. Big endian version. */ void set_mem32(unsigned long memaddr, unsigned long value,int* breakpoint) { slp_checkaccess(memaddr, SLP_MEMWRITE); memaddr = simulate_dc_mmu_store(memaddr); /* If we produced exception don't set anything */ if (pending.valid == 1) return; if (DEBUG_ENABLED) { *breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr); /* 28/05/01 CZ */ *breakpoint += CheckDebugUnit(DebugStoreData,value); } setsim_mem32(memaddr, value); } void setsim_mem32(unsigned long memaddr, unsigned long value) { struct dev_memarea *dev; if (verify_memoryarea(memaddr)) { if (cur_area->log) fprintf (cur_area->log, "[%08x] -> write %08x\n", memaddr, value); switch(cur_area->granularity) { case 1: cur_area->writefunc(memaddr , (value >> 24) & 0xFF); cur_area->writefunc(memaddr + 1, (value >> 16) & 0xFF); cur_area->writefunc(memaddr + 2, (value >> 8) & 0xFF); cur_area->writefunc(memaddr + 3, (value ) & 0xFF); break; case 2: cur_area->writefunc(memaddr, (value >> 16) & 0xFFFF); cur_area->writefunc(memaddr + 2, value & 0xFFFF); break; case 4: cur_area->writefunc(memaddr, value); break; } } else { printf("EXCEPTION: write out of memory (32-bit access to %.8lx)\n", memaddr); except_handle(EXCEPT_BUSERR, memaddr); } } /* Set mem, 16-bit. Big endian version. */ void set_mem16(unsigned long memaddr, unsigned short value,int* breakpoint) { memaddr = simulate_dc_mmu_store(memaddr); /* If we produced exception don't set anything */ if (pending.valid == 1) return; if (DEBUG_ENABLED) { *breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr); /* 28/05/01 CZ */ *breakpoint += CheckDebugUnit(DebugStoreData,value); } setsim_mem16(memaddr, value); } void setsim_mem16(unsigned long memaddr, unsigned short value) { if (verify_memoryarea(memaddr)) { if (cur_area->log) fprintf (cur_area->log, "[%08x] -> write %08x\n", memaddr, value); switch(cur_area->granularity) { case 1: cur_area->writefunc(memaddr, (value >> 8) & 0xFF); cur_area->writefunc(memaddr + 1, value & 0xFF); break; case 2: cur_area->writefunc(memaddr, value & 0xFFFF); break; case 4: printf("EXCEPTION: write 16-bit value to 32-bit region (address 0x%08lX)\n", memaddr); cont_run = 0; break; } } else { printf("EXCEPTION: write out of memory (16-bit access to %.8lx)\n", memaddr); except_handle(EXCEPT_BUSERR, memaddr); } } /* Set mem, 8-bit. */ void set_mem8(unsigned long memaddr, unsigned char value,int* breakpoint) { memaddr = simulate_dc_mmu_store(memaddr); /* If we produced exception don't set anything */ if (pending.valid == 1) return; if (DEBUG_ENABLED) { *breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr); /* 28/05/01 CZ */ *breakpoint += CheckDebugUnit(DebugStoreData,value); } setsim_mem8(memaddr, value); } void setsim_mem8(unsigned long memaddr, unsigned char value) { if (verify_memoryarea(memaddr)) { if (cur_area->log) fprintf (cur_area->log, "[%08x] -> write %08x\n", memaddr, value); if (cur_area->granularity == 1) cur_area->writefunc(memaddr, value); else { printf("EXCEPTION: write 8-bit value to %u-bit region (address 0x%08lX)\n", cur_area->granularity * 8, memaddr); cont_run = 0; } } else { printf("EXCEPTION: write out of memory (8-bit access to %.8lx)\n", memaddr); except_handle(EXCEPT_BUSERR, memaddr); } } void dumpmemory(unsigned int from, unsigned int to, int disasm, int nl) { unsigned int i, j; struct label_entry *tmp; int breakpoint = 0; int ilen = disasm ? 4 : 16; for(i = from; i < to; i += ilen) { printf("%.8x: ", i); for (j = 0; j < ilen;) { int data = -1; if (!disasm) { tmp = NULL; if (verify_memoryarea(i+j)) { struct label_entry *entry; entry = get_label(i + j); if (entry) printf("(%s)", entry->name); printf("%02x ", data = evalsim_mem8(i+j)); } else printf("XX "); j++; } else { int breakpoint; unsigned int _insn = read_mem(i, &breakpoint); int index = insn_decode (_insn); int len = insn_len (index); tmp = NULL; if (verify_memoryarea(i+j)) { struct label_entry *entry; entry = get_label(i + j); if (entry) printf("(%s)", entry->name); printf(": %08x ", (unsigned long)_insn); if (index >= 0) { disassemble_insn (_insn); printf(" %s", disassembled); } else printf("<invalid>"); } else printf("XXXXXXXX"); j += len; } } if (nl) printf ("\n"); } } unsigned long simmem_read_byte(unsigned long addr) { return simmem[cur_area->misc + (addr & cur_area->size_mask)].data; } void simmem_write_byte(unsigned long addr, unsigned long value) { simmem[cur_area->misc + (addr & cur_area->size_mask)].data = (unsigned char)value; } unsigned long simmem_read_zero(unsigned long addr) { if (config.sim.verbose) fprintf (stderr, "WARNING: memory read from non-read memory area 0x%08x.\n", addr); return 0; } void simmem_write_null(unsigned long addr, unsigned long value) { if (config.sim.verbose) fprintf (stderr, "WARNING: memory write to 0x%08x, non-write memory area (value 0x%08x).\n", addr, value); } /* Initialize memory table from a config struct */ void init_memory_table () { unsigned long memory_needed = 0; /* If nothing was defined, use default memory block */ if (config.memory.nmemories) { int i; for (i = 0; i < config.memory.nmemories; i++) { unsigned long start = config.memory.table[i].baseaddr; unsigned long length = config.memory.table[i].size; char *type = config.memory.table[i].name; int rd = config.memory.table[i].delayr; int wd = config.memory.table[i].delayw; int ce = config.memory.table[i].ce; if (config.sim.verbose) debug (1, "%08X %08X (%i KB): %s (activated by CE%i; read delay = %icyc, write delay = %icyc)\n", start, length, length >> 10, type, ce, rd, wd); register_memoryarea(start, length, 1, &simmem_read_byte, &simmem_write_byte); cur_area->misc = memory_needed; cur_area->delayw = wd; cur_area->delayr = rd; if (config.memory.table[i].log[0] != '\0') { if ((cur_area->log = fopen (config.memory.table[i].log, "wt+")) == NULL) fprintf (stderr, "WARNING: Cannot open '%s'.\n", config.memory.table[i].log); } else cur_area->log = 0; memory_needed += cur_area->size; } printf ("\n"); } else { if (config.sim.verbose) fprintf (stderr, "WARNING: Memory not defined, assuming standard configuration.\n"); register_memoryarea(DEFAULT_MEMORY_START, DEFAULT_MEMORY_LEN, 1, &simmem_read_byte, &simmem_write_byte); memory_needed += cur_area->size; } simmem = (struct mem_entry *) malloc (sizeof (struct mem_entry) * memory_needed); if (!simmem) { fprintf (stderr, "Failed to allocate sim memory. Aborting\n"); exit (-1); } } /* Changes read/write memory in read/write only */ void lock_memory_table () { struct dev_memarea *ptmp; /* Check list of registered devices. */ for(ptmp = dev_list; ptmp; ptmp = ptmp->next) { if (ptmp->delayr < 0 && ptmp->readfunc == &simmem_read_byte) ptmp->readfunc = &simmem_read_zero; if (ptmp->delayw < 0 && ptmp->writefunc == &simmem_write_byte) ptmp->writefunc = &simmem_write_null; } } /* Closes files, etc. */ void done_memory_table () { struct dev_memarea *ptmp; /* Check list of registered devices. */ for(ptmp = dev_list; ptmp; ptmp = ptmp->next) { if (ptmp->log) fclose (ptmp->log); } } /* Displays current memory configuration */ void memory_table_status () { struct dev_memarea *ptmp; /* Check list of registered devices. */ for(ptmp = dev_list; ptmp; ptmp = ptmp->next) { printf ("addr & %08x == %08x to %08x, size %08x, gran %iB\n", ptmp->addr_mask, ptmp->addr_compare, ptmp->addr_compare | bit_mask (ptmp->size), ptmp->size, ptmp->granularity); printf ("\t"); if (ptmp->delayr >= 0) printf ("read delay = %i cycles, ", ptmp->delayr); else printf ("reads not possible, "); if (ptmp->delayw >= 0) printf ("write delay = %i cycles", ptmp->delayw); else printf ("writes not possible"); if (ptmp->log) printf (", (logged)\n"); else printf ("\n"); } } /* Outputs time in pretty form to dest string */ void generate_time_pretty (char *dest, long time_ps) { int exp3 = 0; if (time_ps) { while ((time_ps % 1000) == 0) { time_ps /= 1000; exp3++; } } sprintf (dest, "%i%cs", time_ps, "pnum"[exp3]); }
Go to most recent revision | Compare with Previous | Blame | View Log