* [Qemu-devel] [PULL 01/11] lm32_sys: increase test case name length limit
2013-09-25 18:59 [Qemu-devel] [PULL 00/11] target-lm32 updates Michael Walle
@ 2013-09-25 18:59 ` Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 02/11] tests: lm32: new rule for single test cases Michael Walle
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Michael Walle @ 2013-09-25 18:59 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Walle
The new MMU tests use longer names.
Signed-off-by: Michael Walle <michael@walle.cc>
---
hw/misc/lm32_sys.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/misc/lm32_sys.c b/hw/misc/lm32_sys.c
index 9bdb781..8176cdb 100644
--- a/hw/misc/lm32_sys.c
+++ b/hw/misc/lm32_sys.c
@@ -42,7 +42,7 @@ enum {
R_MAX
};
-#define MAX_TESTNAME_LEN 16
+#define MAX_TESTNAME_LEN 32
#define TYPE_LM32_SYS "lm32-sys"
#define LM32_SYS(obj) OBJECT_CHECK(LM32SysState, (obj), TYPE_LM32_SYS)
@@ -80,7 +80,7 @@ static void sys_write(void *opaque, hwaddr addr,
case R_PASSFAIL:
s->regs[addr] = value;
testname = (char *)s->testname;
- qemu_log("TC %-16s %s\n", testname, (value) ? "FAILED" : "OK");
+ qemu_log("TC %-32s %s\n", testname, (value) ? "FAILED" : "OK");
break;
case R_TESTNAME:
s->regs[addr] = value;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PULL 02/11] tests: lm32: new rule for single test cases
2013-09-25 18:59 [Qemu-devel] [PULL 00/11] target-lm32 updates Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 01/11] lm32_sys: increase test case name length limit Michael Walle
@ 2013-09-25 18:59 ` Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 03/11] milkymist-uart: use qemu_chr_fe_write_all() instead of qemu_chr_fe_write() Michael Walle
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Michael Walle @ 2013-09-25 18:59 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Walle
Introduce new target "check_%" to run indiviudal test caes, eg.
make check_mmu
Signed-off-by: Michael Walle <michael@walle.cc>
---
tests/tcg/lm32/Makefile | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tests/tcg/lm32/Makefile b/tests/tcg/lm32/Makefile
index 9a00ef7..19e0664 100644
--- a/tests/tcg/lm32/Makefile
+++ b/tests/tcg/lm32/Makefile
@@ -101,5 +101,8 @@ check: $(CRT) $(SYS) $(TESTCASES)
$(SIM) $(SIMFLAGS) ./$$case; \
done
+check_%: test_%.tst $(CRT) $(SYS)
+ $(SIM) $(SIMFLAGS) $<
+
clean:
$(RM) -fr $(TESTCASES) $(CRT)
--
1.7.10.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PULL 03/11] milkymist-uart: use qemu_chr_fe_write_all() instead of qemu_chr_fe_write()
2013-09-25 18:59 [Qemu-devel] [PULL 00/11] target-lm32 updates Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 01/11] lm32_sys: increase test case name length limit Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 02/11] tests: lm32: new rule for single test cases Michael Walle
@ 2013-09-25 18:59 ` Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 04/11] lm32_uart/lm32_juart: use qemu_chr_fe_write_all() Michael Walle
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Michael Walle @ 2013-09-25 18:59 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Walle, Antony Pavlov
From: Antony Pavlov <antonynpavlov@gmail.com>
qemu_chr_fe_write() is capable of returning 0
to indicate EAGAIN (and friends) and we don't
handle this.
Just change it to qemu_chr_fe_write_all() to fix.
Reported-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Acked-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Michael Walle <michael@walle.cc>
---
hw/char/milkymist-uart.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
index 2e4b5c5..6e4bc20 100644
--- a/hw/char/milkymist-uart.c
+++ b/hw/char/milkymist-uart.c
@@ -124,7 +124,7 @@ static void uart_write(void *opaque, hwaddr addr, uint64_t value,
switch (addr) {
case R_RXTX:
if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
+ qemu_chr_fe_write_all(s->chr, &ch, 1);
}
s->regs[R_STAT] |= STAT_TX_EVT;
break;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PULL 04/11] lm32_uart/lm32_juart: use qemu_chr_fe_write_all()
2013-09-25 18:59 [Qemu-devel] [PULL 00/11] target-lm32 updates Michael Walle
` (2 preceding siblings ...)
2013-09-25 18:59 ` [Qemu-devel] [PULL 03/11] milkymist-uart: use qemu_chr_fe_write_all() instead of qemu_chr_fe_write() Michael Walle
@ 2013-09-25 18:59 ` Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 05/11] target-lm32: register helper functions Michael Walle
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Michael Walle @ 2013-09-25 18:59 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Walle
qemu_chr_fe_write() may return EAGAIN. Therefore, use
qemu_chr_fe_write_all().
Signed-off-by: Michael Walle <michael@walle.cc>
---
hw/char/lm32_juart.c | 2 +-
hw/char/lm32_uart.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c
index 252fe46..380cb5d 100644
--- a/hw/char/lm32_juart.c
+++ b/hw/char/lm32_juart.c
@@ -75,7 +75,7 @@ void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
s->jtx = jtx;
if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
+ qemu_chr_fe_write_all(s->chr, &ch, 1);
}
}
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
index 85d7265..84c2549 100644
--- a/hw/char/lm32_uart.c
+++ b/hw/char/lm32_uart.c
@@ -177,7 +177,7 @@ static void uart_write(void *opaque, hwaddr addr,
switch (addr) {
case R_RXTX:
if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
+ qemu_chr_fe_write_all(s->chr, &ch, 1);
}
break;
case R_IER:
--
1.7.10.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PULL 05/11] target-lm32: register helper functions
2013-09-25 18:59 [Qemu-devel] [PULL 00/11] target-lm32 updates Michael Walle
` (3 preceding siblings ...)
2013-09-25 18:59 ` [Qemu-devel] [PULL 04/11] lm32_uart/lm32_juart: use qemu_chr_fe_write_all() Michael Walle
@ 2013-09-25 18:59 ` Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 06/11] milkymist-vgafb: swap pixel data in source buffer Michael Walle
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Michael Walle @ 2013-09-25 18:59 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Walle
This has been forgotton in the initial commit. Fix it.
Reported-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Michael Walle <michael@walle.cc>
---
target-lm32/translate.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
index 6ea0ecd..9605494 100644
--- a/target-lm32/translate.c
+++ b/target-lm32/translate.c
@@ -1234,5 +1234,8 @@ void lm32_translate_init(void)
cpu_deba = tcg_global_mem_new(TCG_AREG0,
offsetof(CPULM32State, deba),
"deba");
+
+#define GEN_HELPER 2
+#include "helper.h"
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PULL 06/11] milkymist-vgafb: swap pixel data in source buffer
2013-09-25 18:59 [Qemu-devel] [PULL 00/11] target-lm32 updates Michael Walle
` (4 preceding siblings ...)
2013-09-25 18:59 ` [Qemu-devel] [PULL 05/11] target-lm32: register helper functions Michael Walle
@ 2013-09-25 18:59 ` Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 07/11] target-lm32: kill cpu_abort() calls Michael Walle
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Michael Walle @ 2013-09-25 18:59 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Michael Walle
In commit fc97bb5ba3e7239c0b6d24095df6784868dfebbf the lduw_raw() call was
eliminated. But we are reading from the target buffer a 16-bit value, which
is in big-endian format. Therefore, swap the bytes if we are building for a
little-endian host.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Michael Walle <michael@walle.cc>
---
hw/display/milkymist-vgafb_template.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/hw/display/milkymist-vgafb_template.h b/hw/display/milkymist-vgafb_template.h
index e0036e1..5a906af 100644
--- a/hw/display/milkymist-vgafb_template.h
+++ b/hw/display/milkymist-vgafb_template.h
@@ -62,6 +62,9 @@ static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
while (width--) {
memcpy(&rgb565, s, sizeof(rgb565));
+#ifndef HOST_WORDS_BIGENDIAN
+ rgb565 = bswap16(rgb565);
+#endif
r = ((rgb565 >> 11) & 0x1f) << 3;
g = ((rgb565 >> 5) & 0x3f) << 2;
b = ((rgb565 >> 0) & 0x1f) << 3;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PULL 07/11] target-lm32: kill cpu_abort() calls
2013-09-25 18:59 [Qemu-devel] [PULL 00/11] target-lm32 updates Michael Walle
` (5 preceding siblings ...)
2013-09-25 18:59 ` [Qemu-devel] [PULL 06/11] milkymist-vgafb: swap pixel data in source buffer Michael Walle
@ 2013-09-25 18:59 ` Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 08/11] target-lm32: move model features to LM32CPU Michael Walle
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Michael Walle @ 2013-09-25 18:59 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Walle, Andreas Färber
Instead of killing QEMU, translate instructions which are not available on
the CPU model as a noop and issue a log message at translation time.
On the real hardware CPU unknown opcodes results in undefined behaviour.
These changes prepare the removal of CPULM32State from DisasContext.
Cc: Andreas Färber <afaerber@suse.de>
Signed-off-by: Michael Walle <michael@walle.cc>
---
target-lm32/translate.c | 72 ++++++++++++++++++++++++++---------------------
1 file changed, 40 insertions(+), 32 deletions(-)
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
index 9605494..1d94d52 100644
--- a/target-lm32/translate.c
+++ b/target-lm32/translate.c
@@ -80,7 +80,6 @@ typedef struct DisasContext {
unsigned int tb_flags, synced_flags; /* tb dependent flags. */
int is_jmp;
- int nr_nops;
struct TranslationBlock *tb;
int singlestep_enabled;
} DisasContext;
@@ -422,7 +421,8 @@ static void dec_divu(DisasContext *dc)
LOG_DIS("divu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
- cpu_abort(dc->env, "hardware divider is not available\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n");
+ return;
}
l1 = gen_new_label();
@@ -500,7 +500,8 @@ static void dec_modu(DisasContext *dc)
LOG_DIS("modu r%d, r%d, %d\n", dc->r2, dc->r0, dc->r1);
if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
- cpu_abort(dc->env, "hardware divider is not available\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n");
+ return;
}
l1 = gen_new_label();
@@ -521,7 +522,9 @@ static void dec_mul(DisasContext *dc)
}
if (!(dc->env->features & LM32_FEATURE_MULTIPLY)) {
- cpu_abort(dc->env, "hardware multiplier is not available\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "hardware multiplier is not available\n");
+ return;
}
if (dc->format == OP_FMT_RI) {
@@ -590,7 +593,8 @@ static void dec_scall(DisasContext *dc)
} else if (dc->imm5 == 2) {
LOG_DIS("break\n");
} else {
- cpu_abort(dc->env, "invalid opcode\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode @0x%x", dc->pc);
+ return;
}
if (dc->imm5 == 7) {
@@ -647,10 +651,10 @@ static void dec_rcsr(DisasContext *dc)
case CSR_WP1:
case CSR_WP2:
case CSR_WP3:
- cpu_abort(dc->env, "invalid read access csr=%x\n", dc->csr);
+ qemu_log_mask(LOG_GUEST_ERROR, "invalid read access csr=%x\n", dc->csr);
break;
default:
- cpu_abort(dc->env, "read_csr: unknown csr=%x\n", dc->csr);
+ qemu_log_mask(LOG_GUEST_ERROR, "read_csr: unknown csr=%x\n", dc->csr);
break;
}
}
@@ -672,7 +676,9 @@ static void dec_sextb(DisasContext *dc)
LOG_DIS("sextb r%d, r%d\n", dc->r2, dc->r0);
if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
- cpu_abort(dc->env, "hardware sign extender is not available\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "hardware sign extender is not available\n");
+ return;
}
tcg_gen_ext8s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
@@ -683,7 +689,9 @@ static void dec_sexth(DisasContext *dc)
LOG_DIS("sexth r%d, r%d\n", dc->r2, dc->r0);
if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
- cpu_abort(dc->env, "hardware sign extender is not available\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "hardware sign extender is not available\n");
+ return;
}
tcg_gen_ext16s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
@@ -710,7 +718,8 @@ static void dec_sl(DisasContext *dc)
}
if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
- cpu_abort(dc->env, "hardware shifter is not available\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "hardware shifter is not available\n");
+ return;
}
if (dc->format == OP_FMT_RI) {
@@ -736,7 +745,9 @@ static void dec_sr(DisasContext *dc)
/* TODO: check r1 == 1 during runtime */
} else {
if (dc->imm5 != 1) {
- cpu_abort(dc->env, "hardware shifter is not available\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "hardware shifter is not available\n");
+ return;
}
}
}
@@ -764,7 +775,9 @@ static void dec_sru(DisasContext *dc)
/* TODO: check r1 == 1 during runtime */
} else {
if (dc->imm5 != 1) {
- cpu_abort(dc->env, "hardware shifter is not available\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "hardware shifter is not available\n");
+ return;
}
}
}
@@ -802,7 +815,7 @@ static void dec_user(DisasContext *dc)
{
LOG_DIS("user");
- cpu_abort(dc->env, "user insn undefined\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "user instruction undefined\n");
}
static void dec_wcsr(DisasContext *dc)
@@ -868,7 +881,9 @@ static void dec_wcsr(DisasContext *dc)
case CSR_BP3:
no = dc->csr - CSR_BP0;
if (dc->env->num_bps <= no) {
- cpu_abort(dc->env, "breakpoint #%i is not available\n", no);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "breakpoint #%i is not available\n", no);
+ break;
}
tcg_gen_mov_tl(cpu_bp[no], cpu_R[dc->r1]);
break;
@@ -878,16 +893,20 @@ static void dec_wcsr(DisasContext *dc)
case CSR_WP3:
no = dc->csr - CSR_WP0;
if (dc->env->num_wps <= no) {
- cpu_abort(dc->env, "watchpoint #%i is not available\n", no);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "watchpoint #%i is not available\n", no);
+ break;
}
tcg_gen_mov_tl(cpu_wp[no], cpu_R[dc->r1]);
break;
case CSR_CC:
case CSR_CFG:
- cpu_abort(dc->env, "invalid write access csr=%x\n", dc->csr);
+ qemu_log_mask(LOG_GUEST_ERROR, "invalid write access csr=%x\n",
+ dc->csr);
break;
default:
- cpu_abort(dc->env, "write_csr unknown csr=%x\n", dc->csr);
+ qemu_log_mask(LOG_GUEST_ERROR, "write_csr: unknown csr=%x\n",
+ dc->csr);
break;
}
}
@@ -933,7 +952,7 @@ static void dec_xor(DisasContext *dc)
static void dec_ill(DisasContext *dc)
{
- cpu_abort(dc->env, "unknown opcode 0x%02x\n", dc->opcode);
+ qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode 0x%02x\n", dc->opcode);
}
typedef void (*DecoderInfo)(DisasContext *dc);
@@ -959,18 +978,6 @@ static inline void decode(DisasContext *dc, uint32_t ir)
dc->ir = ir;
LOG_DIS("%8.8x\t", dc->ir);
- /* try guessing 'empty' instruction memory, although it may be a valid
- * instruction sequence (eg. srui r0, r0, 0) */
- if (dc->ir) {
- dc->nr_nops = 0;
- } else {
- LOG_DIS("nr_nops=%d\t", dc->nr_nops);
- dc->nr_nops++;
- if (dc->nr_nops > 4) {
- cpu_abort(dc->env, "fetching nop sequence\n");
- }
- }
-
dc->opcode = EXTRACT_FIELD(ir, 26, 31);
dc->imm5 = EXTRACT_FIELD(ir, 0, 4);
@@ -1034,10 +1041,11 @@ void gen_intermediate_code_internal(LM32CPU *cpu,
dc->is_jmp = DISAS_NEXT;
dc->pc = pc_start;
dc->singlestep_enabled = cs->singlestep_enabled;
- dc->nr_nops = 0;
if (pc_start & 3) {
- cpu_abort(env, "LM32: unaligned PC=%x\n", pc_start);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "unaligned PC=%x. Ignoring lowest bits.\n", pc_start);
+ pc_start &= ~3;
}
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PULL 08/11] target-lm32: move model features to LM32CPU
2013-09-25 18:59 [Qemu-devel] [PULL 00/11] target-lm32 updates Michael Walle
` (6 preceding siblings ...)
2013-09-25 18:59 ` [Qemu-devel] [PULL 07/11] target-lm32: kill cpu_abort() calls Michael Walle
@ 2013-09-25 18:59 ` Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 09/11] target-lm32: add breakpoint/watchpoint support Michael Walle
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Michael Walle @ 2013-09-25 18:59 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Walle, Andreas Färber
This allows us to completely remove CPULM32State from DisasContext.
Instead, copy the fields we need to DisasContext.
Cc: Andreas Färber <afaerber@suse.de>
Signed-off-by: Michael Walle <michael@walle.cc>
---
target-lm32/cpu-qom.h | 1 +
target-lm32/cpu.h | 12 +++++++++---
target-lm32/helper.c | 15 ++-------------
target-lm32/translate.c | 24 ++++++++++++------------
4 files changed, 24 insertions(+), 28 deletions(-)
diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h
index 723f604..9f4e233 100644
--- a/target-lm32/cpu-qom.h
+++ b/target-lm32/cpu-qom.h
@@ -60,6 +60,7 @@ typedef struct LM32CPU {
/*< public >*/
CPULM32State env;
+ const LM32Def *def;
} LM32CPU;
static inline LM32CPU *lm32_env_get_cpu(CPULM32State *env)
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index dbfe043..67a785e 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -149,6 +149,15 @@ enum {
LM32_FLAG_IGNORE_MSB = 1,
};
+typedef struct {
+ const char *name;
+ uint32_t revision;
+ uint8_t num_interrupts;
+ uint8_t num_breakpoints;
+ uint8_t num_watchpoints;
+ uint32_t features;
+} LM32Def;
+
struct CPULM32State {
/* general registers */
uint32_t regs[32];
@@ -177,10 +186,7 @@ struct CPULM32State {
DeviceState *juart_state;
/* processor core features */
- uint32_t features;
uint32_t flags;
- uint8_t num_bps;
- uint8_t num_wps;
};
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 15bc615..383bcf3 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -90,15 +90,6 @@ void lm32_cpu_do_interrupt(CPUState *cs)
}
}
-typedef struct {
- const char *name;
- uint32_t revision;
- uint8_t num_interrupts;
- uint8_t num_breakpoints;
- uint8_t num_watchpoints;
- uint32_t features;
-} LM32Def;
-
static const LM32Def lm32_defs[] = {
{
.name = "lm32-basic",
@@ -214,11 +205,9 @@ LM32CPU *cpu_lm32_init(const char *cpu_model)
}
cpu = LM32_CPU(object_new(TYPE_LM32_CPU));
- env = &cpu->env;
+ cpu->def = def;
- env->features = def->features;
- env->num_bps = def->num_breakpoints;
- env->num_wps = def->num_watchpoints;
+ env = &cpu->env;
env->cfg = cfg_by_def(def);
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
index 1d94d52..c8c862e 100644
--- a/target-lm32/translate.c
+++ b/target-lm32/translate.c
@@ -64,7 +64,7 @@ enum {
/* This is the state at translation time. */
typedef struct DisasContext {
- CPULM32State *env;
+ const LM32Def *def;
target_ulong pc;
/* Decoder. */
@@ -420,7 +420,7 @@ static void dec_divu(DisasContext *dc)
LOG_DIS("divu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
+ if (!(dc->def->features & LM32_FEATURE_DIVIDE)) {
qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n");
return;
}
@@ -499,7 +499,7 @@ static void dec_modu(DisasContext *dc)
LOG_DIS("modu r%d, r%d, %d\n", dc->r2, dc->r0, dc->r1);
- if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
+ if (!(dc->def->features & LM32_FEATURE_DIVIDE)) {
qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n");
return;
}
@@ -521,7 +521,7 @@ static void dec_mul(DisasContext *dc)
LOG_DIS("mul r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
}
- if (!(dc->env->features & LM32_FEATURE_MULTIPLY)) {
+ if (!(dc->def->features & LM32_FEATURE_MULTIPLY)) {
qemu_log_mask(LOG_GUEST_ERROR,
"hardware multiplier is not available\n");
return;
@@ -675,7 +675,7 @@ static void dec_sextb(DisasContext *dc)
{
LOG_DIS("sextb r%d, r%d\n", dc->r2, dc->r0);
- if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
+ if (!(dc->def->features & LM32_FEATURE_SIGN_EXTEND)) {
qemu_log_mask(LOG_GUEST_ERROR,
"hardware sign extender is not available\n");
return;
@@ -688,7 +688,7 @@ static void dec_sexth(DisasContext *dc)
{
LOG_DIS("sexth r%d, r%d\n", dc->r2, dc->r0);
- if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
+ if (!(dc->def->features & LM32_FEATURE_SIGN_EXTEND)) {
qemu_log_mask(LOG_GUEST_ERROR,
"hardware sign extender is not available\n");
return;
@@ -717,7 +717,7 @@ static void dec_sl(DisasContext *dc)
LOG_DIS("sl r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
}
- if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+ if (!(dc->def->features & LM32_FEATURE_SHIFT)) {
qemu_log_mask(LOG_GUEST_ERROR, "hardware shifter is not available\n");
return;
}
@@ -740,7 +740,7 @@ static void dec_sr(DisasContext *dc)
LOG_DIS("sr r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
}
- if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+ if (!(dc->def->features & LM32_FEATURE_SHIFT)) {
if (dc->format == OP_FMT_RI) {
/* TODO: check r1 == 1 during runtime */
} else {
@@ -770,7 +770,7 @@ static void dec_sru(DisasContext *dc)
LOG_DIS("sru r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
}
- if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+ if (!(dc->def->features & LM32_FEATURE_SHIFT)) {
if (dc->format == OP_FMT_RI) {
/* TODO: check r1 == 1 during runtime */
} else {
@@ -880,7 +880,7 @@ static void dec_wcsr(DisasContext *dc)
case CSR_BP2:
case CSR_BP3:
no = dc->csr - CSR_BP0;
- if (dc->env->num_bps <= no) {
+ if (dc->def->num_breakpoints <= no) {
qemu_log_mask(LOG_GUEST_ERROR,
"breakpoint #%i is not available\n", no);
break;
@@ -892,7 +892,7 @@ static void dec_wcsr(DisasContext *dc)
case CSR_WP2:
case CSR_WP3:
no = dc->csr - CSR_WP0;
- if (dc->env->num_wps <= no) {
+ if (dc->def->num_watchpoints <= no) {
qemu_log_mask(LOG_GUEST_ERROR,
"watchpoint #%i is not available\n", no);
break;
@@ -1033,7 +1033,7 @@ void gen_intermediate_code_internal(LM32CPU *cpu,
int max_insns;
pc_start = tb->pc;
- dc->env = env;
+ dc->def = cpu->def;
dc->tb = tb;
gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PULL 09/11] target-lm32: add breakpoint/watchpoint support
2013-09-25 18:59 [Qemu-devel] [PULL 00/11] target-lm32 updates Michael Walle
` (7 preceding siblings ...)
2013-09-25 18:59 ` [Qemu-devel] [PULL 08/11] target-lm32: move model features to LM32CPU Michael Walle
@ 2013-09-25 18:59 ` Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 10/11] lm32_sys: print test result on stderr Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 11/11] lm32_sys: dump cpu state if test case fails Michael Walle
10 siblings, 0 replies; 12+ messages in thread
From: Michael Walle @ 2013-09-25 18:59 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Walle
This patch adds in-target breakpoint and watchpoint support.
Signed-off-by: Michael Walle <michael@walle.cc>
---
target-lm32/TODO | 2 --
target-lm32/cpu.c | 1 +
target-lm32/cpu.h | 27 ++++++++++++--
target-lm32/helper.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++
target-lm32/helper.h | 3 ++
target-lm32/op_helper.c | 58 +++++++++++++++++++++++++++++-
target-lm32/translate.c | 6 ++--
7 files changed, 178 insertions(+), 8 deletions(-)
diff --git a/target-lm32/TODO b/target-lm32/TODO
index b9ea0c8..e163c42 100644
--- a/target-lm32/TODO
+++ b/target-lm32/TODO
@@ -1,3 +1 @@
-* disassembler (lm32-dis.c)
* linux-user emulation
-* native bp/wp emulation (?)
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index 869878c..2ca8dee 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -71,6 +71,7 @@ static void lm32_cpu_initfn(Object *obj)
if (tcg_enabled() && !tcg_initialized) {
tcg_initialized = true;
lm32_translate_init();
+ cpu_set_debug_excp_handler(lm32_debug_excp_handler);
}
}
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index 67a785e..cef9167 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -172,8 +172,11 @@ struct CPULM32State {
/* debug registers */
uint32_t dc; /* debug control */
- uint32_t bp[4]; /* breakpoint addresses */
- uint32_t wp[4]; /* watchpoint addresses */
+ uint32_t bp[4]; /* breakpoints */
+ uint32_t wp[4]; /* watchpoints */
+
+ CPUBreakpoint * cpu_breakpoint[4];
+ CPUWatchpoint * cpu_watchpoint[4];
CPU_COMMON
@@ -190,6 +193,19 @@ struct CPULM32State {
};
+typedef enum {
+ LM32_WP_DISABLED = 0,
+ LM32_WP_READ,
+ LM32_WP_WRITE,
+ LM32_WP_READ_WRITE,
+} lm32_wp_t;
+
+static inline lm32_wp_t lm32_wp_type(uint32_t dc, int idx)
+{
+ assert(idx < 4);
+ return (dc >> (idx+1)*2) & 0x3;
+}
+
#include "cpu-qom.h"
LM32CPU *cpu_lm32_init(const char *cpu_model);
@@ -202,6 +218,13 @@ int cpu_lm32_signal_handler(int host_signum, void *pinfo,
void *puc);
void lm32_translate_init(void);
void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value);
+void QEMU_NORETURN raise_exception(CPULM32State *env, int index);
+void lm32_debug_excp_handler(CPULM32State *env);
+void lm32_breakpoint_insert(CPULM32State *env, int index, target_ulong address);
+void lm32_breakpoint_remove(CPULM32State *env, int index);
+void lm32_watchpoint_insert(CPULM32State *env, int index, target_ulong address,
+ lm32_wp_t wp_type);
+void lm32_watchpoint_remove(CPULM32State *env, int index);
static inline CPULM32State *cpu_init(const char *cpu_model)
{
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 383bcf3..cff1b95 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -49,6 +49,95 @@ hwaddr lm32_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
}
}
+void lm32_breakpoint_insert(CPULM32State *env, int idx, target_ulong address)
+{
+ cpu_breakpoint_insert(env, address, BP_CPU, &env->cpu_breakpoint[idx]);
+}
+
+void lm32_breakpoint_remove(CPULM32State *env, int idx)
+{
+ if (!env->cpu_breakpoint[idx]) {
+ return;
+ }
+
+ cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[idx]);
+ env->cpu_breakpoint[idx] = NULL;
+}
+
+void lm32_watchpoint_insert(CPULM32State *env, int idx, target_ulong address,
+ lm32_wp_t wp_type)
+{
+ int flags = 0;
+
+ switch (wp_type) {
+ case LM32_WP_DISABLED:
+ /* nothing to to */
+ break;
+ case LM32_WP_READ:
+ flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_READ;
+ break;
+ case LM32_WP_WRITE:
+ flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_WRITE;
+ break;
+ case LM32_WP_READ_WRITE:
+ flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_ACCESS;
+ break;
+ }
+
+ if (flags != 0) {
+ cpu_watchpoint_insert(env, address, 1, flags,
+ &env->cpu_watchpoint[idx]);
+ }
+}
+
+void lm32_watchpoint_remove(CPULM32State *env, int idx)
+{
+ if (!env->cpu_watchpoint[idx]) {
+ return;
+ }
+
+ cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[idx]);
+ env->cpu_watchpoint[idx] = NULL;
+}
+
+static bool check_watchpoints(CPULM32State *env)
+{
+ LM32CPU *cpu = lm32_env_get_cpu(env);
+ int i;
+
+ for (i = 0; i < cpu->def->num_watchpoints; i++) {
+ if (env->cpu_watchpoint[i] &&
+ env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void lm32_debug_excp_handler(CPULM32State *env)
+{
+ CPUBreakpoint *bp;
+
+ if (env->watchpoint_hit) {
+ if (env->watchpoint_hit->flags & BP_CPU) {
+ env->watchpoint_hit = NULL;
+ if (check_watchpoints(env)) {
+ raise_exception(env, EXCP_WATCHPOINT);
+ } else {
+ cpu_resume_from_signal(env, NULL);
+ }
+ }
+ } else {
+ QTAILQ_FOREACH(bp, &env->breakpoints, entry)
+ if (bp->pc == env->pc) {
+ if (bp->flags & BP_CPU) {
+ raise_exception(env, EXCP_BREAKPOINT);
+ }
+ break;
+ }
+ }
+}
+
void lm32_cpu_do_interrupt(CPUState *cs)
{
LM32CPU *cpu = LM32_CPU(cs);
diff --git a/target-lm32/helper.h b/target-lm32/helper.h
index 3ea15a6..ad44fdf 100644
--- a/target-lm32/helper.h
+++ b/target-lm32/helper.h
@@ -2,6 +2,9 @@
DEF_HELPER_2(raise_exception, void, env, i32)
DEF_HELPER_1(hlt, void, env)
+DEF_HELPER_3(wcsr_bp, void, env, i32, i32)
+DEF_HELPER_3(wcsr_wp, void, env, i32, i32)
+DEF_HELPER_2(wcsr_dc, void, env, i32)
DEF_HELPER_2(wcsr_im, void, env, i32)
DEF_HELPER_2(wcsr_ip, void, env, i32)
DEF_HELPER_2(wcsr_jtx, void, env, i32)
diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c
index 8f5ef55..71f21d1 100644
--- a/target-lm32/op_helper.c
+++ b/target-lm32/op_helper.c
@@ -19,12 +19,17 @@
#define SHIFT 3
#include "exec/softmmu_template.h"
-void HELPER(raise_exception)(CPULM32State *env, uint32_t index)
+void raise_exception(CPULM32State *env, int index)
{
env->exception_index = index;
cpu_loop_exit(env);
}
+void HELPER(raise_exception)(CPULM32State *env, uint32_t index)
+{
+ raise_exception(env, index);
+}
+
void HELPER(hlt)(CPULM32State *env)
{
CPUState *cs = CPU(lm32_env_get_cpu(env));
@@ -34,6 +39,57 @@ void HELPER(hlt)(CPULM32State *env)
cpu_loop_exit(env);
}
+void HELPER(wcsr_bp)(CPULM32State *env, uint32_t bp, uint32_t idx)
+{
+ uint32_t addr = bp & ~1;
+
+ assert(idx < 4);
+
+ env->bp[idx] = bp;
+ lm32_breakpoint_remove(env, idx);
+ if (bp & 1) {
+ lm32_breakpoint_insert(env, idx, addr);
+ }
+}
+
+void HELPER(wcsr_wp)(CPULM32State *env, uint32_t wp, uint32_t idx)
+{
+ lm32_wp_t wp_type;
+
+ assert(idx < 4);
+
+ env->wp[idx] = wp;
+
+ wp_type = lm32_wp_type(env->dc, idx);
+ lm32_watchpoint_remove(env, idx);
+ if (wp_type != LM32_WP_DISABLED) {
+ lm32_watchpoint_insert(env, idx, wp, wp_type);
+ }
+}
+
+void HELPER(wcsr_dc)(CPULM32State *env, uint32_t dc)
+{
+ uint32_t old_dc;
+ int i;
+ lm32_wp_t old_type;
+ lm32_wp_t new_type;
+
+ old_dc = env->dc;
+ env->dc = dc;
+
+ for (i = 0; i < 4; i++) {
+ old_type = lm32_wp_type(old_dc, i);
+ new_type = lm32_wp_type(dc, i);
+
+ if (old_type != new_type) {
+ lm32_watchpoint_remove(env, i);
+ if (new_type != LM32_WP_DISABLED) {
+ lm32_watchpoint_insert(env, i, env->wp[i], new_type);
+ }
+ }
+ }
+}
+
void HELPER(wcsr_im)(CPULM32State *env, uint32_t im)
{
lm32_pic_set_im(env->pic_state, im);
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
index c8c862e..5abd2aa 100644
--- a/target-lm32/translate.c
+++ b/target-lm32/translate.c
@@ -873,7 +873,7 @@ static void dec_wcsr(DisasContext *dc)
gen_helper_wcsr_jrx(cpu_env, cpu_R[dc->r1]);
break;
case CSR_DC:
- tcg_gen_mov_tl(cpu_dc, cpu_R[dc->r1]);
+ gen_helper_wcsr_dc(cpu_env, cpu_R[dc->r1]);
break;
case CSR_BP0:
case CSR_BP1:
@@ -885,7 +885,7 @@ static void dec_wcsr(DisasContext *dc)
"breakpoint #%i is not available\n", no);
break;
}
- tcg_gen_mov_tl(cpu_bp[no], cpu_R[dc->r1]);
+ gen_helper_wcsr_bp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no));
break;
case CSR_WP0:
case CSR_WP1:
@@ -897,7 +897,7 @@ static void dec_wcsr(DisasContext *dc)
"watchpoint #%i is not available\n", no);
break;
}
- tcg_gen_mov_tl(cpu_wp[no], cpu_R[dc->r1]);
+ gen_helper_wcsr_wp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no));
break;
case CSR_CC:
case CSR_CFG:
--
1.7.10.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PULL 10/11] lm32_sys: print test result on stderr
2013-09-25 18:59 [Qemu-devel] [PULL 00/11] target-lm32 updates Michael Walle
` (8 preceding siblings ...)
2013-09-25 18:59 ` [Qemu-devel] [PULL 09/11] target-lm32: add breakpoint/watchpoint support Michael Walle
@ 2013-09-25 18:59 ` Michael Walle
2013-09-25 18:59 ` [Qemu-devel] [PULL 11/11] lm32_sys: dump cpu state if test case fails Michael Walle
10 siblings, 0 replies; 12+ messages in thread
From: Michael Walle @ 2013-09-25 18:59 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Walle
Do not use qemu_log().
Signed-off-by: Michael Walle <michael@walle.cc>
---
hw/misc/lm32_sys.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/misc/lm32_sys.c b/hw/misc/lm32_sys.c
index 8176cdb..6af0cca 100644
--- a/hw/misc/lm32_sys.c
+++ b/hw/misc/lm32_sys.c
@@ -80,7 +80,7 @@ static void sys_write(void *opaque, hwaddr addr,
case R_PASSFAIL:
s->regs[addr] = value;
testname = (char *)s->testname;
- qemu_log("TC %-32s %s\n", testname, (value) ? "FAILED" : "OK");
+ fprintf(stderr, "TC %-32s %s\n", testname, (value) ? "FAILED" : "OK");
break;
case R_TESTNAME:
s->regs[addr] = value;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PULL 11/11] lm32_sys: dump cpu state if test case fails
2013-09-25 18:59 [Qemu-devel] [PULL 00/11] target-lm32 updates Michael Walle
` (9 preceding siblings ...)
2013-09-25 18:59 ` [Qemu-devel] [PULL 10/11] lm32_sys: print test result on stderr Michael Walle
@ 2013-09-25 18:59 ` Michael Walle
10 siblings, 0 replies; 12+ messages in thread
From: Michael Walle @ 2013-09-25 18:59 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Walle
This will ease debugging the test cases.
Signed-off-by: Michael Walle <michael@walle.cc>
---
hw/misc/lm32_sys.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/hw/misc/lm32_sys.c b/hw/misc/lm32_sys.c
index 6af0cca..1fd69ff 100644
--- a/hw/misc/lm32_sys.c
+++ b/hw/misc/lm32_sys.c
@@ -81,6 +81,9 @@ static void sys_write(void *opaque, hwaddr addr,
s->regs[addr] = value;
testname = (char *)s->testname;
fprintf(stderr, "TC %-32s %s\n", testname, (value) ? "FAILED" : "OK");
+ if (value) {
+ cpu_dump_state(qemu_get_cpu(0), stderr, fprintf, 0);
+ }
break;
case R_TESTNAME:
s->regs[addr] = value;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 12+ messages in thread