1139749Simp/* This file is part of SIS (SPARC instruction simulator)
274429Sorion
374429Sorion   Copyright (C) 1995-2023 Free Software Foundation, Inc.
474429Sorion   Contributed by Jiri Gaisler, European Space Agency
574429Sorion
674429Sorion   This program is free software; you can redistribute it and/or modify
774429Sorion   it under the terms of the GNU General Public License as published by
874429Sorion   the Free Software Foundation; either version 3 of the License, or
974429Sorion   (at your option) any later version.
1074429Sorion
1174429Sorion   This program is distributed in the hope that it will be useful,
1274429Sorion   but WITHOUT ANY WARRANTY; without even the implied warranty of
1374429Sorion   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1474429Sorion   GNU General Public License for more details.
1574429Sorion
1674429Sorion   You should have received a copy of the GNU General Public License
1774429Sorion   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1874429Sorion
1974429Sorion/* This must come before any other includes.  */
2074429Sorion#include "defs.h"
2174429Sorion
2274429Sorion#include <signal.h>
2374429Sorion#include <string.h>
2474429Sorion#include <stdlib.h>
25192919Sjoel#include <stdio.h>
26192919Sjoel#include <sys/fcntl.h>
27192919Sjoel#include "sis.h"
2874429Sorion#include <dis-asm.h>
2974429Sorion#include "sim-config.h"
3074429Sorion#include <inttypes.h>
3182180Scg
3274429Sorion#define	VAL(x)	strtol(x,(char **)NULL,0)
33193640Sariff
34193640Sariff/* Structures and functions from readline library */
35193640Sariff
36193640Sariff#include "readline/readline.h"
3774429Sorion#include "readline/history.h"
3874429Sorion
3974429Sorion/* Command history buffer length - MUST be binary */
40119287Simp#define HIST_LEN	64
41119287Simp
4274429Sorionextern struct disassemble_info dinfo;
4374429Sorionextern struct pstate sregs;
4474429Sorionextern struct estate ebase;
4582180Scg
4682180Scgextern int      ctrl_c;
4774429Sorionextern int      nfp;
4874429Sorionextern int      ift;
4974429Sorionextern int      wrp;
5074429Sorionextern int      rom8;
5184771Sorionextern int      uben;
5284771Sorionextern int      sis_verbose;
5374429Sorionextern char    *sis_version;
5474429Sorionextern struct estate ebase;
5574429Sorionextern struct evcell evbuf[];
5674429Sorionextern struct irqcell irqarr[];
5774429Sorionextern int      irqpend, ext_irl;
5874429Sorionextern int      termsave;
5974429Sorionextern int      sparclite;
6074429Sorionextern int      dumbio;
6174429Sorionextern char     uart_dev1[];
6274429Sorionextern char     uart_dev2[];
6374429Sorionextern uint32_t   last_load_addr;
6474429Sorion
6574429Sorion#ifdef ERA
6674763Scgextern int era;
6774763Scg#endif
6874571Sorion
6974429Sorionint
7074429Sorionrun_sim(struct pstate *sregs, uint64_t icount, int dis)
7174429Sorion{
7274429Sorion    int             irq, mexc, deb;
7374429Sorion
7474429Sorion    sregs->starttime = get_time();
7574429Sorion    init_stdio();
7674429Sorion    if (sregs->err_mode) icount = 0;
7774429Sorion    deb = dis || sregs->histlen || sregs->bptnum;
7874429Sorion    irq = 0;
7974429Sorion    while (icount > 0) {
8074429Sorion
8174429Sorion	mexc = memory_iread (sregs->pc, &sregs->inst, &sregs->hold);
8274429Sorion	sregs->icnt = 1;
8374429Sorion	if (sregs->annul) {
8474429Sorion	    sregs->annul = 0;
8574429Sorion	    sregs->pc = sregs->npc;
8674429Sorion	    sregs->npc = sregs->npc + 4;
8774429Sorion	} else {
8874429Sorion	    sregs->fhold = 0;
8974429Sorion	    if (ext_irl) irq = check_interrupts(sregs);
9074429Sorion	    if (!irq) {
9174429Sorion		if (mexc) {
9274429Sorion		    sregs->trap = I_ACC_EXC;
9374429Sorion		} else {
9474429Sorion		    if (deb) {
9574429Sorion	    		if ((sregs->bphit = check_bpt(sregs)) != 0) {
9674429Sorion            		    restore_stdio();
9774429Sorion	    		    return BPT_HIT;
9884771Sorion	    		}
9984771Sorion		        if (sregs->histlen) {
10084771Sorion			    sregs->histbuf[sregs->histind].addr = sregs->pc;
10174429Sorion			    sregs->histbuf[sregs->histind].time = ebase.simtime;
10274429Sorion			    sregs->histind++;
10374429Sorion			    if (sregs->histind >= sregs->histlen)
10474429Sorion			        sregs->histind = 0;
10574429Sorion		        }
106193640Sariff		        if (dis) {
107193640Sariff			    printf(" %8" PRIu64 " ", ebase.simtime);
108193640Sariff			    dis_mem(sregs->pc, 1, &dinfo);
109193640Sariff		        }
11074429Sorion		    }
11174429Sorion		    dispatch_instruction(sregs);
11274429Sorion		    icount--;
11374763Scg		}
11474429Sorion	    }
11574429Sorion	    if (sregs->trap) {
11674429Sorion		irq = 0;
11774429Sorion		sregs->err_mode = execute_trap(sregs);
11874429Sorion        	if (sregs->err_mode) {
11974429Sorion	            error_mode(sregs->pc);
12074429Sorion	            icount = 0;
12174797Scg	        }
12274429Sorion	    }
12374429Sorion	}
12474429Sorion	advance_time(sregs);
12574429Sorion	if (ctrl_c || (sregs->tlimit <= ebase.simtime)) {
12674429Sorion	    icount = 0;
12774797Scg	    if (sregs->tlimit <= ebase.simtime) sregs->tlimit = -1;
12874429Sorion	}
12974429Sorion    }
13074429Sorion    sregs->tottime += get_time() - sregs->starttime;
13174429Sorion    restore_stdio();
13274429Sorion    if (sregs->err_mode)
13374429Sorion	return ERROR;
13474429Sorion    if (ctrl_c) {
13574429Sorion	ctrl_c = 0;
13674429Sorion	return CTRL_C;
13774429Sorion    }
13874429Sorion    return TIME_OUT;
13974797Scg}
14074429Sorion
14174797Scgstatic int ATTRIBUTE_PRINTF (3, 4)
14274429Sorionfprintf_styled (void *stream, enum disassembler_style style,
14374429Sorion		const char *fmt, ...)
14474429Sorion{
14574429Sorion  int ret;
14674429Sorion  FILE *out = (FILE *) stream;
14774429Sorion  va_list args;
14874429Sorion
14974429Sorion  va_start (args, fmt);
15074429Sorion  ret = vfprintf (out, fmt, args);
15174797Scg  va_end (args);
15274429Sorion
15374797Scg  return ret;
15474429Sorion}
15574429Sorion
15674429Sorionint
15774429Sorionmain(int argc, char **argv)
15874429Sorion{
15974429Sorion
16074429Sorion    int             cont = 1;
16174429Sorion    int             stat = 1;
16274429Sorion    int             freq = 14;
16374429Sorion    int             copt = 0;
16474429Sorion
16574429Sorion    char           *cfile, *bacmd;
16674429Sorion    char           *cmdq[HIST_LEN];
16774429Sorion    int             cmdi = 0;
16874429Sorion    int             i;
16974797Scg    int             lfile = 0;
17074797Scg
17174429Sorion    cfile = 0;
17274429Sorion    for (i = 0; i < 64; i++)
17374429Sorion	cmdq[i] = 0;
17474429Sorion    printf("\n SIS - SPARC instruction simulator %s,  copyright Jiri Gaisler 1995\n", sis_version);
17574429Sorion    printf(" Bug-reports to jgais@wd.estec.esa.nl\n\n");
17674429Sorion    while (stat < argc) {
17774429Sorion	if (argv[stat][0] == '-') {
17874429Sorion	    if (strcmp(argv[stat], "-v") == 0) {
17974429Sorion		sis_verbose += 1;
18074429Sorion	    } else if (strcmp(argv[stat], "-c") == 0) {
18174429Sorion		if ((stat + 1) < argc) {
18274429Sorion		    copt = 1;
18374429Sorion		    cfile = argv[++stat];
18474429Sorion		}
18574429Sorion	    } else if (strcmp(argv[stat], "-nfp") == 0)
18674429Sorion		nfp = 1;
18774429Sorion	    else if (strcmp(argv[stat], "-ift") == 0)
18874429Sorion		ift = 1;
18974429Sorion	    else if (strcmp(argv[stat], "-wrp") == 0)
19074429Sorion		wrp = 1;
19174763Scg	    else if (strcmp(argv[stat], "-rom8") == 0)
19274429Sorion		rom8 = 1;
19374429Sorion	    else if (strcmp(argv[stat], "-uben") == 0)
19474429Sorion		uben = 1;
19574797Scg	    else if (strcmp(argv[stat], "-uart1") == 0) {
19674429Sorion		if ((stat + 1) < argc)
19774429Sorion		    strcpy(uart_dev1, argv[++stat]);
19874429Sorion	    } else if (strcmp(argv[stat], "-uart2") == 0) {
19974429Sorion		if ((stat + 1) < argc)
20074429Sorion		    strcpy(uart_dev2, argv[++stat]);
201168847Sariff	    } else if (strcmp(argv[stat], "-freq") == 0) {
20274429Sorion		if ((stat + 1) < argc)
20374429Sorion		    freq = VAL(argv[++stat]);
20474429Sorion	    } else if (strcmp(argv[stat], "-sparclite") == 0) {
20574429Sorion		sparclite = 1;
206193640Sariff#ifdef ERA
20774429Sorion	    } else if (strcmp(argv[stat], "-era") == 0) {
20874429Sorion		era = 1;
20974429Sorion#endif
21074429Sorion            } else if (strcmp(argv[stat], "-dumbio") == 0) {
21174429Sorion		dumbio = 1;
21274429Sorion	    } else {
21374763Scg		printf("unknown option %s\n", argv[stat]);
21474429Sorion		usage();
21574429Sorion		exit(1);
21674429Sorion	    }
21774429Sorion	} else {
21874429Sorion	    lfile = stat;
219193640Sariff	}
22074429Sorion	stat++;
22174429Sorion    }
22274429Sorion    if (nfp)
22384771Sorion	printf("FPU disabled\n");
22474429Sorion#ifdef ERA
22574429Sorion    if (era)
22684771Sorion	printf("ERA ECC emulation enabled\n");
22774429Sorion#endif
22874429Sorion    sregs.freq = freq;
22982835Sorion
23074429Sorion    INIT_DISASSEMBLE_INFO(dinfo, stdout, (fprintf_ftype) fprintf,
23174429Sorion			  (fprintf_styled_ftype) fprintf_styled);
23274429Sorion#ifdef HOST_LITTLE_ENDIAN
23374429Sorion    dinfo.endian = BFD_ENDIAN_LITTLE;
23474429Sorion#else
23574429Sorion    dinfo.endian = BFD_ENDIAN_BIG;
23674429Sorion#endif
23774429Sorion
238193640Sariff#ifdef F_GETFL
23974429Sorion    termsave = fcntl(0, F_GETFL, 0);
24074429Sorion#endif
24174429Sorion    using_history();
24274429Sorion    init_signals();
243193640Sariff    ebase.simtime = 0;
24474429Sorion    reset_all();
24574429Sorion    init_bpt(&sregs);
24674429Sorion    init_sim();
24774429Sorion    if (lfile)
24874429Sorion        last_load_addr = bfd_load(argv[lfile]);
24974429Sorion#ifdef STAT
25074429Sorion    reset_stat(&sregs);
25174429Sorion#endif
25274429Sorion
25374429Sorion    if (copt) {
25474429Sorion	bacmd = (char *) malloc(256);
25574797Scg	strcpy(bacmd, "batch ");
25674429Sorion	strcat(bacmd, cfile);
25774429Sorion	exec_cmd(&sregs, bacmd);
25874429Sorion    }
25974429Sorion    while (cont) {
26074429Sorion
26174429Sorion	if (cmdq[cmdi] != 0) {
26274429Sorion#if 0
26374429Sorion	    remove_history(cmdq[cmdi]);
26474429Sorion#else
26574429Sorion	    remove_history(cmdi);
26674429Sorion#endif
26774429Sorion	    free(cmdq[cmdi]);
26874429Sorion	    cmdq[cmdi] = 0;
26974429Sorion	}
27074429Sorion	cmdq[cmdi] = readline("sis> ");
27174429Sorion	if (cmdq[cmdi] && *cmdq[cmdi])
27274429Sorion	    add_history(cmdq[cmdi]);
27374429Sorion	if (cmdq[cmdi])
27474429Sorion	    stat = exec_cmd(&sregs, cmdq[cmdi]);
27574429Sorion	else {
27674429Sorion	    puts("\n");
27774429Sorion	    exit(0);
27874429Sorion	}
27974429Sorion	switch (stat) {
28074797Scg	case OK:
28174429Sorion	    break;
28274429Sorion	case CTRL_C:
28374429Sorion	    printf("\b\bInterrupt!\n");
28474429Sorion	case TIME_OUT:
28574797Scg	    printf(" Stopped at time %" PRIu64 " (%.3f ms)\n", ebase.simtime,
28674429Sorion	      ((double) ebase.simtime / (double) sregs.freq) / 1000.0);
28774429Sorion	    break;
28874429Sorion	case BPT_HIT:
28974429Sorion	    printf("breakpoint at 0x%08x reached\n", sregs.pc);
29074429Sorion	    sregs.bphit = 1;
29174429Sorion	    break;
29274429Sorion	case ERROR:
29374429Sorion	    printf("IU in error mode (%d)\n", sregs.trap);
29474429Sorion	    stat = 0;
29574429Sorion	    printf(" %8" PRIu64 " ", ebase.simtime);
29674429Sorion	    dis_mem(sregs.pc, 1, &dinfo);
29774429Sorion	    break;
29874429Sorion	default:
29974429Sorion	    break;
30074429Sorion	}
30174429Sorion	ctrl_c = 0;
30274429Sorion	stat = OK;
30374797Scg
30474429Sorion	cmdi = (cmdi + 1) & (HIST_LEN - 1);
30574429Sorion
30674429Sorion    }
30774429Sorion    return 0;
30874429Sorion}
30974429Sorion
31074429Sorion