📄 sim.c
字号:
/*
* sim.c -- xr16 simulator
*
* Copyright (C) 1999, 2000, Gray Research LLC. All rights reserved.
* The contents of this file are subject to the XSOC License Agreement;
* you may not use this file except in compliance with this Agreement.
* See the LICENSE file.
*
* $Log: /dist/src/xr16/sim.c $
*
* 3 4/06/00 11:54a Jan
* implement bv bnv bc bnc
*
* 2 3/04/00 9:44a Jan
* getting automatic rebuild to work
* applying proper rcsids
*
* 1 3/02/00 8:36p Jan
*
* tabs=4
*/
static char rcsid[] =
"$Header: /dist/src/xr16/sim.c 3 4/06/00 11:54a Jan $\n"
"Copyright (C) 1999,2000, Gray Research LLC. All rights reserved.\n"
"This program is subject to the XSOC License Agreement.\n"
"See the LICENSE file.";
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <memory.h>
#include "xr16.h"
#include "xr16sim.h"
#define TRACE(p) ((p).trace)
#define TR_INSN(p) ((p).trace & trInsn)
#define TR_MEM(p) ((p).trace & trMem)
#define TR_CALL(p) ((p).trace & trCall)
#define SIGNED(a) ((int)(short)(a))
/* eval sign-extended immediate operand */
#define SEXT_IMM(p, insn) \
((p).imm_prefix ? ((Word)((p).insnPrev << 4) | IMM(insn)) : IMM_SEXT(insn))
/* eval 0-extended word offset (scale 2X) immediate operand */
#define WORD_IMM(p, insn) \
((p).imm_prefix ? ((Word)((p).insnPrev << 4) | IMM(insn)) : IMM_WORD(insn))
/* eval 0-extended byte offset immediate operand */
#define BYTE_IMM(p, insn) \
((p).imm_prefix ? ((Word)((p).insnPrev << 4) | IMM(insn)) : IMM(insn))
/* eval word effective address imm(ra) */
#define WORD_EA(p, insn) \
((Word)((p).r[RA(insn)] + WORD_IMM((p), (insn))))
/* eval byte effective address imm(ra) */
#define BYTE_EA(p, insn) \
((Word)((p).r[RA(insn)] + BYTE_IMM((p), (insn))))
#define SIGN(w) ((w)&0x8000)
#define BIT(i) (1<<(i))
enum {
bitopResult = BIT(OP_ADD) | BIT(OP_SUB) | BIT(OP_ADDI) | BIT(OP_RR) |
BIT(OP_RI) | BIT(OP_LW) | BIT(OP_LB) | BIT(OP_JAL) |
BIT(OP_CALL),
bitopCall = BIT(OP_CALL) | BIT(OP_JAL),
};
enum {
cbAddr = 13, /* length of symbolic address display */
cbInsn = 19 /* length of instruction dissambly display */
};
Word fetchInsn(Addr addr);
Word loadWord(XR16* p, Addr addr);
Word loadByte(XR16* p, Addr addr);
void storeWord(XR16* p, Addr addr, Word w);
void storeByte(XR16* p, Addr addr, Word w);
void trap(XR16* p, int n);
void nyi();
void invalidOpcode();
void notreached();
void invalidseq();
/* Return processor state following reset.
*
* Args
* trace - initial trace flags
*/
XR16 reset(Word trace)
{
XR16 p;
memset(&p, 0, sizeof p);
p.trace = trace;
return p;
}
/* Simulate one or more instructions. Return updated processor state.
*
* Args
* p - initial processor state
* cinsns - count of instructions to step through, or -1 to run until pc==0
*
* Also trace instruction execution according to p.trace.
*/
XR16 sim(XR16 p, int cinsns)
{
while (cinsns == -1 || --cinsns >= 0) {
Insn insn = fetchInsn(p.pc);
Word* prd = &p.r[RD(insn)];
char szAddr[cbAddr];
++p.insns;
++p.cycles;
if (TRACE(p) && (TR_INSN(p) || (TR_CALL(p) && (BIT(OP(insn))&bitopCall)))) {
char szInsn[19];
szForAddr(szAddr, sizeof szAddr, p.pc);
szForInsn(szInsn, sizeof szInsn, p.pc, insn);
printf("%7d %04X %-12.12s %04X %-17s", p.cycles, p.pc, szAddr, insn, szInsn);
}
p.pc += 2;
switch (OP(insn)) {
case OP_ADD:
p.a = p.r[RA(insn)];
p.b = p.r[RB(insn)];
*prd = p.a + p.b;
break;
case OP_SUB:
p.a = p.r[RA(insn)];
p.b = -p.r[RB(insn)];
*prd = p.a + p.b;
break;
case OP_ADDI:
p.a = p.r[RA(insn)];
p.b = SEXT_IMM(p, insn);
*prd = p.a + p.b;
break;
case OP_RR:
switch (FN(insn)) {
case FN_AND:
*prd &= p.r[RB(insn)];
break;
case FN_OR:
*prd |= p.r[RB(insn)];
break;
case FN_XOR:
*prd ^= p.r[RB(insn)];
break;
case FN_ANDN:
*prd &= ~p.r[RB(insn)];
break;
case FN_ADC:
p.a = *prd;
p.b = p.r[RB(insn)];
nyi();
*prd = p.a + p.b + p.c;
break;
case FN_SBC:
p.a = *prd;
p.b = -p.r[RB(insn)];
nyi();
*prd = p.a + p.b - p.c;
break;
default:
invalidOpcode();
}
break;
case OP_RI:
switch (FN(insn)) {
case FN_AND:
*prd = *prd & SEXT_IMM(p, insn);
break;
case FN_OR:
*prd = *prd | SEXT_IMM(p, insn);
break;
case FN_XOR:
*prd = *prd ^ SEXT_IMM(p, insn);
break;
case FN_ANDN:
*prd = *prd & ~SEXT_IMM(p, insn);
break;
case FN_ADC:
p.a = *prd;
p.b = SEXT_IMM(p, insn);
nyi();
*prd = p.a + p.b + p.c;
break;
case FN_SBC:
p.a = *prd;
p.b = -SEXT_IMM(p, insn);
nyi();
*prd = p.a + p.b - p.c;
break;
case FN_SLL:
p.x = !!(*prd & 0x8000);
*prd <<= 1;
break;
case FN_SLX: {
int x = !!(*prd & 0x8000);
*prd = (*prd << 1) | p.x;
p.x = x;
break;
}
case FN_SRA:
p.x = *prd & 1;
*prd = (short)*prd >> 1;
break;
case FN_SRL:
p.x = *prd & 1;
*prd >>= 1;
break;
case FN_SRX: {
int x = *prd & 1;
*prd = (p.x << 15) | (*prd >> 1);
p.x = x;
break;
}
default:
invalidOpcode();
}
break;
case OP_LW:
*prd = loadWord(&p, WORD_EA(p, insn));
break;
case OP_LB:
*prd = loadByte(&p, BYTE_EA(p, insn));
break;
case OP_SW:
storeWord(&p, WORD_EA(p, insn), *prd);
break;
case OP_SB:
storeByte(&p, BYTE_EA(p, insn), *prd);
break;
case OP_JAL: {
Word target = WORD_EA(p, insn);
*prd = p.pc;
p.pc = target;
p.cycles += 2;
if (TRACE(p)) {
if (TR_INSN(p) || TR_CALL(p))
szForAddr(szAddr, sizeof szAddr, p.pc);
if (TR_CALL(p) && RD(insn) == 15)
printf(" call %s %d %d %d", szAddr, (short)p.r[3], (short)p.r[4], (short)p.r[5]);
else if (TR_CALL(p) && RD(insn) == 0 && RA(insn) == 15)
printf(" ret %s %d", szAddr, (short)p.r[2]);
else if (TR_INSN(p) || TR_CALL(p))
printf(" pc=%s", szAddr);
}
break;
}
case OP_BR: {
Bool t;
Word sum;
switch (COND(insn) & ~1) {
case BR_BR:
t = TRUE;
break;
case BR_BEQ:
t = p.a == (Word)-p.b;
break;
case BR_BC:
sum = p.a + p.b;
t = sum < p.a || sum < p.b;
break;
case BR_BV:
sum = p.a + p.b;
t = SIGN(p.a) == SIGN(p.b) && SIGN(p.a) != SIGN(sum);
break;
case BR_BLT:
t = SIGNED(p.a) < SIGNED(-p.b);
break;
case BR_BLE:
t = SIGNED(p.a) <= SIGNED(-p.b);
break;
case BR_BLTU:
t = p.a < (Word)-p.b;
break;
case BR_BLEU:
t = p.a <= (Word)-p.b;
break;
}
if (t != (COND(insn) & 1)) {
p.pc += 2*DISP(insn) + 2;
p.cycles += 2;
if (TR_INSN(p))
printf(" pc=%s", szForAddr(szAddr, sizeof szAddr, p.pc));
}
break;
}
case OP_CALL:
prd = &p.r[15];
*prd = p.pc;
p.pc = IMM12(insn) << 4;
p.cycles += 2;
if (TRACE(p)) {
if (TR_INSN(p) || TR_CALL(p))
szForAddr(szAddr, sizeof szAddr, p.pc);
if (TR_CALL(p))
printf(" call %s %d %d %d", szAddr, (short)p.r[3], (short)p.r[4], (short)p.r[5]);
else if (TR_INSN(p))
printf(" pc=%s", szAddr);
}
break;
case OP_IMM:
break;
case OP_TRAP:
trap(&p, IMM12(insn));
break;
default:
invalidOpcode();
break;
}
p.imm_prefix = OP(insn) == OP_IMM;
p.insnPrev = insn;
p.r[0] = 0; /* cheaper to forgive writes to r0 than to guard them */
if (TRACE(p) && (TR_INSN(p) || (TR_CALL(p) && (BIT(OP(insn))&bitopCall)))) {
if ((BIT(OP(insn)) & bitopResult) && prd != &p.r[0])
printf(" r%d=%d", prd - p.r, (short)*prd);
printf("\n");
}
if (!p.pc)
break;
}
return p;
}
/* Memory abstraction: big-endian word, byte put/get functions */
/* Fetch instruction word at addr. */
Word fetchInsn(Addr addr)
{
return (rgb[addr] << 8) | rgb[addr+1];
}
/* Fetch word at addr. */
Word loadWord(XR16* p, Addr addr)
{
char szAddr[cbAddr];
if (TR_MEM(*p))
printf(" %04X=[%s]", (rgb[addr] << 8) | rgb[addr+1], szForAddr(szAddr, sizeof szAddr, addr));
p->cycles++;
return (rgb[addr] << 8) | rgb[addr+1];
}
/* Fetch byte at addr. */
Word loadByte(XR16* p, Addr addr)
{
char szAddr[cbAddr];
if (TR_MEM(*p))
printf(" %02X=[%04X]", rgb[addr], szForAddr(szAddr, sizeof szAddr, addr));
p->cycles++;
return rgb[addr];
}
/* Store word at addr. */
void storeWord(XR16* p, Addr addr, Word w)
{
char szAddr[cbAddr];
if (TR_MEM(*p))
printf(" [%s]=%04X", szForAddr(szAddr, sizeof szAddr, addr), w);
rgb[addr] = w >> 8;
rgb[addr+1] = (Byte)w;
p->cycles++;
}
/* Store byte at addr. */
void storeByte(XR16* p, Addr addr, Word w)
{
char szAddr[cbAddr];
if (TR_MEM(*p))
printf(" [%s]=%02X", szForAddr(szAddr, sizeof szAddr, addr), (Byte)w);
p->cycles++;
rgb[addr] = (Byte)w;
}
/* Execute a trap instruction. */
void trap(XR16* p, int n)
{
switch (n) {
case 0: /* puts */
printf("%s", rgb + p->r[3]);
break;
default:
printf("trap %d?\n", n);
break;
}
}
/* Report invalid opcode. */
void invalidOpcode()
{
assert(0);
}
/* Report invalid sequence of instructions. */
void invalidseq()
{
assert(0);
}
/* Highlight code that should not be reached. */
void notreached()
{
assert(0);
}
/* Highlight Not Yet Implemented functionality. */
void nyi()
{
assert(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -