📄 remote-nindy.c
字号:
{ struct nindy_regs nindy_regs; int regnum, inv; double dub; immediate_quit++; ninRegsGet( (char *) &nindy_regs ); immediate_quit--; bcopy (nindy_regs.local_regs, ®isters[REGISTER_BYTE (R0_REGNUM)], 16*4); bcopy (nindy_regs.global_regs, ®isters[REGISTER_BYTE (G0_REGNUM)], 16*4); bcopy (nindy_regs.pcw_acw, ®isters[REGISTER_BYTE (PCW_REGNUM)], 2*4); bcopy (nindy_regs.ip, ®isters[REGISTER_BYTE (IP_REGNUM)], 1*4); bcopy (nindy_regs.tcw, ®isters[REGISTER_BYTE (TCW_REGNUM)], 1*4); for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) { dub = unpack_double (builtin_type_double, &nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)], &inv); /* dub now in host byte order */ double_to_ieee_extended (&ext_format_i960, &dub, ®isters[REGISTER_BYTE (regnum)]); } registers_fetched ();}static voidnindy_prepare_to_store(){ /* Fetch all regs if they aren't already here. */ read_register_bytes (0, NULL, REGISTER_BYTES);}static voidnindy_store_registers(regno) int regno;{ struct nindy_regs nindy_regs; int regnum, inv; double dub; bcopy (®isters[REGISTER_BYTE (R0_REGNUM)], nindy_regs.local_regs, 16*4); bcopy (®isters[REGISTER_BYTE (G0_REGNUM)], nindy_regs.global_regs, 16*4); bcopy (®isters[REGISTER_BYTE (PCW_REGNUM)], nindy_regs.pcw_acw, 2*4); bcopy (®isters[REGISTER_BYTE (IP_REGNUM)], nindy_regs.ip, 1*4); bcopy (®isters[REGISTER_BYTE (TCW_REGNUM)], nindy_regs.tcw, 1*4); /* Float regs. Only works on IEEE_FLOAT hosts. */ for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) { ieee_extended_to_double (&ext_format_i960, ®isters[REGISTER_BYTE (regnum)], &dub); /* dub now in host byte order */ /* FIXME-someday, the arguments to unpack_double are backward. It expects a target double and returns a host; we pass the opposite. This mostly works but not quite. */ dub = unpack_double (builtin_type_double, &dub, &inv); /* dub now in target byte order */ bcopy ((char *)&dub, &nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)], 8); } immediate_quit++; ninRegsPut( (char *) &nindy_regs ); immediate_quit--;}/* Read a word from remote address ADDR and return it. * This goes through the data cache. */intnindy_fetch_word (addr) CORE_ADDR addr;{ return dcache_fetch (addr);}/* Write a word WORD into remote address ADDR. This goes through the data cache. */voidnindy_store_word (addr, word) CORE_ADDR addr; int word;{ dcache_poke (addr, word);}/* Copy LEN bytes to or from inferior's memory starting at MEMADDR to debugger memory starting at MYADDR. Copy to inferior if WRITE is nonzero. Returns the length copied. This is stolen almost directly from infptrace.c's child_xfer_memory, which also deals with a word-oriented memory interface. Sometime, FIXME, rewrite this to not use the word-oriented routines. */intnindy_xfer_inferior_memory(memaddr, myaddr, len, write, target) CORE_ADDR memaddr; char *myaddr; int len; int write; struct target_ops *target; /* ignored */{ register int i; /* Round starting address down to longword boundary. */ register CORE_ADDR addr = memaddr & - sizeof (int); /* Round ending address up; get number of longwords that makes. */ register int count = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); /* Allocate buffer of that many longwords. */ register int *buffer = (int *) alloca (count * sizeof (int)); if (write) { /* Fill start and end extra bytes of buffer with existing memory data. */ if (addr != memaddr || len < (int)sizeof (int)) { /* Need part of initial word -- fetch it. */ buffer[0] = nindy_fetch_word (addr); } if (count > 1) /* FIXME, avoid if even boundary */ { buffer[count - 1] = nindy_fetch_word (addr + (count - 1) * sizeof (int)); } /* Copy data to be written over corresponding part of buffer */ bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); /* Write the entire buffer. */ for (i = 0; i < count; i++, addr += sizeof (int)) { errno = 0; nindy_store_word (addr, buffer[i]); if (errno) return 0; } } else { /* Read all the longwords */ for (i = 0; i < count; i++, addr += sizeof (int)) { errno = 0; buffer[i] = nindy_fetch_word (addr); if (errno) return 0; QUIT; } /* Copy appropriate bytes out of the buffer. */ bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); } return len;}/* The data cache records all the data read from the remote machine since the last time it stopped. Each cache block holds 16 bytes of data starting at a multiple-of-16 address. */#define DCACHE_SIZE 64 /* Number of cache blocks */struct dcache_block { struct dcache_block *next, *last; unsigned int addr; /* Address for which data is recorded. */ int data[4];};struct dcache_block dcache_free, dcache_valid;/* Free all the data cache blocks, thus discarding all cached data. */ staticvoiddcache_flush (){ register struct dcache_block *db; while ((db = dcache_valid.next) != &dcache_valid) { remque (db); insque (db, &dcache_free); }}/* * If addr is present in the dcache, return the address of the block * containing it. */staticstruct dcache_block *dcache_hit (addr) unsigned int addr;{ register struct dcache_block *db; if (addr & 3) abort (); /* Search all cache blocks for one that is at this address. */ db = dcache_valid.next; while (db != &dcache_valid) { if ((addr & 0xfffffff0) == db->addr) return db; db = db->next; } return NULL;}/* Return the int data at address ADDR in dcache block DC. */staticintdcache_value (db, addr) struct dcache_block *db; unsigned int addr;{ if (addr & 3) abort (); return (db->data[(addr>>2)&3]);}/* Get a free cache block, put or keep it on the valid list, and return its address. The caller should store into the block the address and data that it describes, then remque it from the free list and insert it into the valid list. This procedure prevents errors from creeping in if a ninMemGet is interrupted (which used to put garbage blocks in the valid list...). */staticstruct dcache_block *dcache_alloc (){ register struct dcache_block *db; if ((db = dcache_free.next) == &dcache_free) { /* If we can't get one from the free list, take last valid and put it on the free list. */ db = dcache_valid.last; remque (db); insque (db, &dcache_free); } remque (db); insque (db, &dcache_valid); return (db);}/* Return the contents of the word at address ADDR in the remote machine, using the data cache. */staticintdcache_fetch (addr) CORE_ADDR addr;{ register struct dcache_block *db; db = dcache_hit (addr); if (db == 0) { db = dcache_alloc (); immediate_quit++; ninMemGet(addr & ~0xf, (unsigned char *)db->data, 16); immediate_quit--; db->addr = addr & ~0xf; remque (db); /* Off the free list */ insque (db, &dcache_valid); /* On the valid list */ } return (dcache_value (db, addr));}/* Write the word at ADDR both in the data cache and in the remote machine. */static voiddcache_poke (addr, data) CORE_ADDR addr; int data;{ register struct dcache_block *db; /* First make sure the word is IN the cache. DB is its cache block. */ db = dcache_hit (addr); if (db == 0) { db = dcache_alloc (); immediate_quit++; ninMemGet(addr & ~0xf, (unsigned char *)db->data, 16); immediate_quit--; db->addr = addr & ~0xf; remque (db); /* Off the free list */ insque (db, &dcache_valid); /* On the valid list */ } /* Modify the word in the cache. */ db->data[(addr>>2)&3] = data; /* Send the changed word. */ immediate_quit++; ninMemPut(addr, (unsigned char *)&data, 4); immediate_quit--;}/* The cache itself. */struct dcache_block the_cache[DCACHE_SIZE];/* Initialize the data cache. */static voiddcache_init (){ register i; register struct dcache_block *db; db = the_cache; dcache_free.next = dcache_free.last = &dcache_free; dcache_valid.next = dcache_valid.last = &dcache_valid; for (i=0;i<DCACHE_SIZE;i++,db++) insque (db, &dcache_free);}static voidnindy_create_inferior (execfile, args, env) char *execfile; char *args; char **env;{ int entry_pt; int pid; if (args && *args) error ("Can't pass arguments to remote NINDY process"); if (execfile == 0 || exec_bfd == 0) error ("No exec file specified"); entry_pt = (int) bfd_get_start_address (exec_bfd); pid = 42;#ifdef CREATE_INFERIOR_HOOK CREATE_INFERIOR_HOOK (pid);#endif /* The "process" (board) is already stopped awaiting our commands, and the program is already downloaded. We just set its PC and go. */ inferior_pid = pid; /* Needed for wait_for_inferior below */ clear_proceed_status (); /* Tell wait_for_inferior that we've started a new process. */ init_wait_for_inferior (); /* Set up the "saved terminal modes" of the inferior based on what modes we are starting it with. */ target_terminal_init (); /* Install inferior's terminal modes. */ target_terminal_inferior (); /* insert_step_breakpoint (); FIXME, do we need this? */ proceed ((CORE_ADDR)entry_pt, -1, 0); /* Let 'er rip... */}static voidreset_command(args, from_tty) char *args; int from_tty;{ if ( !nindy_fd ){ error( "No target system to reset -- use 'target nindy' command."); } if ( query("Really reset the target system?",0,0) ){ send_break( nindy_fd ); tty_flush( nindy_fd ); }}voidnindy_kill (args, from_tty) char *args; int from_tty;{ return; /* Ignore attempts to kill target system */}/* Clean up when a program exits. The program actually lives on in the remote processor's RAM, and may be run again without a download. Don't leave it full of breakpoint instructions. */voidnindy_mourn_inferior (){ remove_breakpoints (); generic_mourn_inferior (); /* Do all the proper things now */}/* This routine is run as a hook, just before the main command loop is entered. If gdb is configured for the i960, but has not had its nindy target specified yet, this will loop prompting the user to do so. Unlike the loop provided by Intel, we actually let the user get out of this with a RETURN. This is useful when e.g. simply examining an i960 object file on the host system. */nindy_before_main_loop (){ char ttyname[100]; char *p, *p2; setjmp(to_top_level); while (current_target != &nindy_ops) { /* remote tty not specified yet */ if ( instream == stdin ){ printf("\nAttach /dev/ttyNN -- specify NN, or \"quit\" to quit: "); fflush( stdout ); } fgets( ttyname, sizeof(ttyname)-1, stdin ); /* Strip leading and trailing whitespace */ for ( p = ttyname; isspace(*p); p++ ){ ; } if ( *p == '\0' ){ return; /* User just hit spaces or return, wants out */ } for ( p2= p; !isspace(*p2) && (*p2 != '\0'); p2++ ){ ; } *p2= '\0'; if ( !strcmp("quit",p) ){ exit(1); } nindy_open( p, 1 ); /* Now that we have a tty open for talking to the remote machine, download the executable file if one was specified. */ if ( !setjmp(to_top_level) && exec_bfd ) { target_load (bfd_get_filename (exec_bfd), 1); } }}/* Define the target subroutine names */struct target_ops nindy_ops = { "nindy", "Remote serial target in i960 NINDY-specific protocol", "Use a remote i960 system running NINDY connected by a serial line.\n\Specify the name of the device the serial line is connected to.\n\The speed (baud rate), whether to use the old NINDY protocol,\n\and whether to send a break on startup, are controlled by options\n\specified when you started GDB.", nindy_open, nindy_close, 0, nindy_detach, nindy_resume, nindy_wait, nindy_fetch_registers, nindy_store_registers, nindy_prepare_to_store, nindy_xfer_inferior_memory, nindy_files_info, 0, 0, /* insert_breakpoint, remove_breakpoint, */ 0, 0, 0, 0, 0, /* Terminal crud */ nindy_kill, nindy_load, 0, /* lookup_symbol */ nindy_create_inferior, nindy_mourn_inferior, 0, /* can_run */ 0, /* notice_signals */ process_stratum, 0, /* next */ 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ 0, 0, /* Section pointers */ OPS_MAGIC, /* Always the last thing */};void_initialize_nindy (){ add_target (&nindy_ops); add_com ("reset", class_obscure, reset_command, "Send a 'break' to the remote target system.\n\Only useful if the target has been equipped with a circuit\n\to perform a hard reset when a break is detected.");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -