413 lines
11 KiB
C
Executable File
413 lines
11 KiB
C
Executable File
/*******************************************************************************
|
|
' Version 0.54
|
|
' Copyright (c) 2010, 2011, 2012
|
|
' See end of file for terms of use.
|
|
'******************************************************************************/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
#include <dirent.h>
|
|
#include <sys/stat.h>
|
|
#include "conion.h"
|
|
#include "interp.h"
|
|
#include "spinsim.h"
|
|
|
|
#define GCC_REG_BASE 0
|
|
|
|
extern FILE *logfile;
|
|
extern FILE *tracefile;
|
|
extern FILE *cmdfile;
|
|
extern PasmVarsT PasmVars[8];
|
|
extern char *hubram;
|
|
char cmd[1028];
|
|
extern int32_t profile;
|
|
extern int32_t loopcount;
|
|
|
|
void reply(char *ptr, int len){
|
|
unsigned char cksum = 0;
|
|
int i;
|
|
|
|
putc('$', stdout);
|
|
if(logfile) fprintf(logfile, "sim>$");
|
|
for(i = 0; i < len; i++){
|
|
putc(ptr[i], stdout);
|
|
if(logfile) putc(ptr[i], logfile);
|
|
cksum += ptr[i];
|
|
}
|
|
fprintf(stdout, "#%02x", cksum);
|
|
if(logfile) fprintf(logfile, "#%02x", cksum);
|
|
if(logfile) putc('\n', logfile);
|
|
fflush(stdout);
|
|
if(logfile) fflush(logfile);
|
|
}
|
|
|
|
char parse_byte(char *ch){
|
|
char s[3];
|
|
char val;
|
|
s[0] = ch[0];
|
|
s[1] = ch[1];
|
|
s[2] = 0;
|
|
val = 0xff & strtol(s, NULL, 16);
|
|
return val;
|
|
}
|
|
|
|
char get_byte(uint32_t addr){
|
|
if(addr & 0x80000000){
|
|
int cog = (addr >> 28) - 8;
|
|
uint32_t tmp;
|
|
tmp = PasmVars[cog].mem[(addr & 0x000007ff) >> 2];
|
|
return (tmp >> 8*(addr & 0x3)) & 0xff;
|
|
} else {
|
|
return BYTE(addr);
|
|
}
|
|
}
|
|
|
|
void put_byte(uint32_t addr, unsigned char val){
|
|
if(addr & 0x80000000){
|
|
int cog = (addr >> 28) - 8;
|
|
uint32_t tmp;
|
|
tmp = PasmVars[cog].mem[(addr & 0x000007ff) >> 2];
|
|
switch(addr & 3){
|
|
case 0:
|
|
tmp &= 0xffffff00;
|
|
tmp |= val;
|
|
break;
|
|
case 1:
|
|
tmp &= 0xffff00ff;
|
|
tmp |= val << 8;
|
|
break;
|
|
case 2:
|
|
tmp &= 0xff00ffff;
|
|
tmp |= val << 16;
|
|
break;
|
|
case 3:
|
|
tmp &= 0x00ffffff;
|
|
tmp |= val << 24;
|
|
break;
|
|
}
|
|
PasmVars[cog].mem[(addr & 0x000007ff) >> 2] = tmp;
|
|
return;
|
|
} else {
|
|
BYTE(addr) = val;
|
|
return;
|
|
}
|
|
}
|
|
|
|
void get_cmd(){
|
|
int i = 0;
|
|
int ch;
|
|
|
|
do{
|
|
ch = getc(cmdfile);
|
|
} while(ch != '$');
|
|
|
|
if(logfile) fprintf(logfile, "gdb>");
|
|
if(logfile) putc(ch, logfile);
|
|
|
|
for(i = 0; i < sizeof(cmd); i++){
|
|
ch = getc(cmdfile);
|
|
if(logfile) putc(ch, logfile);
|
|
if(ch == '#') break;
|
|
cmd[i] = ch;
|
|
}
|
|
cmd[i] = 0;
|
|
// eat the checksum
|
|
ch = getc(cmdfile);
|
|
if(logfile) putc(ch, logfile);
|
|
ch = getc(cmdfile);
|
|
if(logfile) putc(ch, logfile);
|
|
if(logfile) putc('\n', logfile);
|
|
// send an ACK
|
|
putchar('+');
|
|
fflush(stdout);
|
|
if(logfile) fflush(logfile);
|
|
}
|
|
|
|
int tohex(char x){
|
|
if(x >= '0' && x <= '9') return x - '0';
|
|
if(x >= 'a' && x <= 'f') return 10 + x - 'a';
|
|
if(x >= 'A' && x <= 'F') return 10 + x - 'A';
|
|
return 0;
|
|
}
|
|
|
|
int32_t get_addr(int *i){
|
|
int32_t reg;
|
|
reg = tohex(cmd[(*i)++]) << 4;
|
|
reg |= tohex(cmd[(*i)++]) << 0;
|
|
reg |= tohex(cmd[(*i)++]) << 12;
|
|
reg |= tohex(cmd[(*i)++]) << 8;
|
|
reg |= tohex(cmd[(*i)++]) << 20;
|
|
reg |= tohex(cmd[(*i)++]) << 16;
|
|
reg |= tohex(cmd[(*i)++]) << 28;
|
|
reg |= tohex(cmd[(*i)++]) << 24;
|
|
return reg;
|
|
}
|
|
|
|
struct bkpt {
|
|
struct bkpt *next;
|
|
uint32_t addr;
|
|
uint32_t len;
|
|
};
|
|
|
|
struct bkpt *bkpt = 0;
|
|
|
|
// Check the cog's PC to see if the LMM microcode is at an appropriate place
|
|
// for a breakpoint to occur. We don't want to break on LMM administrative
|
|
// instructions.
|
|
// FIXME we need a more general way to do this. This is too dependent on special knowledge.
|
|
int breakable_point(int i){
|
|
int32_t pc = PasmVars[i].pc;
|
|
if ((pc == 0x0000004c/4)
|
|
|| (pc == 0x00000058/4)
|
|
|| (pc == 0x00000064/4)
|
|
|| (pc == 0x00000070/4)
|
|
|| (pc == 0x0000007c/4)
|
|
|| (pc == 0x00000088/4)
|
|
|| (pc == 0x00000094/4)
|
|
|| (pc == 0x000000a0/4))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void gdb(void)
|
|
{
|
|
int i;
|
|
int j;
|
|
char response[1024];
|
|
unsigned int addr;
|
|
int len;
|
|
char *end;
|
|
char val;
|
|
int32_t reg;
|
|
int cog = 0;
|
|
char *halt_code = "S05";
|
|
|
|
if(logfile) fprintf(logfile, "\n\nStarting log:\n");
|
|
|
|
RebootProp();
|
|
|
|
for(;;){
|
|
get_cmd();
|
|
i = 0;
|
|
switch(cmd[i++]){
|
|
case 'g':
|
|
for(i = 0; i < 18; i++){
|
|
reg = PasmVars[cog].mem[GCC_REG_BASE + i];
|
|
sprintf(response+8*i,
|
|
"%02x%02x%02x%02x",
|
|
(unsigned char)(reg & 0xff),
|
|
(unsigned char)((reg>>8) & 0xff),
|
|
(unsigned char)((reg>>16) & 0xff),
|
|
(unsigned char)((reg>>24) & 0xff));
|
|
}
|
|
reg = PasmVars[cog].pc * 4 + 0x80000000 + cog * 0x10000000;
|
|
sprintf(response+8*i,
|
|
"%02x%02x%02x%02x",
|
|
(unsigned char)(reg & 0xff),
|
|
(unsigned char)((reg>>8) & 0xff),
|
|
(unsigned char)((reg>>16) & 0xff),
|
|
(unsigned char)((reg>>24) & 0xff));
|
|
reply(response, 8*18+8);
|
|
break;
|
|
|
|
case 'G':
|
|
for(j = 0; j < 18; j++){
|
|
PasmVars[cog].mem[GCC_REG_BASE + j] = get_addr(&i);
|
|
}
|
|
// Ignore writes to cog pc. Instead, reset it to be
|
|
// ready for a fresh instruction.
|
|
// This is too magical. How do we fix it?
|
|
PasmVars[cog].pc = 0x12;
|
|
reply("OK",2);
|
|
break;
|
|
|
|
case 'm':
|
|
addr = strtol(&cmd[i], &end, 16);
|
|
i = (size_t)end - (size_t)cmd;
|
|
i++;
|
|
len = strtol(&cmd[i], NULL, 16);
|
|
if(len > 512) len = 512;
|
|
j = 0;
|
|
while(len--){
|
|
val = get_byte(addr);
|
|
addr++;
|
|
sprintf(&response[j], "%02x", (unsigned char)val);
|
|
j += 2;
|
|
}
|
|
reply(response, j);
|
|
break;
|
|
|
|
case 'M':
|
|
addr = strtol(&cmd[i], &end, 16);
|
|
i = (size_t)end - (size_t)cmd;
|
|
i++;
|
|
len = strtol(&cmd[i], &end, 16);
|
|
i = (size_t)end - (size_t)cmd;
|
|
i++;
|
|
while(len--){
|
|
val = parse_byte(&cmd[i]);
|
|
i += 2;
|
|
put_byte(addr, val & 0xff);
|
|
addr++;
|
|
}
|
|
reply("OK",2);
|
|
break;
|
|
|
|
case 's':
|
|
if(cmd[i]){
|
|
// Get the new LMM PC, reset the microcode
|
|
PasmVars[cog].mem[GCC_REG_BASE + 17] = get_addr(&i);
|
|
PasmVars[cog].pc = 0x12;
|
|
}
|
|
{
|
|
int brk = 0;
|
|
do {
|
|
int i;
|
|
// Step through a full LMM instruction
|
|
step_chip();
|
|
for(i = 0; i < 8; i++){
|
|
if(breakable_point(i)) brk = 1;
|
|
}
|
|
} while (!brk);
|
|
}
|
|
halt_code = "S05";
|
|
reply(halt_code, 3);
|
|
break;
|
|
|
|
case 'c':
|
|
if(cmd[i]){
|
|
PasmVars[cog].mem[GCC_REG_BASE + 17] = get_addr(&i);
|
|
PasmVars[cog].pc = 0x12;
|
|
}
|
|
halt_code = "S02";
|
|
do {
|
|
int brk = 0;
|
|
struct bkpt *b;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
if(breakable_point(i)){
|
|
// Look to see if the cog's LMM PC is at a breakpoint
|
|
for(b = (struct bkpt *)&bkpt; b->next; b = b->next){
|
|
if((PasmVars[i].mem[GCC_REG_BASE + 17] >= b->next->addr)
|
|
&& (PasmVars[i].mem[GCC_REG_BASE + 17] <= b->next->addr + b->next->len)){
|
|
brk = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(brk){
|
|
halt_code = "S05";
|
|
break;
|
|
} else {
|
|
step_chip();
|
|
}
|
|
} while(getch() != 0x03); // look for a CTRL-C
|
|
reply(halt_code, 3);
|
|
break;
|
|
|
|
case 'H':
|
|
if((cmd[i] == 'g') && (cmd[i+1] == '0')){
|
|
reply("OK", 2);
|
|
} else {
|
|
reply("", 0);
|
|
}
|
|
break;
|
|
|
|
case 'k':
|
|
reply("OK", 2);
|
|
goto out;
|
|
|
|
case 'z':
|
|
/* Remove breakpoint */
|
|
if(cmd[i++] == '0'){
|
|
long addr;
|
|
long len;
|
|
struct bkpt *b;
|
|
char *p = &cmd[i];
|
|
|
|
p++; /* Skip the comma */
|
|
addr = strtol(p, &p, 16);
|
|
p++; /* Skip the other comma */
|
|
len = strtol(p, NULL, 16);
|
|
for(b = (struct bkpt *)&bkpt; b && b->next; b = b->next){
|
|
if((b->next->addr == addr) && (b->next->len == len)){
|
|
struct bkpt *t = b->next;
|
|
b->next = t->next;
|
|
free(t);
|
|
}
|
|
}
|
|
reply("OK", 2);
|
|
} else {
|
|
reply("", 0);
|
|
}
|
|
break;
|
|
|
|
case 'Z':
|
|
/* Set breakpoint */
|
|
if(cmd[i++] == '0'){
|
|
long addr;
|
|
long len;
|
|
struct bkpt *b;
|
|
char *p = &cmd[i];
|
|
p++; /* Skip the comma */
|
|
addr = strtol(p, &p, 16);
|
|
p++; /* Skip the other comma */
|
|
len = strtol(p, NULL, 16);
|
|
for(b = (struct bkpt *)&bkpt; b->next; b = b->next){
|
|
if((b->addr == addr) && (b->len == len)){
|
|
/* Duplicate; bail out */
|
|
break;
|
|
}
|
|
}
|
|
if(b->next){
|
|
/* Was a duplicate, do nothing */
|
|
} else {
|
|
struct bkpt *t = (struct bkpt *)malloc(sizeof(struct bkpt));
|
|
if(!t){
|
|
fprintf(stderr, "Failed to allocate a breakpoint structure\n");
|
|
spinsim_exit(1);
|
|
}
|
|
t->addr = addr;
|
|
t->len = len;
|
|
t->next = bkpt;
|
|
bkpt = t;
|
|
}
|
|
reply("OK", 2);
|
|
} else {
|
|
reply("", 0);
|
|
}
|
|
break;
|
|
|
|
case '?':
|
|
reply(halt_code, 3);
|
|
break;
|
|
|
|
default:
|
|
reply("", 0);
|
|
break;
|
|
}
|
|
}
|
|
out:
|
|
;
|
|
}
|
|
/*
|
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|
| TERMS OF USE: MIT License |
|
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|
|Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation |
|
|
|files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, |
|
|
|modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software|
|
|
|is furnished to do so, subject to the following conditions: |
|
|
| |
|
|
|The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.|
|
|
| |
|
|
|THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
|
|
|WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
|
|
|COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
|
|
|ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|
*/
|