Permalink
Browse files

implemented SLEEP instruction for sh4

  • Loading branch information...
inolen committed Jun 19, 2017
1 parent cb6b7bb commit dc698f8d67df9ed914ab8f0027cc30001bd2baa0
@@ -92,6 +92,17 @@ static void sh4_reg_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
sh4->reg[offset] = data;
}
static void sh4_sleep(void *data) {
struct sh4 *sh4 = data;
/* standby / deep sleep mode are not currently supported */
CHECK_EQ(sh4->STBCR->STBY, 0);
CHECK_EQ(sh4->STBCR2->DSLP, 0);
/* do nothing but spin on the current pc until an interrupt is raised */
sh4->ctx.sleep_mode = 1;
}
static void sh4_invalid_instr(void *data) {
struct sh4 *sh4 = data;
@@ -158,6 +169,7 @@ static int sh4_init(struct device *dev) {
sh4->guest->space = sh4->memory_if->space;
sh4->guest->invalid_instr = &sh4_invalid_instr;
sh4->guest->sq_prefetch = &sh4_ccn_sq_prefetch;
sh4->guest->sleep = &sh4_sleep;
sh4->guest->sr_updated = &sh4_sr_updated;
sh4->guest->fpscr_updated = &sh4_fpscr_updated;
sh4->guest->lookup = &as_lookup;
@@ -13,14 +13,20 @@ static struct sh4_interrupt_info sh4_interrupts[NUM_SH_INTERRUPTS] = {
void sh4_intc_update_pending(struct sh4 *sh4) {
int min_priority = (sh4->ctx.sr & I_MASK) >> I_BIT;
uint64_t priority_mask = ~sh4->priority_mask[min_priority];
uint64_t mask = ~sh4->priority_mask[min_priority];
int block = (sh4->ctx.sr & BL_MASK) == BL_MASK;
/* ignore block bit when sleeping */
if (sh4->ctx.sleep_mode) {
block = 0;
}
/* mask all interrupts if interrupt block bit is set */
if (sh4->ctx.sr & BL_MASK) {
priority_mask = 0;
if (block) {
mask = 0;
}
sh4->ctx.pending_interrupts = sh4->requested_interrupts & priority_mask;
sh4->ctx.pending_interrupts = sh4->requested_interrupts & mask;
}
void sh4_intc_check_pending(void *data) {
@@ -44,6 +50,7 @@ void sh4_intc_check_pending(void *data) {
sh4->ctx.sgr = sh4->ctx.r[15];
sh4->ctx.sr |= (BL_MASK | MD_MASK | RB_MASK);
sh4->ctx.pc = sh4->ctx.vbr + 0x600;
sh4->ctx.sleep_mode = 0;
sh4_sr_updated(sh4, sh4->ctx.ssr);
}
@@ -78,10 +78,10 @@ SH4_REG(0xffa00084, DAR7, 0x00000000, uint32_t)
SH4_REG(0xffa00088, DMATCR7, 0x00000000, uint32_t)
SH4_REG(0xffa0008c, CHCR7, 0x00000000, union chcr)
SH4_REG(0xffc00000, FRQCR, 0x00000000, uint32_t)
SH4_REG(0xffc00004, STBCR, 0x00000000, uint32_t)
SH4_REG(0xffc00004, STBCR, 0x00000000, union stbcr)
SH4_REG(0xffc00008, WTCNT, 0x00000000, uint32_t)
SH4_REG(0xffc0000c, WTCSR, 0x00000000, uint32_t)
SH4_REG(0xffc00010, STBCR2, 0x00000000, uint32_t)
SH4_REG(0xffc00010, STBCR2, 0x00000000, union stbcr2)
SH4_REG(0xffc80000, R64CNT, 0x00000000, uint32_t)
SH4_REG(0xffc80004, RSECCNT, 0x00000000, uint32_t)
SH4_REG(0xffc80008, RMINCNT, 0x00000000, uint32_t)
@@ -64,6 +64,30 @@ union dmaor {
};
};
union stbcr {
uint32_t full;
struct {
uint32_t MSTP0 : 1;
uint32_t MSTP1 : 1;
uint32_t MSTP2 : 1;
uint32_t MSTP3 : 1;
uint32_t MSTP4 : 1;
uint32_t PPU : 1;
uint32_t PHZ : 1;
uint32_t STBY : 1;
uint32_t : 24;
};
};
union stbcr2 {
uint32_t full;
struct {
uint32_t : 7;
uint32_t DSLP : 1;
uint32_t : 24;
};
};
/* control register area (0xfc000000 - 0xffffffff) contains only 16kb of
physical memory. this memory is mapped as 64 x 256 byte blocks, with the
block index being encoded in bits 17-24 of the address, and the block
@@ -3,7 +3,9 @@
#include <stdint.h>
/* SR bits */
/*
* SR bits
*/
/* true / false condition or carry/borrow bit */
#define T_BIT 0
@@ -38,7 +40,9 @@
(MD_MASK | RB_MASK | BL_MASK | FD_MASK | M_MASK | Q_MASK | I_MASK | S_MASK | \
T_MASK)
/* FPSCR bits */
/*
* FPSCR bits
*/
/* denormalization mode */
#define DN_BIT 18
@@ -110,6 +114,9 @@ struct sh4_context {
uint64_t pending_interrupts;
uint32_t sq[2][8];
/* processor sleep state */
uint32_t sleep_mode;
/* the main dispatch loop is ran until remaining_cycles is <= 0 */
int32_t run_cycles;
@@ -384,6 +384,9 @@ typedef int32_t int128_t[4];
#define INVALID_INSTR() guest->invalid_instr(guest->data)
#define PREF_SQ_COND(c, addr) if (c) { guest->sq_prefetch(guest->data, addr); }
#define SLEEP() guest->sleep(guest->data)
/* clang-format on */
#define INSTR(name) \
@@ -9,6 +9,7 @@ struct sh4_guest {
/* runtime interface */
void (*invalid_instr)(void *);
void (*sq_prefetch)(void *, uint32_t);
void (*sleep)(void *);
void (*sr_updated)(void *, uint32_t);
void (*fpscr_updated)(void *, uint32_t);
};
@@ -1370,7 +1370,7 @@ INSTR(SETT) {
/* SLEEP */
INSTR(SLEEP) {
LOG_FATAL("SLEEP not implemented");
SLEEP();
}
/* STC SR,Rn */
@@ -167,7 +167,7 @@ SH4_INSTR(PREF, "pref @rn", 0000nnnn10000011, 1, SH4_FL
SH4_INSTR(RTE, "rte", 0000000000101011, 5, SH4_FLAG_SET_PC | SH4_FLAG_DELAYED | SH4_FLAG_SET_SR)
SH4_INSTR(SETS, "sets", 0000000001011000, 1, 0)
SH4_INSTR(SETT, "sett", 0000000000011000, 1, 0)
SH4_INSTR(SLEEP, "sleep", 0000000000011011, 4, 0)
SH4_INSTR(SLEEP, "sleep", 0000000000011011, 4, SH4_FLAG_SET_PC)
SH4_INSTR(STCSR, "stc sr, rn", 0000nnnn00000010, 2, 0)
SH4_INSTR(STCGBR, "stc gbr, rn", 0000nnnn00010010, 2, 0)
SH4_INSTR(STCVBR, "stc vbr, rn", 0000nnnn00100010, 2, 0)
@@ -435,6 +435,13 @@ static void store_fpscr(struct sh4_guest *guest, struct ir *ir,
struct ir_value *data = ir_alloc_i64(ir, (uint64_t)guest->data); \
ir_call_cond_2(ir, c, sq_prefetch, data, addr); \
}
#define SLEEP() { \
struct ir_value *sleep = ir_alloc_i64(ir, (uint64_t)guest->sleep); \
struct ir_value *data = ir_alloc_i64(ir, (uint64_t)guest->data); \
ir_call_1(ir, sleep, data); \
}
/* clang-format on */
#define INSTR(name) \

0 comments on commit dc698f8

Please sign in to comment.