URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 234 to Rev 235
- ↔ Reverse comparison
Rev 234 → Rev 235
/trunk/or1ksim/cpu/common/abstract.c
56,51 → 56,51
|
void dumpmemory(unsigned int from, unsigned int to, int disasm) |
{ |
unsigned int i, j; |
struct label_entry *tmp; |
int breakpoint = 0; |
int ilen = disasm ? 4 : 16; |
unsigned int i, j; |
struct label_entry *tmp; |
int breakpoint = 0; |
int ilen = disasm ? 4 : 16; |
|
for(i = from; i < to; i += ilen) { |
for (j = 0; j < ilen;) { |
int data = -1; |
if (!disasm) { |
tmp = NULL; |
if (verify_memoryarea(i+j)) { |
if (cur_area->getentry) |
tmp = cur_area->getentry(i+j)->label; |
|
for(; tmp; tmp = tmp->next) |
printf(" %s%s", tmp->name, LABELEND_CHAR); |
printf("%02x ", data = (unsigned char)cur_area->readfunc(i+j)); |
} else printf("XX "); |
j++; |
} else { |
int breakpoint; |
unsigned int _insn = eval_mem32(i, &breakpoint); |
int index = insn_decode (_insn); |
int len = insn_len (index); |
|
tmp = NULL; |
if (verify_memoryarea(i+j)) { |
if (cur_area->getentry) |
tmp = cur_area->getentry(i+j)->label; |
|
for(; tmp; tmp = tmp->next) |
printf(" %s%s", tmp->name, LABELEND_CHAR); |
printf("%.8x: ", i); |
for(i = from; i < to; i += ilen) { |
for (j = 0; j < ilen;) { |
int data = -1; |
if (!disasm) { |
tmp = NULL; |
if (verify_memoryarea(i+j)) { |
struct mem_entry *entry; |
if (cur_area->getentry && (entry = cur_area->getentry(i+j))) |
for(tmp = entry->label; tmp; tmp = tmp->next) |
printf(" %s%s", tmp->name, LABELEND_CHAR); |
printf("%02x ", data = evalsim_mem8(i+j)); |
} else printf("XX "); |
j++; |
} else { |
int breakpoint; |
unsigned int _insn = eval_mem32(i, &breakpoint); |
int index = insn_decode (_insn); |
int len = insn_len (index); |
|
tmp = NULL; |
if (verify_memoryarea(i+j)) { |
struct mem_entry *entry; |
if (cur_area->getentry && (entry = cur_area->getentry(i+j))) |
tmp = entry->label; |
|
for(; tmp; tmp = tmp->next) |
printf(" %s%s", tmp->name, LABELEND_CHAR); |
printf("%.8x: ", i); |
|
printf("%08x ", (unsigned char)_insn); |
if (index >= 0) { |
disassemble_insn (_insn); |
printf(" %s", disassembled); |
} else |
printf("<invalid>"); |
} else printf("XXXXXXXX"); |
j += len; |
} |
} |
} |
printf("%08x ", (unsigned char)_insn); |
if (index >= 0) { |
disassemble_insn (_insn); |
printf(" %s", disassembled); |
} else |
printf("<invalid>"); |
} else printf("XXXXXXXX"); |
j += len; |
} |
} |
} |
} |
|
/* Searches mem array for a particular label and returns label's address. |
109,7 → 109,7
unsigned long eval_label(char *label) |
{ |
int i; |
char *plus; |
char *plus; |
char *minus; |
int positive_offset = 0; |
int negative_offset = 0; |
123,24 → 123,24
*minus = '\0'; |
negative_offset = atoi(++minus); |
} |
for (cur_area = dev_list; cur_area; cur_area = cur_area->next) { |
for(i = 0; i < cur_area->size; i++) if (cur_area->getentry) { |
int mi = i + cur_area->start; |
struct mem_entry *entry = cur_area->getentry(mi); |
if (entry) { |
struct label_entry *tmp = entry->label; |
for(; tmp; tmp = tmp->next) |
if (strcmp(label, tmp->name) == 0) { |
debug("eval_label(%s) => 0x%x\n", label, i + positive_offset - negative_offset + cur_area->start); |
return i + positive_offset - negative_offset + cur_area->start; |
} |
} |
} |
} |
for (cur_area = dev_list; cur_area; cur_area = cur_area->next) { |
for(i = 0; i < cur_area->size; i++) if (cur_area->getentry) { |
int mi = i + cur_area->start; |
struct mem_entry *entry = cur_area->getentry(mi); |
if (entry) { |
struct label_entry *tmp = entry->label; |
for(; tmp; tmp = tmp->next) |
if (strcmp(label, tmp->name) == 0) { |
debug("eval_label(%s) => 0x%x\n", label, i + positive_offset - negative_offset + cur_area->start); |
return i + positive_offset - negative_offset + cur_area->start; |
} |
} |
} |
} |
|
printf("\nINTERNAL ERROR: undefined label %s\n", label); |
cont_run = 0; |
return 0; |
printf("\nINTERNAL ERROR: undefined label %s\n", label); |
cont_run = 0; |
return 0; |
} |
|
/* Calls IMMU translation routines before simulating insn |
152,26 → 152,26
if (config.ic.tagtype == NONE) |
return virtaddr; |
else |
if (config.ic.tagtype == VIRTUAL) { |
ic_simulate_fetch(virtaddr); |
return immu_translate(virtaddr); |
} |
else if (config.dc.tagtype == PHYSICAL) { |
unsigned long phyaddr = immu_translate(virtaddr); |
ic_simulate_fetch(phyaddr); |
return phyaddr; |
} |
else { |
printf("INTERNAL ERROR: Unknown insn cache type.\n"); |
cont_run = 0; |
} |
if (config.ic.tagtype == VIRTUAL) { |
ic_simulate_fetch(virtaddr); |
return immu_translate(virtaddr); |
} |
else if (config.dc.tagtype == PHYSICAL) { |
unsigned long phyaddr = immu_translate(virtaddr); |
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. */ |
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) |
{ |
178,17 → 178,17
if (config.dc.tagtype == NONE) |
return virtaddr; |
else |
if (config.dc.tagtype == VIRTUAL) { |
dc_simulate_read(virtaddr); |
return dmmu_translate(virtaddr); |
if (config.ic.tagtype == VIRTUAL) { |
ic_simulate_fetch(virtaddr); |
return immu_translate(virtaddr); |
} |
else if (config.dc.tagtype == PHYSICAL) { |
unsigned long phyaddr = dmmu_translate(virtaddr); |
dc_simulate_read(phyaddr); |
unsigned long phyaddr = immu_translate(virtaddr); |
ic_simulate_fetch(phyaddr); |
return phyaddr; |
} |
else { |
printf("INTERNAL ERROR: Unknown data cache type.\n"); |
printf("INTERNAL ERROR: Unknown insn cache type.\n"); |
cont_run = 0; |
} |
|
223,8 → 223,11
|
/* Register read and write function for a memory area (used by peripheral |
devices like 16450 UART etc.) */ |
void register_memoryarea(unsigned long start, unsigned long size, unsigned char (readfunc)(unsigned long), |
void (writefunc)(unsigned long, unsigned char), struct mem_entry *(getentry)(unsigned long)) |
void register_memoryarea(unsigned long start, unsigned long size, |
unsigned granularity, |
unsigned long (readfunc)(unsigned long), |
void (writefunc)(unsigned long, unsigned long), |
struct mem_entry *(getentry)(unsigned long)) |
{ |
struct dev_memarea **pptmp; |
|
235,6 → 238,7
(*pptmp)->start = start; |
(*pptmp)->size = size; |
(*pptmp)->end = start + size; |
(*pptmp)->granularity = granularity; |
(*pptmp)->readfunc = readfunc; |
(*pptmp)->writefunc = writefunc; |
(*pptmp)->getentry = getentry; |
251,7 → 255,7
/* Check list of registered devices. */ |
for(ptmp = dev_list; ptmp; ptmp = ptmp->next) |
if (addr >= ptmp->start && |
addr < (ptmp->end)) |
addr < (ptmp->end)) |
return cur_area = ptmp; |
return cur_area = NULL; |
} |
260,14 → 264,14
unsigned long eval_mem32(unsigned long memaddr,int* breakpoint) |
{ |
|
unsigned long temp; |
struct dev_memarea *dev; |
unsigned long temp; |
struct dev_memarea *dev; |
|
slp_checkaccess(memaddr, SLP_MEMREAD); |
memaddr = simulate_dc_mmu_load(memaddr); |
*breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */ |
temp = evalsim_mem32(memaddr); |
*breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */ |
slp_checkaccess(memaddr, SLP_MEMREAD); |
memaddr = simulate_dc_mmu_load(memaddr); |
*breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */ |
temp = evalsim_mem32(memaddr); |
*breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */ |
return temp; |
} |
|
276,10 → 280,21
unsigned long temp; |
|
if (verify_memoryarea(memaddr)) { |
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); |
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; |
} |
} else { |
printf("EXCEPTION: read out of memory (32-bit access to %.8lx)\n", memaddr); |
cont_run = 0; |
292,12 → 307,12
|
unsigned short eval_mem16(unsigned long memaddr,int* breakpoint) |
{ |
unsigned short temp; |
unsigned short temp; |
memaddr = simulate_dc_mmu_load(memaddr); |
*breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */ |
*breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */ |
|
temp = evalsim_mem16(memaddr); |
*breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */ |
*breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */ |
return temp; |
} |
|
306,8 → 321,19
unsigned short temp; |
|
if (verify_memoryarea(memaddr)) { |
temp = cur_area->readfunc(memaddr) << 8; |
temp |= cur_area->readfunc(memaddr + 1); |
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; |
} |
} else { |
printf("EXCEPTION: read out of memory (16-bit access to %.8lx)\n", memaddr); |
cont_run = 0; |
321,21 → 347,33
|
unsigned char eval_mem8(unsigned long memaddr,int* breakpoint) |
{ |
unsigned char temp; |
unsigned char temp; |
memaddr = simulate_dc_mmu_load(memaddr); |
*breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */ |
*breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */ |
|
temp = evalsim_mem8(memaddr); |
*breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */ |
*breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */ |
return temp; |
} |
|
unsigned char evalsim_mem8(unsigned long memaddr) |
{ |
unsigned char temp; |
unsigned char temp; |
|
if (verify_memoryarea(memaddr)) { |
temp = cur_area->readfunc(memaddr); |
switch(cur_area->granularity) { |
case 1: |
temp = cur_area->readfunc(memaddr); |
temp |= cur_area->readfunc(memaddr + 1) << 16; |
temp |= cur_area->readfunc(memaddr + 2) << 8; |
temp |= cur_area->readfunc(memaddr + 3); |
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; |
} |
} else { |
printf("EXCEPTION: read out of memory (8-bit access to %.8lx)\n", memaddr); |
cont_run = 0; |
348,15 → 386,15
|
void set_mem32(unsigned long memaddr, unsigned long value,int* breakpoint) |
{ |
slp_checkaccess(memaddr, SLP_MEMWRITE); |
memaddr = simulate_dc_mmu_store(memaddr); |
slp_checkaccess(memaddr, SLP_MEMWRITE); |
memaddr = simulate_dc_mmu_store(memaddr); |
|
*breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr); /* 28/05/01 CZ */ |
*breakpoint += CheckDebugUnit(DebugStoreData,value); |
*breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr); /* 28/05/01 CZ */ |
*breakpoint += CheckDebugUnit(DebugStoreData,value); |
|
setsim_mem32(memaddr, value); |
setsim_mem32(memaddr, value); |
|
return; |
return; |
} |
|
void setsim_mem32(unsigned long memaddr, unsigned long value) |
363,11 → 401,22
{ |
struct dev_memarea *dev; |
|
if (verify_memoryarea(memaddr)) { |
cur_area->writefunc(memaddr, value >> 24); |
cur_area->writefunc(memaddr + 1, (unsigned char)(value >> 16)); |
cur_area->writefunc(memaddr + 2, (unsigned char)(value >> 8)); |
cur_area->writefunc(memaddr + 3, (unsigned char)value); |
if (verify_memoryarea(memaddr)) { |
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); |
cont_run = 0; |
380,27 → 429,38
|
void set_mem16(unsigned long memaddr, unsigned short value,int* breakpoint) |
{ |
memaddr = simulate_dc_mmu_store(memaddr); |
memaddr = simulate_dc_mmu_store(memaddr); |
|
*breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr); /* 28/05/01 CZ */ |
*breakpoint += CheckDebugUnit(DebugStoreData,value); |
*breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr); /* 28/05/01 CZ */ |
*breakpoint += CheckDebugUnit(DebugStoreData,value); |
|
setsim_mem16(memaddr, value); |
setsim_mem16(memaddr, value); |
|
return; |
return; |
} |
|
void setsim_mem16(unsigned long memaddr, unsigned short value) |
{ |
if (verify_memoryarea(memaddr)) { |
cur_area->writefunc(memaddr, (unsigned char) (value >> 8)); |
cur_area->writefunc(memaddr + 1, (unsigned char)value); |
} else { |
printf("EXCEPTION: write out of memory (16-bit access to %.8lx)\n", memaddr); |
cont_run = 0; |
} |
if (verify_memoryarea(memaddr)) { |
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 >> 16) & 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); |
cont_run = 0; |
} |
|
return; |
return; |
} |
|
/* Set mem, 8-bit. */ |
407,20 → 467,25
|
void set_mem8(unsigned long memaddr, unsigned char value,int* breakpoint) |
{ |
memaddr = simulate_dc_mmu_store(memaddr); |
memaddr = simulate_dc_mmu_store(memaddr); |
|
*breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr); /* 28/05/01 CZ */ |
*breakpoint += CheckDebugUnit(DebugStoreData,value); |
*breakpoint += CheckDebugUnit(DebugStoreAddress,memaddr); /* 28/05/01 CZ */ |
*breakpoint += CheckDebugUnit(DebugStoreData,value); |
|
setsim_mem8(memaddr, value); |
setsim_mem8(memaddr, value); |
|
return; |
return; |
} |
|
void setsim_mem8(unsigned long memaddr, unsigned char value) |
{ |
if (verify_memoryarea(memaddr)) { |
cur_area->writefunc(memaddr, (unsigned char)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); |
cont_run = 0; |
429,44 → 494,44
return; |
} |
|
unsigned char simmem_readfunc(unsigned long addr) { |
return simmem[cur_area->misc + addr - cur_area->start].data; |
unsigned long simmem_read_byte(unsigned long addr) { |
return simmem[cur_area->misc + addr - cur_area->start].data; |
} |
|
void simmem_writefunc(unsigned long addr, unsigned char value) { |
simmem[cur_area->misc + addr - cur_area->start].data = value; |
void simmem_write_byte(unsigned long addr, unsigned long value) { |
simmem[cur_area->misc + addr - cur_area->start].data = (unsigned char)value; |
} |
|
struct mem_entry * simmem_getentry(unsigned long addr) { |
return &simmem[cur_area->misc + addr - cur_area->start]; |
return &simmem[cur_area->misc + addr - cur_area->start]; |
} |
|
void sim_read_memory_table (char *filename) |
{ |
FILE *f; |
unsigned long memory_needed = 0; |
char *home = getenv("HOME"); |
char ctmp[256]; |
int local = 1; |
sprintf(ctmp, "%s/.or1k/%s", home, filename); |
if ((f = fopen (filename, "rt")) != NULL |
|| home != NULL && !(local = 0) && (f = fopen (ctmp, "rt")) != NULL) { |
unsigned long start, length; |
char type[100]; |
printf ("Reading memory table from '%s':\n", local ? filename : ctmp); |
while (fscanf (f, "%08x %08x %s\n", &start, &length, &type) == 3) { |
printf ("%08X %08X (%i KB): %s\n", start, length, length >> 10, type); |
register_memoryarea(start, length, &simmem_readfunc, &simmem_writefunc, &simmem_getentry); |
cur_area->misc = memory_needed; |
memory_needed += DEFAULT_MEMORY_LEN; |
} |
fclose (f); |
printf ("\n"); |
} else { |
fprintf (stderr, "Cannot read memory table from '%s',\nneither '%s', assuming standard configuration.\n", filename, ctmp); |
register_memoryarea(DEFAULT_MEMORY_START, DEFAULT_MEMORY_LEN, &simmem_readfunc, &simmem_writefunc, &simmem_getentry); |
memory_needed += DEFAULT_MEMORY_LEN; |
} |
|
simmem = (struct mem_entry *) malloc (sizeof (struct mem_entry) * memory_needed); |
FILE *f; |
unsigned long memory_needed = 0; |
char *home = getenv("HOME"); |
char ctmp[256]; |
int local = 1; |
sprintf(ctmp, "%s/.or1k/%s", home, filename); |
if ((f = fopen (filename, "rt")) != NULL |
|| home != NULL && !(local = 0) && (f = fopen (ctmp, "rt")) != NULL) { |
unsigned long start, length; |
char type[100]; |
printf ("Reading memory table from '%s':\n", local ? filename : ctmp); |
while (fscanf (f, "%08x %08x %s\n", &start, &length, &type) == 3) { |
printf ("%08X %08X (%i KB): %s\n", start, length, length >> 10, type); |
register_memoryarea(start, length, 1, &simmem_read_byte, &simmem_write_byte, &simmem_getentry); |
cur_area->misc = memory_needed; |
memory_needed += DEFAULT_MEMORY_LEN; |
} |
fclose (f); |
printf ("\n"); |
} else { |
fprintf (stderr, "Cannot read memory table from '%s',\nneither '%s', assuming standard configuration.\n", filename, ctmp); |
register_memoryarea(DEFAULT_MEMORY_START, DEFAULT_MEMORY_LEN, 1, &simmem_read_byte, &simmem_write_byte, &simmem_getentry); |
memory_needed += DEFAULT_MEMORY_LEN; |
} |
|
simmem = (struct mem_entry *) malloc (sizeof (struct mem_entry) * memory_needed); |
} |
/trunk/or1ksim/cpu/common/abstract.h
60,8 → 60,9
unsigned long start; |
unsigned long end; |
unsigned long size; |
unsigned char (*readfunc)(unsigned long); |
void (*writefunc)(unsigned long, unsigned char); |
unsigned long granularity; /* how many bytes read/write accepts: 1/2/4 */ |
unsigned long (*readfunc)(unsigned long); |
void (*writefunc)(unsigned long, unsigned long); |
struct mem_entry* (*getentry) (unsigned long); |
/* private data */ |
unsigned long misc; |
91,8 → 92,11
|
/* Register read and write function for a memory area (used by peripheral |
devices like 16450 UART etc.) */ |
void register_memoryarea(unsigned long start, unsigned long size, unsigned char (readfunc)(unsigned long), |
void (writefunc)(unsigned long, unsigned char), struct mem_entry *(getentry)(unsigned long)); |
void register_memoryarea(unsigned long start, unsigned long size, |
unsigned granularity, |
unsigned long (readfunc)(unsigned long), |
void (writefunc)(unsigned long, unsigned long), |
struct mem_entry *(getentry)(unsigned long)); |
/* Check if access is to registered area of memory. */ |
struct dev_memarea *verify_memoryarea(unsigned long addr); |
/* Temporary variable to increase speed. */ |
/trunk/or1ksim/peripheral/16450.c
31,6 → 31,7
#include <stdio.h> |
#include <string.h> |
|
#include "abstract.h" |
#include "16450.h" |
#include "sim-config.h" |
#include "pic.h" |
61,11 → 62,11
} |
|
/* Set a specific UART register with value. */ |
void uart_write(unsigned long addr, unsigned long value) |
void uart_write8(unsigned long addr, unsigned char value) |
{ |
int chipsel; |
|
debug("uart_write(%x,%x)\n", addr, (value >> 24)); |
debug("uart_write8(%x,%02x)\n", addr, (unsigned)value); |
|
for(chipsel = 0; chipsel < NR_UARTS; chipsel++) |
if ((addr & ~(UART_ADDR_SPACE-1)) == uarts[chipsel].baseaddr) |
76,13 → 77,13
if (uarts[chipsel].regs.lcr & UART_LCR_DLAB) { |
switch (addr % UART_ADDR_SPACE) { |
case UART_DLL: |
uarts[chipsel].regs.dll = (value >> 24); |
uarts[chipsel].regs.dll = value; |
break; |
case UART_DLH: |
uarts[chipsel].regs.dlh = (value >> 24); |
uarts[chipsel].regs.dlh = value; |
break; |
case UART_LCR: |
uarts[chipsel].regs.lcr = (value >> 24) & UART_VALID_LCR; |
uarts[chipsel].regs.lcr = value & UART_VALID_LCR; |
break; |
default: |
debug("write out of range (addr %x, DLAB=1)\n", addr); |
93,7 → 94,7
|
switch (addr % UART_ADDR_SPACE) { |
case UART_TXBUF: |
uarts[chipsel].regs.txbuf = (value >> 24); |
uarts[chipsel].regs.txbuf = value; |
uarts[chipsel].istat.txbuf = FULL; |
uarts[chipsel].regs.lsr &= ~UART_LSR_TXBUFE; |
uarts[chipsel].regs.lsr &= ~UART_LSR_TXSERE; |
100,16 → 101,16
uarts[chipsel].istat.thre_int = 0; |
break; |
case UART_IER: |
uarts[chipsel].regs.ier = (value >> 24) & UART_VALID_IER; |
uarts[chipsel].regs.ier = value & UART_VALID_IER; |
break; |
case UART_LCR: |
uarts[chipsel].regs.lcr = (value >> 24) & UART_VALID_LCR; |
uarts[chipsel].regs.lcr = value & UART_VALID_LCR; |
break; |
case UART_MCR: |
uarts[chipsel].regs.mcr = (value >> 24) & UART_VALID_MCR; |
uarts[chipsel].regs.mcr = value & UART_VALID_MCR; |
break; |
case UART_SCR: |
uarts[chipsel].regs.scr = (value >> 24); |
uarts[chipsel].regs.scr = value; |
break; |
default: |
debug("write out of range (addr %x)\n", addr); |
119,12 → 120,12
} |
|
/* Read a specific UART register. */ |
unsigned long uart_read(unsigned long addr) |
unsigned char uart_read8(unsigned long addr) |
{ |
unsigned char value = 0; |
int chipsel; |
|
debug("uart_read(%x)\n", addr); |
debug("uart_read8(%x)\n", addr); |
|
for(chipsel = 0; chipsel < NR_UARTS; chipsel++) |
if ((addr & ~(UART_ADDR_SPACE-1)) == uarts[chipsel].baseaddr) |
143,7 → 144,7
default: |
debug("read out of range (addr %x, DLAB=1)\n", addr); |
} |
return (value << 24); |
return value; |
} |
|
switch (addr % UART_ADDR_SPACE) { |
181,7 → 182,7
default: |
debug("read out of range (addr %x)\n", addr); |
} |
return (value << 24); |
return value; |
} |
|
/* Reset. It initializes all registers of all UART devices to zero values, |
189,27 → 190,27
space. */ |
void uart_reset() |
{ |
int i; |
int i; |
|
printf("Resetting %u UART(s).\n", NR_UARTS); |
memset(uarts, 0, sizeof(uarts)); |
printf("Resetting %u UART(s).\n", NR_UARTS); |
memset(uarts, 0, sizeof(uarts)); |
|
for(i = 0; i < NR_UARTS; i++) |
if (config.uarts[i].txfile) { /* MM: Try to create stream. */ |
if (!(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r")) |
&& !(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r+"))) { |
printf("UART%d has problems with RX file stream.\n", i); |
continue; |
} |
uarts[i].txfs = fopen(config.uarts[i].txfile, "a"); |
uarts[i].baseaddr = config.uarts[i].baseaddr; |
if (uarts[i].txfs && uarts[i].txfs) { |
printf("UART%d at 0x%.8x uses ", i, uarts[i].baseaddr); |
printf("%s for RX and %s for TX.\n", config.uarts[i].rxfile, config.uarts[i].txfile); |
} else |
printf("UART%d has problems with TX file stream.\n", i); |
register_memoryarea(uarts[i].baseaddr, UART_ADDR_SPACE, uart_read, uart_write); |
} |
for(i = 0; i < NR_UARTS; i++) |
if (config.uarts[i].txfile) { /* MM: Try to create stream. */ |
if (!(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r")) |
&& !(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r+"))) { |
printf("UART%d has problems with RX file stream.\n", i); |
continue; |
} |
uarts[i].txfs = fopen(config.uarts[i].txfile, "a"); |
uarts[i].baseaddr = config.uarts[i].baseaddr; |
if (uarts[i].txfs && uarts[i].txfs) { |
printf("UART%d at 0x%.8x uses ", i, uarts[i].baseaddr); |
printf("%s for RX and %s for TX.\n", config.uarts[i].rxfile, config.uarts[i].txfile); |
} else |
printf("UART%d has problems with TX file stream.\n", i); |
register_memoryarea(uarts[i].baseaddr, UART_ADDR_SPACE, 1, uart_read8, uart_write8, 0); |
} |
} |
|
/* Simulation hook. Must be called every clock cycle to simulate all UART |
320,9 → 321,8
int i; |
|
for(i = 0; i < NR_UARTS; i++) { |
/* if (!uarts[i].txfs) |
if ( !uarts[i].baseaddr ) |
continue; |
*/ |
printf("\nUART%d visible registers at 0x%.8x:\n", i, uarts[i].baseaddr); |
printf("RXBUF: %.2x TXBUF: %.2x\n", uarts[i].regs.rxbuf, uarts[i].regs.txbuf); |
printf("DLL : %.2x DLH : %.2x\n", uarts[i].regs.dll, uarts[i].regs.dlh); |
/trunk/or1ksim/peripheral/dma.c
1,22 → 1,22
/* dma.c -- Simulation of DMA |
Copyright (C) 2001 by Erez Volk, erez@mailandnews.com |
Copyright (C) 2001 by Erez Volk, erez@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. |
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. |
*/ |
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. |
*/ |
|
/* |
* This simulation of the DMA core is not meant to be full. |
28,15 → 28,15
#include "sim-config.h" |
#include "trace.h" |
#include "pic.h" |
#include "abstract.h" |
#include "fields.h" |
|
/* TODO List: |
* - "Restarting DMA Transfers" |
*/ |
|
/* The representation of the DMA controllers */ |
static struct dma_controller dmas[NR_DMAS]; |
|
static unsigned long dma_read32( unsigned long addr ); |
static void dma_write32( unsigned long addr, unsigned long value ); |
|
static unsigned long dma_read_ch_csr( struct dma_channel *channel ); |
static void dma_write_ch_csr( struct dma_channel *channel, unsigned long value ); |
static void dma_controller_clock( struct dma_controller *dma ); |
52,136 → 52,116
/* Reset. Initializes all registers to default and places devices in memory address space. */ |
void dma_reset() |
{ |
unsigned i; |
unsigned i; |
|
memset( dmas, 0, sizeof(dmas) ); |
|
for ( i = 0; i < NR_DMAS; ++ i ) |
{ |
struct dma_controller *dma = &(dmas[i]); |
unsigned channel_number; |
memset( dmas, 0, sizeof(dmas) ); |
|
for ( i = 0; i < NR_DMAS; ++ i ) { |
struct dma_controller *dma = &(dmas[i]); |
unsigned channel_number; |
|
dma->baseaddr = config.dmas[i].baseaddr; |
for ( channel_number = 0; channel_number < DMA_NUM_CHANNELS; ++ channel_number ) |
{ |
dma->ch[channel_number].controller = &(dmas[i]); |
dma->ch[channel_number].channel_number = channel_number; |
dma->ch[channel_number].channel_mask = 1LU << channel_number; |
dma->ch[channel_number].regs.am0 = dma->ch[channel_number].regs.am1 = 0xFFFFFFFC; |
dma->baseaddr = config.dmas[i].baseaddr; |
dma->irq = config.dmas[i].irq; |
for ( channel_number = 0; channel_number < DMA_NUM_CHANNELS; ++ channel_number ) { |
dma->ch[channel_number].controller = &(dmas[i]); |
dma->ch[channel_number].channel_number = channel_number; |
dma->ch[channel_number].channel_mask = 1LU << channel_number; |
dma->ch[channel_number].regs.am0 = dma->ch[channel_number].regs.am1 = 0xFFFFFFFC; |
} |
if ( dma->baseaddr != 0 ) |
register_memoryarea( dma->baseaddr, DMA_ADDR_SPACE, 4, dma_read32, dma_write32, 0 ); |
} |
if ( dma->baseaddr != 0 ) |
register_memoryarea( dma->baseaddr, DMA_ADDR_SPACE, dma_read, dma_write ); |
} |
} |
|
/* Print register values on stdout */ |
void dma_status( void ) |
{ |
unsigned i, j; |
unsigned i, j; |
|
for ( i = 0; i < NR_DMAS; ++ i ) |
{ |
struct dma_controller *dma = &(dmas[i]); |
for ( i = 0; i < NR_DMAS; ++ i ) { |
struct dma_controller *dma = &(dmas[i]); |
|
if ( dma->baseaddr == 0 ) |
continue; |
if ( dma->baseaddr == 0 ) |
continue; |
|
printf( "\nDMA controller %u at 0x%08X:\n", i, dma->baseaddr ); |
printf( "CSR : 0x%08lX\n", dma->regs.csr ); |
printf( "INT_MSK_A : 0x%08lX\n", dma->regs.int_msk_a ); |
printf( "INT_MSK_B : 0x%08lX\n", dma->regs.int_msk_b ); |
printf( "INT_SRC_A : 0x%08lX\n", dma->regs.int_src_a ); |
printf( "INT_SRC_B : 0x%08lX\n", dma->regs.int_src_b ); |
printf( "\nDMA controller %u at 0x%08X:\n", i, dma->baseaddr ); |
printf( "CSR : 0x%08lX\n", dma->regs.csr ); |
printf( "INT_MSK_A : 0x%08lX\n", dma->regs.int_msk_a ); |
printf( "INT_MSK_B : 0x%08lX\n", dma->regs.int_msk_b ); |
printf( "INT_SRC_A : 0x%08lX\n", dma->regs.int_src_a ); |
printf( "INT_SRC_B : 0x%08lX\n", dma->regs.int_src_b ); |
|
for ( j = 0; j < DMA_NUM_CHANNELS; ++ j ) |
{ |
struct dma_channel *channel = &(dma->ch[j]); |
if ( !channel->referenced ) |
continue; |
printf( "CH%u_CSR : 0x%08lX\n", j, channel->regs.csr ); |
printf( "CH%u_SZ : 0x%08lX\n", j, channel->regs.sz ); |
printf( "CH%u_A0 : 0x%08lX\n", j, channel->regs.a0 ); |
printf( "CH%u_AM0 : 0x%08lX\n", j, channel->regs.am0 ); |
printf( "CH%u_A1 : 0x%08lX\n", j, channel->regs.a1 ); |
printf( "CH%u_AM1 : 0x%08lX\n", j, channel->regs.am1 ); |
printf( "CH%u_DESC : 0x%08lX\n", j, channel->regs.desc ); |
printf( "CH%u_SWPTR : 0x%08lX\n", j, channel->regs.swptr ); |
for ( j = 0; j < DMA_NUM_CHANNELS; ++ j ) { |
struct dma_channel *channel = &(dma->ch[j]); |
if ( !channel->referenced ) |
continue; |
printf( "CH%u_CSR : 0x%08lX\n", j, channel->regs.csr ); |
printf( "CH%u_SZ : 0x%08lX\n", j, channel->regs.sz ); |
printf( "CH%u_A0 : 0x%08lX\n", j, channel->regs.a0 ); |
printf( "CH%u_AM0 : 0x%08lX\n", j, channel->regs.am0 ); |
printf( "CH%u_A1 : 0x%08lX\n", j, channel->regs.a1 ); |
printf( "CH%u_AM1 : 0x%08lX\n", j, channel->regs.am1 ); |
printf( "CH%u_DESC : 0x%08lX\n", j, channel->regs.desc ); |
printf( "CH%u_SWPTR : 0x%08lX\n", j, channel->regs.swptr ); |
} |
} |
} |
} |
|
|
/* Read a register */ |
unsigned long dma_read( unsigned long addr ) |
unsigned long dma_read32( unsigned long addr ) |
{ |
unsigned i; |
struct dma_controller *dma = NULL; |
unsigned i; |
struct dma_controller *dma = NULL; |
|
for ( i = 0; i < NR_DMAS && dma == NULL; ++ i ) |
{ |
if ( addr >= dmas[i].baseaddr && addr < dmas[i].baseaddr + DMA_ADDR_SPACE ) |
dma = &(dmas[i]); |
} |
|
/* verify we found a controller */ |
if ( dma == NULL ) |
{ |
debug( "dma_read( 0x%08lX ): Out of range\n", addr ); |
cont_run = 0; |
return 0; |
} |
for ( i = 0; i < NR_DMAS && dma == NULL; ++ i ) { |
if ( addr >= dmas[i].baseaddr && addr < dmas[i].baseaddr + DMA_ADDR_SPACE ) |
dma = &(dmas[i]); |
} |
|
/* verify we found a controller */ |
if ( dma == NULL ) { |
fprintf( stderr, "dma_read32( 0x%08lX ): Out of range\n", addr ); |
cont_run = 0; |
return 0; |
} |
|
addr -= dma->baseaddr; |
addr -= dma->baseaddr; |
|
if ( addr % 4 != 0 ) |
{ |
debug( "dma_read( 0x%08lX ): Not register-aligned\n", addr + dma->baseaddr ); |
cont_run = 0; |
return 0; |
} |
if ( addr % 4 != 0 ) { |
fprintf( stderr, "dma_read32( 0x%08lX ): Not register-aligned\n", addr + dma->baseaddr ); |
cont_run = 0; |
return 0; |
} |
|
/* case of global (not per-channel) registers */ |
if ( addr < DMA_CH_BASE ) |
{ |
switch( addr ) |
{ |
case DMA_CSR: return dma->regs.csr; |
case DMA_INT_MSK_A: return dma->regs.int_msk_a; |
case DMA_INT_MSK_B: return dma->regs.int_msk_b; |
case DMA_INT_SRC_A: { |
/* TODO: Doc doesn't say clear the bits, but this looks right. Check it */ |
unsigned long result = dma->regs.int_src_a; |
dma->regs.int_src_a = 0; |
return result; |
} |
case DMA_INT_SRC_B: { |
unsigned long result = dma->regs.int_src_b; |
dma->regs.int_src_b = 0; |
return result; |
} |
default: |
debug( "dma_read( 0x%08lX ): Illegal register\n", addr + dma->baseaddr ); |
cont_run = 0; |
return 0; |
} |
} |
else |
{ |
/* case of per-channel registers */ |
unsigned chno = (addr - DMA_CH_BASE) / DMA_CH_SIZE; |
addr = (addr - DMA_CH_BASE) % DMA_CH_SIZE; |
switch( addr ) |
{ |
case DMA_CH_CSR: return dma_read_ch_csr( &(dma->ch[chno]) ); |
case DMA_CH_SZ: return dma->ch[chno].regs.sz; |
case DMA_CH_A0: return dma->ch[chno].regs.a0; |
case DMA_CH_AM0: return dma->ch[chno].regs.am0; |
case DMA_CH_A1: return dma->ch[chno].regs.a1; |
case DMA_CH_AM1: return dma->ch[chno].regs.am1; |
case DMA_CH_DESC: return dma->ch[chno].regs.desc; |
case DMA_CH_SWPTR: return dma->ch[chno].regs.swptr; |
} |
} |
/* case of global (not per-channel) registers */ |
if ( addr < DMA_CH_BASE ) { |
switch( addr ) { |
case DMA_CSR: return dma->regs.csr; |
case DMA_INT_MSK_A: return dma->regs.int_msk_a; |
case DMA_INT_MSK_B: return dma->regs.int_msk_b; |
case DMA_INT_SRC_A: return dma->regs.int_src_a; |
case DMA_INT_SRC_B: return dma->regs.int_src_b; |
default: |
fprintf( stderr, "dma_read32( 0x%08lX ): Illegal register\n", addr + dma->baseaddr ); |
cont_run = 0; |
return 0; |
} |
} else { |
/* case of per-channel registers */ |
unsigned chno = (addr - DMA_CH_BASE) / DMA_CH_SIZE; |
addr = (addr - DMA_CH_BASE) % DMA_CH_SIZE; |
switch( addr ) { |
case DMA_CH_CSR: return dma_read_ch_csr( &(dma->ch[chno]) ); |
case DMA_CH_SZ: return dma->ch[chno].regs.sz; |
case DMA_CH_A0: return dma->ch[chno].regs.a0; |
case DMA_CH_AM0: return dma->ch[chno].regs.am0; |
case DMA_CH_A1: return dma->ch[chno].regs.a1; |
case DMA_CH_AM1: return dma->ch[chno].regs.am1; |
case DMA_CH_DESC: return dma->ch[chno].regs.desc; |
case DMA_CH_SWPTR: return dma->ch[chno].regs.swptr; |
} |
} |
} |
|
|
188,88 → 168,80
/* Handle read from a channel CSR */ |
unsigned long dma_read_ch_csr( struct dma_channel *channel ) |
{ |
unsigned long result = channel->regs.csr; |
unsigned long result = channel->regs.csr; |
|
/* before returning, clear all relevant bits */ |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, INT_CHUNK_DONE ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, INT_DONE ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, INT_ERR ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); |
/* before returning, clear all relevant bits */ |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, INT_CHUNK_DONE ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, INT_DONE ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, INT_ERR ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); |
|
return result; |
return result; |
} |
|
|
|
/* Write a register */ |
void dma_write( unsigned long addr, unsigned long value ) |
void dma_write32( unsigned long addr, unsigned long value ) |
{ |
unsigned i; |
struct dma_controller *dma = NULL; |
unsigned i; |
struct dma_controller *dma = NULL; |
|
/* Find which controller this is */ |
for ( i = 0; i < NR_DMAS && dma == NULL; ++ i ) |
{ |
if ( (addr >= dmas[i].baseaddr) && (addr < dmas[i].baseaddr + DMA_ADDR_SPACE) ) |
dma = &(dmas[i]); |
} |
|
/* verify we found a controller */ |
if ( dma == NULL ) |
{ |
debug( "dma_write( 0x%08lX ): Out of range\n", addr ); |
cont_run = 0; |
return; |
} |
/* Find which controller this is */ |
for ( i = 0; i < NR_DMAS && dma == NULL; ++ i ) { |
if ( (addr >= dmas[i].baseaddr) && (addr < dmas[i].baseaddr + DMA_ADDR_SPACE) ) |
dma = &(dmas[i]); |
} |
|
/* verify we found a controller */ |
if ( dma == NULL ) { |
fprintf( stderr, "dma_write32( 0x%08lX ): Out of range\n", addr ); |
cont_run = 0; |
return; |
} |
|
addr -= dma->baseaddr; |
addr -= dma->baseaddr; |
|
if ( addr % 4 != 0 ) |
{ |
debug( "dma_write( 0x%08lX ): Not register-aligned\n", addr + dma->baseaddr ); |
cont_run = 0; |
return; |
} |
if ( addr % 4 != 0 ) { |
fprintf( stderr, "dma_write32( 0x%08lX, 0x%08lX ): Not register-aligned\n", addr + dma->baseaddr, value ); |
cont_run = 0; |
return; |
} |
|
/* case of global (not per-channel) registers */ |
if ( addr < DMA_CH_BASE ) |
{ |
switch( addr ) |
{ |
case DMA_CSR: |
if ( TEST_FLAG( value, DMA_CSR, PAUSE ) ) |
debug( "dma: PAUSE not implemented\n" ); |
break; |
/* case of global (not per-channel) registers */ |
if ( addr < DMA_CH_BASE ) { |
switch( addr ) { |
case DMA_CSR: |
if ( TEST_FLAG( value, DMA_CSR, PAUSE ) ) |
fprintf( stderr, "dma: PAUSE not implemented\n" ); |
break; |
|
case DMA_INT_MSK_A: dma->regs.int_msk_a = value; break; |
case DMA_INT_MSK_B: dma->regs.int_msk_b = value; break; |
case DMA_INT_SRC_A: dma->regs.int_src_a = value; break; |
case DMA_INT_SRC_B: dma->regs.int_src_b = value; break; |
default: |
debug( "dma_write( 0x%08lX ): Illegal register\n", addr + dma->baseaddr ); |
cont_run = 0; |
return; |
case DMA_INT_MSK_A: dma->regs.int_msk_a = value; break; |
case DMA_INT_MSK_B: dma->regs.int_msk_b = value; break; |
case DMA_INT_SRC_A: dma->regs.int_src_a = value; break; |
case DMA_INT_SRC_B: dma->regs.int_src_b = value; break; |
default: |
fprintf( stderr, "dma_write32( 0x%08lX ): Illegal register\n", addr + dma->baseaddr ); |
cont_run = 0; |
return; |
} |
} else { |
/* case of per-channel registers */ |
unsigned chno = (addr - DMA_CH_BASE) / DMA_CH_SIZE; |
struct dma_channel *channel = &(dma->ch[chno]); |
channel->referenced = 1; |
addr = (addr - DMA_CH_BASE) % DMA_CH_SIZE; |
switch( addr ) { |
case DMA_CSR: dma_write_ch_csr( &(dma->ch[chno]), value ); break; |
case DMA_CH_SZ: channel->regs.sz = value; break; |
case DMA_CH_A0: channel->regs.a0 = value; break; |
case DMA_CH_AM0: channel->regs.am0 = value; break; |
case DMA_CH_A1: channel->regs.a1 = value; break; |
case DMA_CH_AM1: channel->regs.am1 = value; break; |
case DMA_CH_DESC: channel->regs.desc = value; break; |
case DMA_CH_SWPTR: channel->regs.swptr = value; break; |
} |
} |
} |
else |
{ |
/* case of per-channel registers */ |
unsigned chno = (addr - DMA_CH_BASE) / DMA_CH_SIZE; |
struct dma_channel *channel = &(dma->ch[chno]); |
channel->referenced = 1; |
addr = (addr - DMA_CH_BASE) % DMA_CH_SIZE; |
switch( addr ) |
{ |
case DMA_CSR: dma_write_ch_csr( &(dma->ch[chno]), value ); break; |
case DMA_CH_SZ: channel->regs.sz = value; break; |
case DMA_CH_A0: channel->regs.a0 = value; break; |
case DMA_CH_AM0: channel->regs.am0 = value; break; |
case DMA_CH_A1: channel->regs.a1 = value; break; |
case DMA_CH_AM1: channel->regs.am1 = value; break; |
case DMA_CH_DESC: channel->regs.desc = value; break; |
case DMA_CH_SWPTR: channel->regs.swptr = value; break; |
} |
} |
} |
|
|
278,9 → 250,9
*/ |
void dma_write_ch_csr( struct dma_channel *channel, unsigned long value ) |
{ |
/* Copy the writable bits to the channel CSR */ |
channel->regs.csr &= ~DMA_CH_CSR_WRITE_MASK; |
channel->regs.csr |= value & DMA_CH_CSR_WRITE_MASK; |
/* Copy the writable bits to the channel CSR */ |
channel->regs.csr &= ~DMA_CH_CSR_WRITE_MASK; |
channel->regs.csr |= value & DMA_CH_CSR_WRITE_MASK; |
} |
|
|
291,27 → 263,27
|
void set_dma_req_i( unsigned dma_controller, unsigned channel ) |
{ |
dmas[dma_controller].ch[channel].dma_req_i = 1; |
dmas[dma_controller].ch[channel].dma_req_i = 1; |
} |
|
void clear_dma_req_i( unsigned dma_controller, unsigned channel ) |
{ |
dmas[dma_controller].ch[channel].dma_req_i = 0; |
dmas[dma_controller].ch[channel].dma_req_i = 0; |
} |
|
void set_dma_nd_i( unsigned dma_controller, unsigned channel ) |
{ |
dmas[dma_controller].ch[channel].dma_nd_i = 1; |
dmas[dma_controller].ch[channel].dma_nd_i = 1; |
} |
|
void clear_dma_nd_i( unsigned dma_controller, unsigned channel ) |
{ |
dmas[dma_controller].ch[channel].dma_nd_i = 0; |
dmas[dma_controller].ch[channel].dma_nd_i = 0; |
} |
|
unsigned check_dma_acq_o( unsigned dma_controller, unsigned channel ) |
unsigned check_dma_ack_o( unsigned dma_controller, unsigned channel ) |
{ |
return dmas[dma_controller].ch[channel].dma_acq_o; |
return dmas[dma_controller].ch[channel].dma_ack_o; |
} |
|
|
319,12 → 291,11
/* Simulation hook. Must be called every clock cycle to simulate DMA. */ |
void dma_clock() |
{ |
unsigned i; |
for ( i = 0; i < NR_DMAS; ++ i ) |
{ |
if ( dmas[i].baseaddr != 0 ) |
dma_controller_clock( &(dmas[i]) ); |
} |
unsigned i; |
for ( i = 0; i < NR_DMAS; ++ i ) { |
if ( dmas[i].baseaddr != 0 ) |
dma_controller_clock( &(dmas[i]) ); |
} |
} |
|
|
334,92 → 305,85
*/ |
void dma_controller_clock( struct dma_controller *dma ) |
{ |
unsigned chno, i; |
int breakpoint = 0; |
|
for ( chno = 0; chno < DMA_NUM_CHANNELS; ++ chno ) |
{ |
struct dma_channel *channel = &(dma->ch[chno]); |
|
/* check if this channel is enabled */ |
if ( !TEST_FLAG( channel->regs.csr, DMA_CH_CSR, CH_EN ) ) |
continue; |
unsigned chno, i; |
int breakpoint = 0; |
|
for ( chno = 0; chno < DMA_NUM_CHANNELS; ++ chno ) { |
struct dma_channel *channel = &(dma->ch[chno]); |
|
/* check if this channel is enabled */ |
if ( !TEST_FLAG( channel->regs.csr, DMA_CH_CSR, CH_EN ) ) |
continue; |
|
/* Do we need to abort? */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, STOP ) ) |
{ |
debug( "DMA: STOP requested\n" ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, CH_EN ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ); |
SET_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); |
|
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INE_ERR ) && |
(channel->controller->regs.int_msk_a & channel->channel_mask) ) |
{ |
SET_FLAG( channel->regs.csr, DMA_CH_CSR, INT_ERR ); |
channel->controller->regs.int_src_a = channel->channel_mask; |
report_interrupt( INT_DMA ); |
} |
/* Do we need to abort? */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, STOP ) ) { |
fprintf( stderr, "DMA: STOP requested\n" ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, CH_EN ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ); |
SET_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); |
|
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INE_ERR ) && |
(channel->controller->regs.int_msk_a & channel->channel_mask) ) { |
SET_FLAG( channel->regs.csr, DMA_CH_CSR, INT_ERR ); |
channel->controller->regs.int_src_a = channel->channel_mask; |
report_interrupt( channel->controller->irq ); |
} |
|
continue; |
} |
continue; |
} |
|
/* In HW Handshake mode, only work when dma_req_i asserted */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, MODE ) && |
!channel->dma_req_i ) |
{ |
debug( "DMA: Waiting for HW handshake\n" ); |
continue; |
} |
/* In HW Handshake mode, only work when dma_req_i asserted */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, MODE ) && |
!channel->dma_req_i ) { |
fprintf( stderr, "DMA: Waiting for HW handshake\n" ); |
continue; |
} |
|
/* If this is the first cycle of the transfer, initialize our state */ |
if ( !TEST_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ) ) |
{ |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, DONE ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); |
SET_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ); |
/* If this is the first cycle of the transfer, initialize our state */ |
if ( !TEST_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ) ) { |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, DONE ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); |
SET_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ); |
|
/* If using linked lists, copy the appropriate fields to our registers */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, USE_ED ) ) |
dma_load_descriptor( channel ); |
else |
channel->load_next_descriptor_when_done = 0; |
|
/* Set our internal status */ |
dma_init_transfer( channel ); |
/* If using linked lists, copy the appropriate fields to our registers */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, USE_ED ) ) |
dma_load_descriptor( channel ); |
else |
channel->load_next_descriptor_when_done = 0; |
|
/* Set our internal status */ |
dma_init_transfer( channel ); |
|
/* Might need to skip descriptor */ |
if ( CHANNEL_ND_I( channel ) ) |
{ |
debug( "DMA: dma_nd_i asserted before dma_req_i, skipping descriptor\n" ); |
dma_channel_terminate_transfer( channel, 0 ); |
continue; |
} |
} |
/* Might need to skip descriptor */ |
if ( CHANNEL_ND_I( channel ) ) { |
fprintf( stderr, "DMA: dma_nd_i asserted before dma_req_i, skipping descriptor\n" ); |
dma_channel_terminate_transfer( channel, 0 ); |
continue; |
} |
} |
|
/* Transfer one word */ |
set_mem32( channel->destination, eval_mem32( channel->source, &breakpoint ), &breakpoint ); |
/* Transfer one word */ |
set_mem32( channel->destination, eval_mem32( channel->source, &breakpoint ), &breakpoint ); |
|
/* Advance the source and destionation pointers */ |
masked_increase( &(channel->source), channel->source_mask ); |
masked_increase( &(channel->destination), channel->destination_mask ); |
++ channel->words_transferred; |
/* Advance the source and destionation pointers */ |
masked_increase( &(channel->source), channel->source_mask ); |
masked_increase( &(channel->destination), channel->destination_mask ); |
++ channel->words_transferred; |
|
/* Have we finished a whole chunk? */ |
channel->dma_acq_o = (channel->words_transferred % channel->chunk_size == 0); |
/* Have we finished a whole chunk? */ |
channel->dma_ack_o = (channel->words_transferred % channel->chunk_size == 0); |
|
/* When done with a chunk, check for dma_nd_i */ |
if ( CHANNEL_ND_I( channel ) ) |
{ |
debug( "DMA: dma_nd_i asserted, \n" ); |
dma_channel_terminate_transfer( channel, 0 ); |
continue; |
/* When done with a chunk, check for dma_nd_i */ |
if ( CHANNEL_ND_I( channel ) ) { |
fprintf( stderr, "DMA: dma_nd_i asserted, \n" ); |
dma_channel_terminate_transfer( channel, 0 ); |
continue; |
} |
|
/* Are we done? */ |
if ( channel->words_transferred >= channel->total_size ) |
dma_channel_terminate_transfer( channel, 1 ); |
} |
|
/* Are we done? */ |
if ( channel->words_transferred >= channel->total_size ) |
dma_channel_terminate_transfer( channel, 1 ); |
} |
} |
|
|
426,23 → 390,23
/* Copy relevant valued from linked list descriptor to channel registers */ |
void dma_load_descriptor( struct dma_channel *channel ) |
{ |
int breakpoint = 0; |
unsigned long desc_csr = eval_mem32( channel->regs.desc + DMA_DESC_CSR, &breakpoint ); |
int breakpoint = 0; |
unsigned long desc_csr = eval_mem32( channel->regs.desc + DMA_DESC_CSR, &breakpoint ); |
|
channel->load_next_descriptor_when_done = !TEST_FLAG( desc_csr, DMA_DESC_CSR, EOL ); |
channel->load_next_descriptor_when_done = !TEST_FLAG( desc_csr, DMA_DESC_CSR, EOL ); |
|
ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, INC_SRC, TEST_FLAG( desc_csr, DMA_DESC_CSR, INC_SRC ) ); |
ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, INC_DST, TEST_FLAG( desc_csr, DMA_DESC_CSR, INC_DST ) ); |
ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, SRC_SEL, TEST_FLAG( desc_csr, DMA_DESC_CSR, SRC_SEL ) ); |
ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, DST_SEL, TEST_FLAG( desc_csr, DMA_DESC_CSR, DST_SEL ) ); |
ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, INC_SRC, TEST_FLAG( desc_csr, DMA_DESC_CSR, INC_SRC ) ); |
ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, INC_DST, TEST_FLAG( desc_csr, DMA_DESC_CSR, INC_DST ) ); |
ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, SRC_SEL, TEST_FLAG( desc_csr, DMA_DESC_CSR, SRC_SEL ) ); |
ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, DST_SEL, TEST_FLAG( desc_csr, DMA_DESC_CSR, DST_SEL ) ); |
|
SET_FIELD( channel->regs.sz, DMA_CH_SZ, TOT_SZ, GET_FIELD( desc_csr, DMA_DESC_CSR, TOT_SZ ) ); |
SET_FIELD( channel->regs.sz, DMA_CH_SZ, TOT_SZ, GET_FIELD( desc_csr, DMA_DESC_CSR, TOT_SZ ) ); |
|
channel->regs.a0 = eval_mem32( channel->regs.desc + DMA_DESC_ADR0, &breakpoint ); |
channel->regs.a1 = eval_mem32( channel->regs.desc + DMA_DESC_ADR1, &breakpoint ); |
channel->regs.a0 = eval_mem32( channel->regs.desc + DMA_DESC_ADR0, &breakpoint ); |
channel->regs.a1 = eval_mem32( channel->regs.desc + DMA_DESC_ADR1, &breakpoint ); |
|
channel->current_descriptor = channel->regs.desc; |
channel->regs.desc = eval_mem32( channel->regs.desc + DMA_DESC_NEXT, &breakpoint ); |
channel->current_descriptor = channel->regs.desc; |
channel->regs.desc = eval_mem32( channel->regs.desc + DMA_DESC_NEXT, &breakpoint ); |
} |
|
|
449,15 → 413,15
/* Initialize internal parameters used to implement transfers */ |
void dma_init_transfer( struct dma_channel *channel ) |
{ |
channel->source = channel->regs.a0; |
channel->destination = channel->regs.a1; |
channel->source_mask = TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INC_SRC ) ? channel->regs.am0 : 0; |
channel->destination_mask = TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INC_DST ) ? channel->regs.am1 : 0; |
channel->total_size = GET_FIELD( channel->regs.sz, DMA_CH_SZ, TOT_SZ ); |
channel->chunk_size = GET_FIELD( channel->regs.sz, DMA_CH_SZ, CHK_SZ ); |
if ( !channel->chunk_size || (channel->chunk_size > channel->total_size) ) |
channel->chunk_size = channel->total_size; |
channel->words_transferred = 0; |
channel->source = channel->regs.a0; |
channel->destination = channel->regs.a1; |
channel->source_mask = TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INC_SRC ) ? channel->regs.am0 : 0; |
channel->destination_mask = TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INC_DST ) ? channel->regs.am1 : 0; |
channel->total_size = GET_FIELD( channel->regs.sz, DMA_CH_SZ, TOT_SZ ); |
channel->chunk_size = GET_FIELD( channel->regs.sz, DMA_CH_SZ, CHK_SZ ); |
if ( !channel->chunk_size || (channel->chunk_size > channel->total_size) ) |
channel->chunk_size = channel->total_size; |
channel->words_transferred = 0; |
} |
|
|
464,54 → 428,49
/* Take care of transfer termination */ |
void dma_channel_terminate_transfer( struct dma_channel *channel, int generate_interrupt ) |
{ |
/* Might be working in a linked list */ |
if ( channel->load_next_descriptor_when_done ) |
{ |
dma_load_descriptor( channel ); |
dma_init_transfer( channel ); |
return; |
} |
/* Might be working in a linked list */ |
if ( channel->load_next_descriptor_when_done ) { |
dma_load_descriptor( channel ); |
dma_init_transfer( channel ); |
return; |
} |
|
/* Might be in auto-restart mode */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, ARS ) ) |
{ |
dma_init_transfer( channel ); |
return; |
} |
/* Might be in auto-restart mode */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, ARS ) ) { |
dma_init_transfer( channel ); |
return; |
} |
|
/* If needed, write amount of data transferred back to memory */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, SZ_WB ) && |
TEST_FLAG( channel->regs.csr, DMA_CH_CSR, USE_ED ) ) |
{ |
int breakpoint = 0; |
unsigned long desc_csr = eval_mem32( channel->regs.desc + DMA_DESC_CSR, &breakpoint ); |
/* TODO: What should we write back? Doc says "total number of remaining bytes" !? */ |
unsigned long remaining_words = channel->total_size - channel->words_transferred; |
SET_FIELD( channel->regs.sz, DMA_DESC_CSR, TOT_SZ, remaining_words ); |
} |
/* If needed, write amount of data transferred back to memory */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, SZ_WB ) && |
TEST_FLAG( channel->regs.csr, DMA_CH_CSR, USE_ED ) ) { |
int breakpoint = 0; |
unsigned long desc_csr = eval_mem32( channel->regs.desc + DMA_DESC_CSR, &breakpoint ); |
/* TODO: What should we write back? Doc says "total number of remaining bytes" !? */ |
unsigned long remaining_words = channel->total_size - channel->words_transferred; |
SET_FIELD( channel->regs.sz, DMA_DESC_CSR, TOT_SZ, remaining_words ); |
} |
|
/* Mark end of transfer */ |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, CH_EN ); |
SET_FLAG( channel->regs.csr, DMA_CH_CSR, DONE ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ); |
|
/* If needed, generate interrupt */ |
if ( generate_interrupt ) |
{ |
/* TODO: Which channel should we interrupt? */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INE_DONE ) && |
(channel->controller->regs.int_msk_a & channel->channel_mask) ) |
{ |
SET_FLAG( channel->regs.csr, DMA_CH_CSR, INT_DONE ); |
channel->controller->regs.int_src_a = channel->channel_mask; |
report_interrupt( INT_DMA ); |
/* Mark end of transfer */ |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, CH_EN ); |
SET_FLAG( channel->regs.csr, DMA_CH_CSR, DONE ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); |
CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ); |
|
/* If needed, generate interrupt */ |
if ( generate_interrupt ) { |
/* TODO: Which channel should we interrupt? */ |
if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INE_DONE ) && |
(channel->controller->regs.int_msk_a & channel->channel_mask) ) { |
SET_FLAG( channel->regs.csr, DMA_CH_CSR, INT_DONE ); |
channel->controller->regs.int_src_a = channel->channel_mask; |
report_interrupt( channel->controller->irq ); |
} |
} |
} |
} |
|
/* Utility function: Add 4 to a value with a mask */ |
void masked_increase( unsigned long *value, unsigned long mask ) |
{ |
*value = (*value & ~mask) | ((*value & mask) + 4); |
*value = (*value & ~mask) | ((*value & mask) + 4); |
} |
/trunk/or1ksim/peripheral/16450.h
18,8 → 18,6
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
/* Prototypes */ |
void uart_write(unsigned long addr, unsigned long value); |
unsigned long uart_read(unsigned long addr); |
void uart_reset(); |
void uart_clock(); |
|
/trunk/or1ksim/peripheral/dma.h
1,5 → 1,5
/* dma.h -- Definition of types and structures for DMA |
Copyright (C) 2001 by Erez Volk, erez@mailandnews.com |
Copyright (C) 2001 by Erez Volk, erez@opencores.org |
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
16,19 → 16,17
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. |
*/ |
*/ |
|
/* Exported function prototypes */ |
void dma_reset( void ); |
void dma_clock( void ); |
void dma_write( unsigned long addr, unsigned long value ); |
unsigned long dma_read( unsigned long addr ); |
|
void set_dma_req_i( unsigned dma_controller, unsigned channel ); |
void clear_dma_req_i( unsigned dma_controller, unsigned channel ); |
void set_dma_nd_i( unsigned dma_controller, unsigned channel ); |
void clear_dma_nd_i( unsigned dma_controller, unsigned channel ); |
unsigned check_dma_acq_o( unsigned dma_controller, unsigned channel ); |
unsigned check_dma_ack_o( unsigned dma_controller, unsigned channel ); |
|
/* Number of channel per DMA controller */ |
#define DMA_NUM_CHANNELS 31 |
137,39 → 135,39
/* Implementation of DMA Channel Registers and State */ |
struct dma_channel |
{ |
/* The controller we belong to */ |
struct dma_controller *controller; |
/* The controller we belong to */ |
struct dma_controller *controller; |
|
/* Our channel number and bit mask */ |
unsigned channel_number; |
unsigned long channel_mask; |
/* Our channel number and bit mask */ |
unsigned channel_number; |
unsigned long channel_mask; |
|
/* Used for dump, to save dumping all 32 channels */ |
unsigned referenced; |
/* Used for dump, to save dumping all 32 channels */ |
unsigned referenced; |
|
/* Inner state of transfer etc. */ |
unsigned load_next_descriptor_when_done; |
unsigned long current_descriptor; |
unsigned long source, destination, source_mask, destination_mask; |
unsigned long chunk_size, total_size, words_transferred; |
/* Inner state of transfer etc. */ |
unsigned load_next_descriptor_when_done; |
unsigned long current_descriptor; |
unsigned long source, destination, source_mask, destination_mask; |
unsigned long chunk_size, total_size, words_transferred; |
|
/* The interface registers */ |
struct |
{ |
unsigned long csr; |
unsigned long sz; |
unsigned long a0; |
unsigned long am0; |
unsigned long a1; |
unsigned long am1; |
unsigned long desc; |
unsigned long swptr; |
} regs; |
/* The interface registers */ |
struct |
{ |
unsigned long csr; |
unsigned long sz; |
unsigned long a0; |
unsigned long am0; |
unsigned long a1; |
unsigned long am1; |
unsigned long desc; |
unsigned long swptr; |
} regs; |
|
/* Some control signals */ |
unsigned dma_req_i; |
unsigned dma_acq_o; |
unsigned dma_nd_i; |
/* Some control signals */ |
unsigned dma_req_i; |
unsigned dma_ack_o; |
unsigned dma_nd_i; |
}; |
|
|
176,19 → 174,22
/* Implementation of DMA Controller Registers and State */ |
struct dma_controller |
{ |
/* Base address in memory */ |
unsigned long baseaddr; |
/* Base address in memory */ |
unsigned long baseaddr; |
|
/* Controller Registers */ |
struct |
{ |
unsigned long csr; |
unsigned long int_msk_a; |
unsigned long int_msk_b; |
unsigned long int_src_a; |
unsigned long int_src_b; |
} regs; |
/* Which interrupt number we generate */ |
unsigned irq; |
|
/* Channels */ |
struct dma_channel ch[DMA_NUM_CHANNELS]; |
/* Controller Registers */ |
struct |
{ |
unsigned long csr; |
unsigned long int_msk_a; |
unsigned long int_msk_b; |
unsigned long int_src_a; |
unsigned long int_src_b; |
} regs; |
|
/* Channels */ |
struct dma_channel ch[DMA_NUM_CHANNELS]; |
}; |