mspdebug/sim.c

604 lines
14 KiB
C
Raw Normal View History

/* MSPDebug - debugging tool for the eZ430
* Copyright (C) 2009, 2010 Daniel Beer
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "device.h"
2010-03-20 02:17:33 +00:00
#include "dis.h"
#include "util.h"
#include "output.h"
2010-04-30 04:01:03 +00:00
#include "sim.h"
#define MEM_SIZE 65536
#define MEM_IO_END 0x200
2010-04-30 04:01:03 +00:00
struct sim_device {
struct device base;
2010-04-30 04:01:03 +00:00
sim_fetch_func_t fetch_func;
sim_store_func_t store_func;
void *user_data;
2010-04-10 02:56:29 +00:00
uint8_t memory[MEM_SIZE];
uint16_t regs[DEVICE_NUM_REGS];
2010-04-30 04:01:03 +00:00
int running;
uint16_t current_insn;
2010-04-30 04:01:03 +00:00
};
2010-04-30 04:01:03 +00:00
#define MEM_GETB(dev, offset) ((dev)->memory[offset])
#define MEM_SETB(dev, offset, value) ((dev)->memory[offset] = (value))
#define MEM_GETW(dev, offset) \
((dev)->memory[offset] | \
((dev)->memory[(offset + 1) & 0xffff] << 8))
#define MEM_SETW(dev, offset, value) \
do { \
(dev)->memory[offset] = (value) & 0xff; \
(dev)->memory[(offset + 1) & 0xffff] = (value) >> 8; \
} while (0);
2010-04-30 04:01:03 +00:00
static int fetch_operand(struct sim_device *dev,
int amode, int reg, int is_byte,
2010-05-13 00:57:21 +00:00
uint16_t *addr_ret, uint32_t *data_ret)
2010-03-20 02:17:33 +00:00
{
2010-05-13 00:57:21 +00:00
uint16_t addr = 0;
uint32_t mask = is_byte ? 0xff : 0xffff;
2010-03-20 02:17:33 +00:00
switch (amode) {
case MSP430_AMODE_REGISTER:
if (reg == MSP430_REG_R3) {
if (data_ret)
*data_ret = 0;
2010-03-22 21:40:57 +00:00
return 0;
}
if (data_ret)
2010-04-30 04:01:03 +00:00
*data_ret = dev->regs[reg] & mask;
2010-03-22 21:40:57 +00:00
return 0;
2010-03-20 02:17:33 +00:00
case MSP430_AMODE_INDEXED:
if (reg == MSP430_REG_R3) {
if (data_ret)
*data_ret = 1;
2010-03-22 21:40:57 +00:00
return 0;
}
2010-03-20 02:17:33 +00:00
2010-04-30 04:01:03 +00:00
addr = MEM_GETW(dev, dev->regs[MSP430_REG_PC]);
dev->regs[MSP430_REG_PC] += 2;
2010-03-20 02:17:33 +00:00
if (reg != MSP430_REG_SR)
2010-04-30 04:01:03 +00:00
addr += dev->regs[reg];
2010-03-20 02:17:33 +00:00
break;
case MSP430_AMODE_INDIRECT:
if (reg == MSP430_REG_SR) {
if (data_ret)
*data_ret = 4;
2010-03-22 21:40:57 +00:00
return 0;
}
if (reg == MSP430_REG_R3) {
if (data_ret)
*data_ret = 2;
2010-03-22 21:40:57 +00:00
return 0;
}
2010-04-30 04:01:03 +00:00
addr = dev->regs[reg];
2010-03-20 02:17:33 +00:00
break;
case MSP430_AMODE_INDIRECT_INC:
if (reg == MSP430_REG_SR) {
if (data_ret)
*data_ret = 8;
2010-03-22 21:40:57 +00:00
return 0;
}
if (reg == MSP430_REG_R3) {
if (data_ret)
*data_ret = mask;
2010-03-22 21:40:57 +00:00
return 0;
}
2010-04-30 04:01:03 +00:00
addr = dev->regs[reg];
dev->regs[reg] += 2;
2010-03-20 02:17:33 +00:00
break;
}
if (addr_ret)
*addr_ret = addr;
if (data_ret) {
2010-04-30 04:01:03 +00:00
*data_ret = MEM_GETW(dev, addr) & mask;
if (addr < MEM_IO_END && dev->fetch_func) {
2010-05-13 00:57:21 +00:00
uint16_t data16 = *data_ret;
2010-04-30 04:01:03 +00:00
int ret;
2010-03-22 21:40:57 +00:00
2010-04-30 04:01:03 +00:00
ret = dev->fetch_func(dev->user_data,
dev->current_insn,
addr, is_byte, &data16);
*data_ret = data16;
return ret;
}
}
2010-03-22 21:40:57 +00:00
return 0;
2010-03-20 02:17:33 +00:00
}
2010-04-30 04:01:03 +00:00
static void store_operand(struct sim_device *dev,
int amode, int reg, int is_byte,
2010-05-13 00:57:21 +00:00
uint16_t addr, uint16_t data)
2010-03-20 02:17:33 +00:00
{
2010-04-30 04:01:03 +00:00
if (is_byte)
MEM_SETB(dev, addr, data);
2010-03-20 02:17:33 +00:00
else
2010-04-30 04:01:03 +00:00
MEM_SETW(dev, addr, data);
if (amode == MSP430_AMODE_REGISTER)
dev->regs[reg] = data;
else if (addr < MEM_IO_END && dev->store_func)
dev->store_func(dev->user_data, dev->current_insn,
addr, is_byte, data);
2010-03-20 02:17:33 +00:00
}
#define ARITH_BITS (MSP430_SR_V | MSP430_SR_N | MSP430_SR_Z | MSP430_SR_C)
2010-05-13 00:57:21 +00:00
static int step_double(struct sim_device *dev, uint16_t ins)
2010-03-20 02:17:33 +00:00
{
2010-05-13 00:57:21 +00:00
uint16_t opcode = ins & 0xf000;
2010-03-20 02:17:33 +00:00
int sreg = (ins >> 8) & 0xf;
int amode_dst = (ins >> 7) & 1;
int is_byte = ins & 0x0040;
int amode_src = (ins >> 4) & 0x3;
int dreg = ins & 0x000f;
2010-05-13 00:57:21 +00:00
uint32_t src_data;
uint16_t dst_addr = 0;
uint32_t dst_data;
uint32_t res_data;
uint32_t msb = is_byte ? 0x80 : 0x8000;
uint32_t mask = is_byte ? 0xff : 0xffff;
2010-03-20 02:17:33 +00:00
2010-04-30 04:01:03 +00:00
if (fetch_operand(dev, amode_src, sreg, is_byte, NULL, &src_data) < 0)
2010-03-22 21:40:57 +00:00
return -1;
2010-04-30 04:01:03 +00:00
if (fetch_operand(dev, amode_dst, dreg, is_byte, &dst_addr,
2010-03-22 21:40:57 +00:00
opcode == MSP430_OP_MOV ? NULL : &dst_data) < 0)
return -1;
2010-03-20 02:17:33 +00:00
switch (opcode) {
case MSP430_OP_MOV:
res_data = src_data;
break;
case MSP430_OP_SUB:
case MSP430_OP_SUBC:
case MSP430_OP_CMP:
src_data = ~src_data;
case MSP430_OP_ADD:
case MSP430_OP_ADDC:
if (opcode == MSP430_OP_ADDC || opcode == MSP430_OP_SUBC)
2010-04-30 04:01:03 +00:00
res_data = (dev->regs[MSP430_REG_SR] &
2010-03-20 02:17:33 +00:00
MSP430_SR_C) ? 1 : 0;
2010-03-20 05:21:29 +00:00
else if (opcode == MSP430_OP_SUB || opcode == MSP430_OP_CMP)
2010-03-20 02:17:33 +00:00
res_data = 1;
else
res_data = 0;
res_data += src_data;
res_data += dst_data;
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
2010-03-20 05:21:29 +00:00
if (!(res_data & mask))
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_Z;
2010-03-20 02:17:33 +00:00
if (res_data & msb)
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_N;
2010-03-20 02:17:33 +00:00
if (res_data & (msb << 1))
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_C;
2010-03-20 02:17:33 +00:00
if (!((src_data ^ dst_data) & msb) &&
(src_data ^ dst_data) & msb)
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_V;
2010-03-20 02:17:33 +00:00
break;
case MSP430_OP_DADD:
res_data = src_data + dst_data;
2010-04-30 04:01:03 +00:00
if (dev->regs[MSP430_REG_SR] & MSP430_SR_C)
2010-03-20 02:17:33 +00:00
res_data++;
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
2010-03-20 05:21:29 +00:00
if (!(res_data & mask))
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_Z;
2010-03-20 02:17:33 +00:00
if (res_data == 1)
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_N;
2010-03-20 02:17:33 +00:00
if ((is_byte && res_data > 99) ||
(!is_byte && res_data > 9999))
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_C;
2010-03-20 02:17:33 +00:00
break;
case MSP430_OP_BIT:
case MSP430_OP_AND:
res_data = src_data & dst_data;
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
dev->regs[MSP430_REG_SR] |=
2010-03-20 05:21:29 +00:00
(res_data & mask) ? MSP430_SR_C : MSP430_SR_Z;
2010-03-20 02:17:33 +00:00
if (res_data & msb)
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_N;
2010-03-20 02:17:33 +00:00
break;
case MSP430_OP_BIC:
res_data = dst_data & ~src_data;
break;
case MSP430_OP_BIS:
res_data = dst_data | src_data;
break;
case MSP430_OP_XOR:
res_data = dst_data ^ src_data;
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
dev->regs[MSP430_REG_SR] |=
2010-03-20 05:21:29 +00:00
(res_data & mask) ? MSP430_SR_C : MSP430_SR_Z;
2010-03-20 02:17:33 +00:00
if (res_data & msb)
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_N;
2010-03-20 02:17:33 +00:00
if (src_data & dst_data & msb)
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_V;
2010-03-20 02:17:33 +00:00
break;
default:
printc_err("sim: invalid double-operand opcode: "
2010-03-20 02:17:33 +00:00
"0x%04x (PC = 0x%04x)\n",
2010-04-30 04:01:03 +00:00
opcode, dev->current_insn);
2010-03-20 02:17:33 +00:00
return -1;
}
if (opcode != MSP430_OP_CMP && opcode != MSP430_OP_BIT)
2010-04-30 04:01:03 +00:00
store_operand(dev, amode_dst, dreg, is_byte,
dst_addr, res_data);
2010-03-20 02:17:33 +00:00
return 0;
}
2010-05-13 00:57:21 +00:00
static int step_single(struct sim_device *dev, uint16_t ins)
2010-03-20 02:17:33 +00:00
{
2010-05-13 00:57:21 +00:00
uint16_t opcode = ins & 0xff80;
2010-03-20 02:17:33 +00:00
int is_byte = ins & 0x0040;
int amode = (ins >> 4) & 0x3;
int reg = ins & 0x000f;
2010-05-13 00:57:21 +00:00
uint16_t msb = is_byte ? 0x80 : 0x8000;
uint32_t mask = is_byte ? 0xff : 0xffff;
uint16_t src_addr = 0;
uint32_t src_data;
2010-05-22 04:09:28 +00:00
uint32_t res_data = 0;
2010-03-20 02:17:33 +00:00
2010-04-30 04:01:03 +00:00
if (fetch_operand(dev, amode, reg, is_byte, &src_addr, &src_data) < 0)
2010-03-22 21:40:57 +00:00
return -1;
2010-03-20 02:17:33 +00:00
switch (opcode) {
case MSP430_OP_RRC:
case MSP430_OP_RRA:
res_data = (src_data >> 1) & ~msb;
if (opcode == MSP430_OP_RRC) {
2010-04-30 04:01:03 +00:00
if (dev->regs[MSP430_REG_SR] & MSP430_SR_C)
2010-03-20 02:17:33 +00:00
res_data |= msb;
} else {
res_data |= src_data & msb;
}
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
2010-03-20 05:21:29 +00:00
if (!(res_data & mask))
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_Z;
2010-03-20 02:17:33 +00:00
if (res_data & msb)
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_N;
2010-03-20 02:17:33 +00:00
if (src_data & 1)
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_C;
2010-03-20 02:17:33 +00:00
break;
case MSP430_OP_SWPB:
res_data = ((src_data & 0xff) << 8) | ((src_data >> 8) & 0xff);
break;
case MSP430_OP_SXT:
res_data = src_data & 0xff;
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] &= ~ARITH_BITS;
2010-03-20 02:17:33 +00:00
if (src_data & 0x80) {
res_data |= 0xff00;
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |= MSP430_SR_N;
2010-03-20 02:17:33 +00:00
}
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] |=
2010-03-20 05:21:29 +00:00
(res_data & mask) ? MSP430_SR_C : MSP430_SR_Z;
2010-03-20 02:17:33 +00:00
break;
case MSP430_OP_PUSH:
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SP] -= 2;
MEM_SETW(dev, dev->regs[MSP430_REG_SP], src_data);
2010-03-20 02:17:33 +00:00
break;
case MSP430_OP_CALL:
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SP] -= 2;
MEM_SETW(dev, dev->regs[MSP430_REG_SP],
dev->regs[MSP430_REG_PC]);
dev->regs[MSP430_REG_PC] = src_data;
2010-03-20 02:17:33 +00:00
break;
case MSP430_OP_RETI:
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_SR] =
MEM_GETW(dev, dev->regs[MSP430_REG_SP]);
dev->regs[MSP430_REG_SP] += 2;
dev->regs[MSP430_REG_PC] =
MEM_GETW(dev, dev->regs[MSP430_REG_SP]);
dev->regs[MSP430_REG_SP] += 2;
2010-03-20 02:17:33 +00:00
break;
default:
printc_err("sim: unknown single-operand opcode: 0x%04x "
2010-04-30 04:01:03 +00:00
"(PC = 0x%04x)\n", opcode, dev->current_insn);
2010-03-20 02:17:33 +00:00
return -1;
}
if (opcode != MSP430_OP_PUSH && opcode != MSP430_OP_CALL &&
opcode != MSP430_OP_RETI)
2010-04-30 04:01:03 +00:00
store_operand(dev, amode, reg, is_byte, src_addr, res_data);
2010-03-20 02:17:33 +00:00
return 0;
}
2010-05-13 00:57:21 +00:00
static int step_jump(struct sim_device *dev, uint16_t ins)
2010-03-20 02:17:33 +00:00
{
2010-05-13 00:57:21 +00:00
uint16_t opcode = ins & 0xfc00;
uint16_t pc_offset = (ins & 0x03ff) << 1;
uint16_t sr = dev->regs[MSP430_REG_SR];
2010-03-20 02:17:33 +00:00
if (pc_offset & 0x0400)
pc_offset |= 0xff800;
switch (opcode) {
case MSP430_OP_JNZ:
sr = !(sr & MSP430_SR_Z);
break;
case MSP430_OP_JZ:
sr &= MSP430_SR_Z;
break;
case MSP430_OP_JNC:
sr = !(sr & MSP430_SR_C);
break;
case MSP430_OP_JC:
sr &= MSP430_SR_C;
break;
case MSP430_OP_JN:
sr &= MSP430_SR_N;
break;
case MSP430_OP_JGE:
2010-05-21 01:17:44 +00:00
sr = ((sr & MSP430_SR_N) ? 1 : 0) ==
2010-03-20 02:17:33 +00:00
((sr & MSP430_SR_V) ? 1 : 0);
break;
case MSP430_OP_JL:
2010-05-21 01:17:44 +00:00
sr = ((sr & MSP430_SR_N) ? 1 : 0) !=
2010-03-20 02:17:33 +00:00
((sr & MSP430_SR_V) ? 1 : 0);
break;
case MSP430_OP_JMP:
sr = 1;
break;
}
if (sr)
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_PC] += pc_offset;
2010-03-20 02:17:33 +00:00
return 0;
}
2010-04-30 04:01:03 +00:00
static int step_cpu(struct sim_device *dev)
2010-03-20 02:17:33 +00:00
{
2010-05-13 00:57:21 +00:00
uint16_t ins;
2010-03-22 21:40:57 +00:00
int ret;
2010-03-20 02:17:33 +00:00
/* Fetch the instruction */
2010-04-30 04:01:03 +00:00
dev->current_insn = dev->regs[MSP430_REG_PC];
ins = MEM_GETW(dev, dev->current_insn);
dev->regs[MSP430_REG_PC] += 2;
2010-03-20 02:17:33 +00:00
/* Handle different instruction types */
if ((ins & 0xf000) >= 0x4000)
2010-04-30 04:01:03 +00:00
ret = step_double(dev, ins);
2010-03-20 02:17:33 +00:00
else if ((ins & 0xf000) >= 0x2000)
2010-04-30 04:01:03 +00:00
ret = step_jump(dev, ins);
2010-03-20 02:17:33 +00:00
else
2010-04-30 04:01:03 +00:00
ret = step_single(dev, ins);
2010-03-22 21:40:57 +00:00
/* If things went wrong, restart at the current instruction */
if (ret < 0)
2010-04-30 04:01:03 +00:00
dev->regs[MSP430_REG_PC] = dev->current_insn;
2010-03-22 21:40:57 +00:00
return ret;
2010-03-20 02:17:33 +00:00
}
/************************************************************************
* Device interface
*/
2010-04-30 04:01:03 +00:00
static void sim_destroy(device_t dev_base)
{
free(dev_base);
}
static int sim_readmem(device_t dev_base, address_t addr,
uint8_t *mem, address_t len)
2010-04-30 04:01:03 +00:00
{
struct sim_device *dev = (struct sim_device *)dev_base;
if (addr > MEM_SIZE || (addr + len) < addr ||
(addr + len) > MEM_SIZE) {
printc_err("sim: memory read out of range\n");
return -1;
}
2010-04-30 04:01:03 +00:00
if (addr + len > MEM_SIZE)
len = MEM_SIZE - addr;
memcpy(mem, dev->memory + addr, len);
return 0;
}
static int sim_writemem(device_t dev_base, address_t addr,
const uint8_t *mem, address_t len)
2010-04-30 04:01:03 +00:00
{
struct sim_device *dev = (struct sim_device *)dev_base;
if (addr > MEM_SIZE || (addr + len) < addr ||
(addr + len) > MEM_SIZE) {
printc_err("sim: memory write out of range\n");
return -1;
}
2010-03-20 02:17:33 +00:00
2010-04-30 04:01:03 +00:00
memcpy(dev->memory + addr, mem, len);
return 0;
}
static int sim_getregs(device_t dev_base, address_t *regs)
{
2010-04-30 04:01:03 +00:00
struct sim_device *dev = (struct sim_device *)dev_base;
int i;
2010-04-30 04:01:03 +00:00
for (i = 0; i < DEVICE_NUM_REGS; i++)
regs[i] = dev->regs[i];
2010-04-30 04:01:03 +00:00
return 0;
}
static int sim_setregs(device_t dev_base, const address_t *regs)
2010-04-30 04:01:03 +00:00
{
struct sim_device *dev = (struct sim_device *)dev_base;
int i;
2010-04-30 04:01:03 +00:00
for (i = 0; i < DEVICE_NUM_REGS; i++)
dev->regs[i] = regs[i];
2010-04-30 04:01:03 +00:00
return 0;
}
static int sim_ctl(device_t dev_base, device_ctl_t op)
{
2010-04-30 04:01:03 +00:00
struct sim_device *dev = (struct sim_device *)dev_base;
switch (op) {
2010-03-20 02:17:33 +00:00
case DEVICE_CTL_RESET:
2010-04-30 04:01:03 +00:00
memset(dev->regs, 0, sizeof(dev->regs));
dev->regs[MSP430_REG_PC] = MEM_GETW(dev, 0xfffe);
return 0;
2010-03-20 02:17:33 +00:00
case DEVICE_CTL_ERASE:
2010-04-30 04:01:03 +00:00
memset(dev->memory, 0xff, MEM_SIZE);
return 0;
case DEVICE_CTL_HALT:
2010-04-30 04:01:03 +00:00
dev->running = 0;
return 0;
2010-03-20 02:17:33 +00:00
case DEVICE_CTL_STEP:
2010-04-30 04:01:03 +00:00
return step_cpu(dev);
2010-03-20 02:17:33 +00:00
case DEVICE_CTL_RUN:
2010-04-30 04:01:03 +00:00
dev->running = 1;
2010-03-20 02:17:33 +00:00
return 0;
}
2010-04-30 04:01:03 +00:00
return 0;
}
2010-04-30 04:01:03 +00:00
static device_status_t sim_poll(device_t dev_base)
{
2010-04-30 04:01:03 +00:00
struct sim_device *dev = (struct sim_device *)dev_base;
int count = 1000000;
if (!dev->running)
return DEVICE_STATUS_HALTED;
2010-04-30 04:01:03 +00:00
ctrlc_reset();
while (count > 0) {
int i;
for (i = 0; i < dev->base.max_breakpoints; i++) {
struct device_breakpoint *bp =
&dev->base.breakpoints[i];
if ((bp->flags & DEVICE_BP_ENABLED) &&
dev->regs[MSP430_REG_PC] == bp->addr) {
dev->running = 0;
return DEVICE_STATUS_HALTED;
}
}
2010-03-20 02:17:33 +00:00
2010-04-30 04:01:03 +00:00
if (dev->regs[MSP430_REG_SR] & MSP430_SR_CPUOFF) {
printc("CPU disabled\n");
2010-04-30 04:01:03 +00:00
dev->running = 0;
return DEVICE_STATUS_HALTED;
}
2010-03-20 02:17:33 +00:00
2010-04-30 04:01:03 +00:00
if (step_cpu(dev) < 0) {
dev->running = 0;
return DEVICE_STATUS_ERROR;
}
2010-03-20 05:21:29 +00:00
2010-04-30 04:01:03 +00:00
if (ctrlc_check())
return DEVICE_STATUS_INTR;
2010-03-20 02:17:33 +00:00
2010-04-30 04:01:03 +00:00
count--;
2010-03-20 02:17:33 +00:00
}
return DEVICE_STATUS_RUNNING;
}
2010-04-30 04:01:03 +00:00
device_t sim_open(sim_fetch_func_t fetch_func,
sim_store_func_t store_func,
void *user_data)
{
2010-04-30 04:01:03 +00:00
struct sim_device *dev = malloc(sizeof(*dev));
2010-04-30 04:01:03 +00:00
if (!dev) {
pr_error("can't allocate memory for simulation");
2010-04-30 04:01:03 +00:00
return NULL;
}
memset(dev, 0, sizeof(*dev));
dev->base.max_breakpoints = DEVICE_MAX_BREAKPOINTS;
2010-04-30 04:01:03 +00:00
dev->base.destroy = sim_destroy;
dev->base.readmem = sim_readmem;
dev->base.writemem = sim_writemem;
dev->base.getregs = sim_getregs;
dev->base.setregs = sim_setregs;
dev->base.ctl = sim_ctl;
dev->base.poll = sim_poll;
2010-04-30 04:01:03 +00:00
dev->fetch_func = fetch_func;
dev->store_func = store_func;
dev->user_data = user_data;
2010-04-30 04:01:03 +00:00
memset(dev->memory, 0xff, sizeof(dev->memory));
memset(dev->regs, 0xff, sizeof(dev->regs));
2010-04-30 04:01:03 +00:00
dev->running = 0;
dev->current_insn = 0;
printc_dbg("Simulation started, 0x%x bytes of RAM\n", MEM_SIZE);
2010-04-30 04:01:03 +00:00
return (device_t)dev;
}