simx: MSP430X simulator by Bruce Burns <bgb@alum.mit.edu>

This commit is contained in:
Daniel Beer 2020-09-05 14:56:37 +12:00
parent e65bc6910a
commit 6740d7d98b
9 changed files with 1116 additions and 314 deletions

View File

@ -87,3 +87,6 @@ Paolo Zebelloni <p.zebelloni@c-labs.it>:
Jan Willeke <willeke@smartmote.de>:
* GPIO JTAG driver.
Bruce Burns <bgb@alum.mit.edu>
* CPUX support in simulation driver (simx)

File diff suppressed because it is too large Load Diff

View File

@ -23,5 +23,6 @@
/* Dummy/simulation implementation. */
extern const struct device_class device_sim;
extern const struct device_class device_simx;
#endif

View File

@ -355,6 +355,12 @@ int simio_read(address_t addr, uint16_t *data)
*data = ((uint16_t)sfr_data[addr]) |
(((uint16_t)sfr_data[addr + 1]) << 8);
return 0;
} else if (addr >= 0x100 && addr < 0x110) {
/* most MSPs map SFR at 0x100 */
*data = ((uint16_t)sfr_data[addr - 0x100]) |
(((uint16_t)sfr_data[addr - 0x100 + 1]) << 8);
return 0;
}
*data = 0;
@ -366,6 +372,11 @@ int simio_write_b(address_t addr, uint8_t data)
if (addr < 16) {
sfr_data[addr] = data;
return 0;
} else if (addr >= 0x100 && addr < 0x110) {
/* most MSPs map SFR at 0x100 */
sfr_data[addr - 0x100] = data;
return 0;
}
return simio_write_b_device(addr, data);
@ -376,6 +387,11 @@ int simio_read_b(address_t addr, uint8_t *data)
if (addr < 16) {
*data = sfr_data[addr];
return 0;
} else if (addr >= 0x100 && addr < 0x110) {
/* most MSPs map SFR at 0x100 */
*data = sfr_data[addr - 0x100];
return 0;
}
*data = 0;

View File

