Add per-hart arrays for tracking halt, resume-acknowledge, have-reset and reset-halt-request state. The initial DM reset handler clears all arrays consistently using a for loop.
Signed-off-by: Chao Liu <[email protected]> --- hw/riscv/dm.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 183 insertions(+), 10 deletions(-) diff --git a/hw/riscv/dm.c b/hw/riscv/dm.c index 9ac5f2cfac..fad8e2b2ce 100644 --- a/hw/riscv/dm.c +++ b/hw/riscv/dm.c @@ -16,32 +16,148 @@ REG32(DMCONTROL, 0x40) FIELD(DMCONTROL, DMACTIVE, 0, 1) + FIELD(DMCONTROL, HARTSELLO, 6, 10) + FIELD(DMCONTROL, HARTSELHI, 16, 10) + FIELD(DMCONTROL, HASEL, 26, 1) REG32(DMSTATUS, 0x44) FIELD(DMSTATUS, VERSION, 0, 4) + FIELD(DMSTATUS, HASRESETHALTREQ, 5, 1) FIELD(DMSTATUS, AUTHENTICATED, 7, 1) + FIELD(DMSTATUS, ANYHALTED, 8, 1) + FIELD(DMSTATUS, ALLHALTED, 9, 1) + FIELD(DMSTATUS, ANYRUNNING, 10, 1) + FIELD(DMSTATUS, ALLRUNNING, 11, 1) + FIELD(DMSTATUS, ANYNONEXISTENT, 14, 1) + FIELD(DMSTATUS, ALLNONEXISTENT, 15, 1) + FIELD(DMSTATUS, ANYRESUMEACK, 16, 1) + FIELD(DMSTATUS, ALLRESUMEACK, 17, 1) + FIELD(DMSTATUS, ANYHAVERESET, 18, 1) + FIELD(DMSTATUS, ALLHAVERESET, 19, 1) + FIELD(DMSTATUS, IMPEBREAK, 22, 1) REG32(HARTINFO, 0x48) + FIELD(HARTINFO, DATAADDR, 0, 12) + FIELD(HARTINFO, DATASIZE, 12, 4) + FIELD(HARTINFO, DATAACCESS, 16, 1) + FIELD(HARTINFO, NSCRATCH, 20, 4) REG32(ABSTRACTCS, 0x58) FIELD(ABSTRACTCS, DATACOUNT, 0, 4) + FIELD(ABSTRACTCS, CMDERR, 8, 3) + FIELD(ABSTRACTCS, BUSY, 12, 1) FIELD(ABSTRACTCS, PROGBUFSIZE, 24, 5) +static inline uint32_t dm_get_hartsel(RISCVDMState *s) +{ + uint32_t hi = ARRAY_FIELD_EX32(s->regs, DMCONTROL, HARTSELHI); + uint32_t lo = ARRAY_FIELD_EX32(s->regs, DMCONTROL, HARTSELLO); + + return (hi << 10) | lo; +} + +static inline bool dm_hart_valid(RISCVDMState *s, uint32_t hartsel) +{ + return hartsel < s->num_harts; +} + +static void dm_status_refresh(RISCVDMState *s) +{ + uint32_t hartsel = dm_get_hartsel(s); + bool valid = dm_hart_valid(s, hartsel); + bool halted = valid && s->hart_halted[hartsel]; + bool running = valid && !s->hart_halted[hartsel]; + bool resumeack = valid && s->hart_resumeack[hartsel]; + bool havereset = valid && s->hart_havereset[hartsel]; + + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYNONEXISTENT, !valid); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLNONEXISTENT, !valid); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYHALTED, halted); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLHALTED, halted); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYRUNNING, running); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLRUNNING, running); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYRESUMEACK, resumeack); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLRESUMEACK, resumeack); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYHAVERESET, havereset); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLHAVERESET, havereset); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, HASRESETHALTREQ, 1); +} + +static void dm_debug_reset(RISCVDMState *s); + +static uint64_t dm_dmcontrol_pre_write(RegisterInfo *reg, uint64_t val64) +{ + RISCVDMState *s = RISCV_DM(reg->opaque); + uint32_t val = val64; + + if (!FIELD_EX32(val, DMCONTROL, DMACTIVE)) { + dm_debug_reset(s); + return 0; + } + + s->dm_active = true; + + val = FIELD_DP32(val, DMCONTROL, DMACTIVE, 1); + s->regs[R_DMCONTROL] = val; + dm_status_refresh(s); + return val; +} + +static uint64_t dm_dmstatus_post_read(RegisterInfo *reg, uint64_t val) +{ + RISCVDMState *s = RISCV_DM(reg->opaque); + + dm_status_refresh(s); + return val; +} + +static uint64_t dm_hartinfo_post_read(RegisterInfo *reg, uint64_t val) +{ + RISCVDMState *s = RISCV_DM(reg->opaque); + uint32_t v = val; + + v = FIELD_DP32(v, HARTINFO, DATAADDR, RISCV_DM_ROM_DATA); + v = FIELD_DP32(v, HARTINFO, DATASIZE, s->num_abstract_data); + v = FIELD_DP32(v, HARTINFO, DATAACCESS, 1); + v = FIELD_DP32(v, HARTINFO, NSCRATCH, s->nscratch); + return v; +} + static RegisterAccessInfo riscv_dm_regs_info[] = { - { .name = "DMCONTROL", .addr = A_DMCONTROL, }, - { .name = "DMSTATUS", .addr = A_DMSTATUS, .ro = 0xffffffff, }, - { .name = "HARTINFO", .addr = A_HARTINFO, .ro = 0xffffffff, }, - { .name = "ABSTRACTCS", .addr = A_ABSTRACTCS, .ro = 0xffffffff, }, + { .name = "DMCONTROL", .addr = A_DMCONTROL, + .pre_write = dm_dmcontrol_pre_write, }, + { .name = "DMSTATUS", .addr = A_DMSTATUS, + .ro = 0xffffffff, + .post_read = dm_dmstatus_post_read, }, + { .name = "HARTINFO", .addr = A_HARTINFO, + .ro = 0xffffffff, + .post_read = dm_hartinfo_post_read, }, + { .name = "ABSTRACTCS", .addr = A_ABSTRACTCS, + .ro = 0xffffffff, }, }; static uint64_t riscv_dm_read(void *opaque, hwaddr addr, unsigned size) { + RegisterInfoArray *reg_array = opaque; + RISCVDMState *s = RISCV_DM(reg_array->r[0]->opaque); + + if (!s->dm_active && addr != A_DMCONTROL) { + return 0; + } + return register_read_memory(opaque, addr, size); } static void riscv_dm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { + RegisterInfoArray *reg_array = opaque; + RISCVDMState *s = RISCV_DM(reg_array->r[0]->opaque); + + if (!s->dm_active && addr != A_DMCONTROL) { + return; + } + register_write_memory(opaque, addr, value, size); } @@ -75,6 +191,20 @@ static void dm_rom_write(void *opaque, hwaddr offset, RISCVDMState *s = opaque; stn_le_p(s->rom_ptr + offset, size, value); + + if (offset == RISCV_DM_ROM_HARTID && size == 4) { + riscv_dm_hart_halted(s, value); + return; + } + + if (offset == RISCV_DM_ROM_RESUME && size == 4) { + riscv_dm_hart_resumed(s, value); + return; + } + + if (offset == RISCV_DM_ROM_EXCP && size == 4) { + riscv_dm_abstracts_exception(s, dm_get_hartsel(s)); + } } static const MemoryRegionOps dm_rom_ops = { @@ -113,26 +243,38 @@ static bool dm_rom_realize(RISCVDMState *s, Error **errp) void riscv_dm_hart_halted(RISCVDMState *s, uint32_t hartsel) { - (void)s; - (void)hartsel; + if (!dm_hart_valid(s, hartsel)) { + return; + } + + s->hart_halted[hartsel] = true; + riscv_dm_abstracts_done(s, hartsel); + dm_status_refresh(s); } void riscv_dm_hart_resumed(RISCVDMState *s, uint32_t hartsel) { - (void)s; - (void)hartsel; + if (!dm_hart_valid(s, hartsel)) { + return; + } + + s->hart_halted[hartsel] = false; + s->hart_resumeack[hartsel] = true; + dm_status_refresh(s); } void riscv_dm_abstracts_done(RISCVDMState *s, uint32_t hartsel) { - (void)s; (void)hartsel; + ARRAY_FIELD_DP32(s->regs, ABSTRACTCS, BUSY, 0); } void riscv_dm_abstracts_exception(RISCVDMState *s, uint32_t hartsel) { - (void)s; (void)hartsel; + ARRAY_FIELD_DP32(s->regs, ABSTRACTCS, BUSY, 0); + ARRAY_FIELD_DP32(s->regs, ABSTRACTCS, CMDERR, + RISCV_DM_CMDERR_EXCEPTION); } static void dm_debug_reset(RISCVDMState *s) @@ -140,12 +282,23 @@ static void dm_debug_reset(RISCVDMState *s) memset(s->regs, 0, sizeof(s->regs)); ARRAY_FIELD_DP32(s->regs, DMSTATUS, VERSION, 3); ARRAY_FIELD_DP32(s->regs, DMSTATUS, AUTHENTICATED, 1); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, IMPEBREAK, s->impebreak); ARRAY_FIELD_DP32(s->regs, ABSTRACTCS, DATACOUNT, s->num_abstract_data); ARRAY_FIELD_DP32(s->regs, ABSTRACTCS, PROGBUFSIZE, s->progbuf_size); + if (s->hart_halted) { + memset(s->hart_halted, 0, s->num_harts * sizeof(bool)); + memset(s->hart_resumeack, 0, s->num_harts * sizeof(bool)); + memset(s->hart_havereset, 1, s->num_harts * sizeof(bool)); + } + + s->dm_active = false; + if (s->rom_ptr) { memset(s->rom_ptr, 0, RISCV_DM_SIZE); } + + dm_status_refresh(s); } static void riscv_dm_init(Object *obj) @@ -171,6 +324,10 @@ static void riscv_dm_realize(DeviceState *dev, Error **errp) return; } + s->hart_halted = g_new0(bool, s->num_harts); + s->hart_resumeack = g_new0(bool, s->num_harts); + s->hart_havereset = g_new0(bool, s->num_harts); + if (!dm_rom_realize(s, errp)) { return; } @@ -184,6 +341,15 @@ static void riscv_dm_reset_hold(Object *obj, ResetType type) dm_debug_reset(RISCV_DM(obj)); } +static void riscv_dm_unrealize(DeviceState *dev) +{ + RISCVDMState *s = RISCV_DM(dev); + + g_free(s->hart_halted); + g_free(s->hart_resumeack); + g_free(s->hart_havereset); +} + static const Property riscv_dm_props[] = { DEFINE_PROP_UINT32("num-harts", RISCVDMState, num_harts, 1), DEFINE_PROP_UINT32("datacount", RISCVDMState, num_abstract_data, 2), @@ -200,6 +366,12 @@ static const VMStateDescription vmstate_riscv_dm = { .fields = (const VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, RISCVDMState, RISCV_DM_R_MAX), VMSTATE_BOOL(dm_active, RISCVDMState), + VMSTATE_VARRAY_UINT32(hart_halted, RISCVDMState, num_harts, + 0, vmstate_info_bool, bool), + VMSTATE_VARRAY_UINT32(hart_resumeack, RISCVDMState, num_harts, + 0, vmstate_info_bool, bool), + VMSTATE_VARRAY_UINT32(hart_havereset, RISCVDMState, num_harts, + 0, vmstate_info_bool, bool), VMSTATE_END_OF_LIST(), } }; @@ -210,6 +382,7 @@ static void riscv_dm_class_init(ObjectClass *klass, const void *data) ResettableClass *rc = RESETTABLE_CLASS(klass); dc->realize = riscv_dm_realize; + dc->unrealize = riscv_dm_unrealize; dc->vmsd = &vmstate_riscv_dm; device_class_set_props(dc, riscv_dm_props); rc->phases.hold = riscv_dm_reset_hold; -- 2.53.0
