aboutsummaryrefslogtreecommitdiff
path: root/target-alpha
diff options
context:
space:
mode:
Diffstat (limited to 'target-alpha')
-rw-r--r--target-alpha/cpu.h4
-rw-r--r--target-alpha/helper.h5
-rw-r--r--target-alpha/op_helper.c25
-rw-r--r--target-alpha/translate.c77
4 files changed, 95 insertions, 16 deletions
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index c2e7bb31ef..9d61d45ab6 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -265,6 +265,10 @@ struct CPUAlphaState {
uint64_t scratch[24];
#endif
+ /* This alarm doesn't exist in real hardware; we wish it did. */
+ struct QEMUTimer *alarm_timer;
+ uint64_t alarm_expire;
+
#if TARGET_LONG_BITS > HOST_LONG_BITS
/* temporary fixed-point registers
* used to emulate 64 bits target on 32 bits hosts
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index 2dec57e44b..b693ceea97 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -113,6 +113,11 @@ DEF_HELPER_2(stq_c_phys, i64, i64, i64)
DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void)
DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64)
+
+DEF_HELPER_1(halt, void, i64);
+
+DEF_HELPER_FLAGS_0(get_time, TCG_CALL_CONST, i64)
+DEF_HELPER_FLAGS_1(set_alarm, TCG_CALL_CONST, void, i64)
#endif
#include "def-helper.h"
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index d8945dcbca..cc102dbd63 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -22,6 +22,7 @@
#include "host-utils.h"
#include "softfloat.h"
#include "helper.h"
+#include "sysemu.h"
#include "qemu-timer.h"
#define FP_STATUS (env->fp_status)
@@ -1218,6 +1219,30 @@ void helper_tbis(uint64_t p)
{
tlb_flush_page(env, p);
}
+
+void helper_halt(uint64_t restart)
+{
+ if (restart) {
+ qemu_system_reset_request();
+ } else {
+ qemu_system_shutdown_request();
+ }
+}
+
+uint64_t helper_get_time(void)
+{
+ return qemu_get_clock_ns(rtc_clock);
+}
+
+void helper_set_alarm(uint64_t expire)
+{
+ if (expire) {
+ env->alarm_expire = expire;
+ qemu_mod_timer(env->alarm_timer, expire);
+ } else {
+ qemu_del_timer(env->alarm_timer);
+ }
+}
#endif
/*****************************************************************************/
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 1e224a2152..a961159d5d 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1590,18 +1590,34 @@ static int cpu_pr_data(int pr)
return offsetof(CPUAlphaState, shadow[pr - 32]);
case 40 ... 63:
return offsetof(CPUAlphaState, scratch[pr - 40]);
+
+ case 251:
+ return offsetof(CPUAlphaState, alarm_expire);
}
return 0;
}
-static void gen_mfpr(int ra, int regno)
+static ExitStatus gen_mfpr(int ra, int regno)
{
int data = cpu_pr_data(regno);
/* In our emulated PALcode, these processor registers have no
side effects from reading. */
if (ra == 31) {
- return;
+ return NO_EXIT;
+ }
+
+ if (regno == 250) {
+ /* WALL_TIME */
+ if (use_icount) {
+ gen_io_start();
+ gen_helper_get_time(cpu_ir[ra]);
+ gen_io_end();
+ return EXIT_PC_STALE;
+ } else {
+ gen_helper_get_time(cpu_ir[ra]);
+ return NO_EXIT;
+ }
}
/* The basic registers are data only, and unknown registers
@@ -1615,11 +1631,13 @@ static void gen_mfpr(int ra, int regno)
} else {
tcg_gen_ld_i64(cpu_ir[ra], cpu_env, data);
}
+ return NO_EXIT;
}
-static void gen_mtpr(int rb, int regno)
+static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno)
{
TCGv tmp;
+ int data;
if (rb == 31) {
tmp = tcg_const_i64(0);
@@ -1627,19 +1645,37 @@ static void gen_mtpr(int rb, int regno)
tmp = cpu_ir[rb];
}
- /* These two register numbers perform a TLB cache flush. Thankfully we
- can only do this inside PALmode, which means that the current basic
- block cannot be affected by the change in mappings. */
- if (regno == 255) {
+ switch (regno) {
+ case 255:
/* TBIA */
gen_helper_tbia();
- } else if (regno == 254) {
+ break;
+
+ case 254:
/* TBIS */
gen_helper_tbis(tmp);
- } else {
+ break;
+
+ case 253:
+ /* WAIT */
+ tmp = tcg_const_i64(1);
+ tcg_gen_st32_i64(tmp, cpu_env, offsetof(CPUState, halted));
+ return gen_excp(ctx, EXCP_HLT, 0);
+
+ case 252:
+ /* HALT */
+ gen_helper_halt(tmp);
+ return EXIT_PC_STALE;
+
+ case 251:
+ /* ALARM */
+ gen_helper_set_alarm(tmp);
+ break;
+
+ default:
/* The basic registers are data only, and unknown registers
are read-zero, write-ignore. */
- int data = cpu_pr_data(regno);
+ data = cpu_pr_data(regno);
if (data != 0) {
if (data & PR_BYTE) {
tcg_gen_st8_i64(tmp, cpu_env, data & ~PR_BYTE);
@@ -1649,11 +1685,14 @@ static void gen_mtpr(int rb, int regno)
tcg_gen_st_i64(tmp, cpu_env, data);
}
}
+ break;
}
if (rb == 31) {
tcg_temp_free(tmp);
}
+
+ return NO_EXIT;
}
#endif /* !USER_ONLY*/
@@ -2721,8 +2760,16 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0xC000:
/* RPCC */
- if (ra != 31)
- gen_helper_load_pcc(cpu_ir[ra]);
+ if (ra != 31) {
+ if (use_icount) {
+ gen_io_start();
+ gen_helper_load_pcc(cpu_ir[ra]);
+ gen_io_end();
+ ret = EXIT_PC_STALE;
+ } else {
+ gen_helper_load_pcc(cpu_ir[ra]);
+ }
+ }
break;
case 0xE000:
/* RC */
@@ -2747,8 +2794,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
/* HW_MFPR (PALcode) */
#ifndef CONFIG_USER_ONLY
if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
- gen_mfpr(ra, insn & 0xffff);
- break;
+ return gen_mfpr(ra, insn & 0xffff);
}
#endif
goto invalid_opc;
@@ -3053,8 +3099,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
/* HW_MTPR (PALcode) */
#ifndef CONFIG_USER_ONLY
if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
- gen_mtpr(rb, insn & 0xffff);
- break;
+ return gen_mtpr(ctx, rb, insn & 0xffff);
}
#endif
goto invalid_opc;