@ -24,21 +24,23 @@
#include "output.h"
#include "expr.h"
/* Multiplier register addresses - taken from mspgcc */
#define MPY 0x0130 /* Multiply Unsigned/Operand 1 */
#define MPYS 0x0132 /* Multiply Signed/Operand 1 */
#define MAC 0x0134 /* Multiply Unsigned and Accumulate/Operand 1 */
#define MACS 0x0136 /* Multiply Signed and Accumulate/Operand 1 */
#define OP2 0x0138 /* Operand 2 */
#define RESLO 0x013A /* Result Low Word */
#define RESHI 0x013C /* Result High Word */
#define SUMEXT 0x013E /* Sum Extend */
/* Multiplier register offsets from base addr */
#define MPY 0x0 /* Multiply Unsigned/Operand 1 */
#define MPYS 0x2 /* Multiply Signed/Operand 1 */
#define MAC 0x4 /* Multiply Unsigned and Accumulate/Operand 1 */
#define MACS 0x6 /* Multiply Signed and Accumulate/Operand 1 */
#define OP2 0x8 /* Operand 2 */
#define RESLO 0xA /* Result Low Word */
#define RESHI 0xC /* Result High Word */
#define SUMEXT 0xE /* Sum Extend */
struct hwmult {
struct simio_device base;
int mode;
address_t base_addr;
uint16_t op1;
uint16_t op2;
uint32_t result;
@ -59,6 +61,8 @@ struct simio_device *hwmult_create(char **arg_text)
memset(h, 0, sizeof(*h));
h->base.type = &simio_hwmult;
h->base_addr = 0x130;
return (struct simio_device *)h;
}
@ -67,6 +71,44 @@ static void hwmult_destroy(struct simio_device *dev)
free(dev);
}
static int config_addr(address_t *addr, char **arg_text)
{
char *text = get_arg(arg_text);
if (!text) {
printc_err("hwmult: config: expected address\n");
return -1;
}
if (expr_eval(text, addr) < 0) {
printc_err("hwmult: can't parse address: %s\n", text);
return -1;
}
return 0;
}
static int hwmult_config(struct simio_device *dev,
const char *param, char **arg_text)
{
struct hwmult *h = (struct hwmult *)dev;
if (!strcasecmp(param, "base"))
return config_addr(&h->base_addr, arg_text);
printc_err("hwmult: config: unknown parameter: %s\n", param);
return -1;
}
static int hwmult_info(struct simio_device *dev)
{
struct hwmult *h = (struct hwmult *)dev;
printc("Base address: 0x%04x\n\n", h->base_addr);
return 0;
}
static void do_multiply(struct hwmult *h)
{
uint32_t im;
@ -100,6 +142,10 @@ static int hwmult_write(struct simio_device *dev, address_t addr, uint16_t data)
{
struct hwmult *h = (struct hwmult *)dev;
if (addr < h->base_addr) return 1;
addr -= h->base_addr;
switch (addr) {
case RESHI:
h->result = (h->result & 0xffff) | ((uint32_t)data << 16);
@ -130,6 +176,10 @@ static int hwmult_read(struct simio_device *dev, address_t addr, uint16_t *data)
{
struct hwmult *h = (struct hwmult *)dev;
if (addr < h->base_addr) return 1;
addr -= h->base_addr;
switch (addr) {
case MPY:
case MPYS:
@ -161,9 +211,14 @@ static int hwmult_read(struct simio_device *dev, address_t addr, uint16_t *data)
const struct simio_class simio_hwmult = {
.name = "hwmult",
.help =
"This module simulates the hardware multiplier.\n",
"This module simulates the hardware multiplier.\n"
"Config arguments are:\n"
" base <address>\n"
" Set the peripheral base address.\n",
.create = hwmult_create,
.destroy = hwmult_destroy,
.config = hwmult_config,
.info = hwmult_info,
.write = hwmult_write,
.read = hwmult_read
};

View File

@ -80,6 +80,7 @@ static const struct device_class *const driver_table[] = {
&device_olimex_iso,
&device_olimex_iso_mk2,
&device_sim,
&device_simx,
&device_uif,
&device_bsl,
&device_flash_bsl,
@ -550,11 +551,11 @@ int main(int argc, char **argv)
goto fail_driver;
}
simio_init();
if (device_probe_id(device_default, args.devarg.forced_chip_id) < 0)
printc_err("warning: device ID probe failed\n");
simio_init();
if (!(args.flags & OPT_NO_RC))
process_rc_file(args.alt_config);

View File

@ -249,14 +249,24 @@ static int decode_14xx(const uint8_t *code,
* valid single-operand instruction could not be found.
*/
static int decode_single(const uint8_t *code, address_t offset,
address_t size, struct msp430_instruction *insn)
address_t size, struct msp430_instruction *insn,
uint16_t ex_word)
{
uint16_t op = (code[1] << 8) | code[0];
int need_arg = 0;
insn->itype = MSP430_ITYPE_SINGLE;
insn->op = op & 0xff80;
insn->dsize = (op & 0x0040) ? MSP430_DSIZE_BYTE : MSP430_DSIZE_WORD;
/* length encoding is based on AL bit (if ex_word present) and BW bit;
SWPB and SXT have non-standard encodings */
insn->dsize = (insn->op != MSP430_OP_SWPB && insn->op != MSP430_OP_SXT)
? ((!ex_word || (ex_word & 0x0040))
? ((op & 0x0040) ? MSP430_DSIZE_BYTE : MSP430_DSIZE_WORD)
: ((op & 0x0040) ? MSP430_DSIZE_AWORD : MSP430_DSIZE_UNKNOWN))
: ((op & 0x0040)
? MSP430_DSIZE_UNKNOWN
: (!ex_word || (ex_word & 0x0040)) ? MSP430_DSIZE_WORD : MSP430_DSIZE_AWORD);
insn->dst_mode = (op >> 4) & 0x3;
insn->dst_reg = op & 0xf;
@ -317,7 +327,9 @@ static int decode_double(const uint8_t *code, address_t offset,
/* Decode and consume opcode */
insn->itype = MSP430_ITYPE_DOUBLE;
insn->op = op & 0xf000;
insn->dsize = (op & 0x0040) ? MSP430_DSIZE_BYTE : MSP430_DSIZE_WORD;
insn->dsize = (!ex_word || (ex_word & 0x0040))
? ((op & 0x0040) ? MSP430_DSIZE_BYTE : MSP430_DSIZE_WORD)
: ((op & 0x0040) ? MSP430_DSIZE_AWORD : MSP430_DSIZE_UNKNOWN);
insn->src_mode = (op >> 4) & 0x3;
insn->src_reg = (op >> 8) & 0xf;
@ -785,7 +797,7 @@ int dis_decode(const uint8_t *code, address_t offset, address_t len,
if ((op & 0xf000) >= 0x4000)
ret = decode_double(code, offset, len, insn, ex_word);
else if ((op & 0xf000) == 0x1000 && (op & 0xfc00) < 0x1280)
ret = decode_single(code, offset, len, insn);
ret = decode_single(code, offset, len, insn, ex_word);
else
return -1;
@ -796,16 +808,15 @@ int dis_decode(const uint8_t *code, address_t offset, address_t len,
(insn->itype == MSP430_ITYPE_SINGLE ||
insn->src_mode == MSP430_AMODE_REGISTER)) {
if ((ex_word >> 8) & 1) {
if (insn->op != MSP430_OP_RRCX)
return -1;
if (insn->op == MSP430_OP_RRCX)
insn->op = MSP430_OP_RRUX;
else
insn->ignore_cy = 1;
}
insn->rep_register = (ex_word >> 7) & 1;
insn->rep_index = ex_word & 0xf;
}
if (!(ex_word & 0x40))
insn->dsize |= 2;
} else {
if ((op & 0xf000) == 0x0000)
ret = decode_00xx(code, len, insn);
@ -814,7 +825,7 @@ int dis_decode(const uint8_t *code, address_t offset, address_t len,
else if ((op & 0xff00) == 0x1300)
ret = decode_13xx(code, len, insn);
else if ((op & 0xf000) == 0x1000)
ret = decode_single(code, offset, len, insn);
ret = decode_single(code, offset, len, insn, 0);
else if ((op & 0xf000) >= 0x2000 && (op & 0xf000) < 0x4000)
ret = decode_jump(code, offset, insn);
else if ((op & 0xf000) >= 0x4000)

View File

@ -270,6 +270,7 @@ struct msp430_instruction {
int rep_index;
int rep_register;
int ignore_cy;
};
/* Decode a single instruction.

View File

@ -202,6 +202,9 @@ static int dis_format(const struct msp430_instruction *insn)
else if (insn->rep_index)
len += printc(" [repeat %d]", insn->rep_index + 1);
if (insn->ignore_cy)
len += printc(" [ignore carry]");
return len;
}