mirror of
https://github.com/MCKero6423/uv-k5-v3-emulator.git
synced 2026-10-02 11:07:31 +00:00
Make the ADC settable, which reaches the battery behaviour
Prompted by a fair criticism: the reports said what runs, not what is actually reproduced. An audit found the ADC was modelled but returned a hardcoded 2200 forever, so gBatteryDisplayLevel, gLowBattery and the warning popup were all unreachable. A peripheral that answers reads is not the same as a peripheral that is reproduced. adc-result is now settable over QOM and clamped to 12 bits. Measured: 2200 gives level 4 and no warning, 1200 gives level 0 and raises gLowBattery, and the level recovers to 4 afterwards. tools/test_battery.py covers it, and deliberately does NOT assert that gLowBattery clears on recovery. helper/battery.c:190-204 only clears it when the level lands exactly on 2; above that it clears gLowBatteryConfirmed and leaves gLowBattery set. So 4 -> 0 -> 4 really does leave the flag raised. The first version of this test called that a failure -- the test was wrong, not the model. The emulator reproduces the firmware, including behaviour that looks like a bug.
This commit is contained in:
1 parent
7ed9f61f71
commit
e46cae2e48
4 files changed
+245
-3
No files matched your search
+44
-3
@@ -2005,6 +2005,7 @@ struct PY32AdcState {
|
||||
SysBusDevice parent_obj;
|
||||
MemoryRegion iomem;
|
||||
uint32_t regs[0x20];
|
||||
uint32_t result; /* what a conversion returns; see PY32_ADC_RESULT */
|
||||
};
|
||||
|
||||
#define ADC_SR 0x00
|
||||
@@ -2023,8 +2024,15 @@ struct PY32AdcState {
|
||||
#define ADC_CR2_RSTCAL (1u << 3)
|
||||
#define ADC_CR2_SWSTART (1u << 22)
|
||||
|
||||
/* Battery sits around 7.4 V; the calibration table in flash maps raw counts to
|
||||
* volts, and 2200 lands mid-scale on a real dump. */
|
||||
/*
|
||||
* Battery sits around 7.4 V; the calibration table in flash maps raw counts to volts,
|
||||
* and 2200 lands mid-scale on a real dump.
|
||||
*
|
||||
* Settable at runtime via the "adc-result" property, because a fixed reading cannot
|
||||
* exercise anything interesting. The firmware derives gBatteryDisplayLevel from this
|
||||
* and raises gLowBattery plus a warning popup below a threshold -- none of which can be
|
||||
* reached, let alone tested, while the value never moves.
|
||||
*/
|
||||
#define PY32_ADC_RESULT 2200
|
||||
|
||||
static uint64_t py32_adc_read(void *opaque, hwaddr addr, unsigned size)
|
||||
@@ -2039,7 +2047,7 @@ static uint64_t py32_adc_read(void *opaque, hwaddr addr, unsigned size)
|
||||
if (addr == ADC_DR) {
|
||||
/* Reading the result clears end-of-conversion, as on hardware. */
|
||||
s->regs[ADC_SR >> 2] &= ~ADC_SR_EOC;
|
||||
return PY32_ADC_RESULT;
|
||||
return s->result;
|
||||
}
|
||||
return s->regs[idx];
|
||||
}
|
||||
@@ -2090,6 +2098,27 @@ static void py32_adc_reset(DeviceState *dev)
|
||||
{
|
||||
PY32AdcState *s = PY32_ADC(dev);
|
||||
memset(s->regs, 0, sizeof(s->regs));
|
||||
s->result = PY32_ADC_RESULT;
|
||||
}
|
||||
|
||||
static void py32_adc_get_result(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
uint64_t value = PY32_ADC(obj)->result;
|
||||
visit_type_uint64(v, name, &value, errp);
|
||||
}
|
||||
|
||||
static void py32_adc_set_result(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
PY32AdcState *s = PY32_ADC(obj);
|
||||
uint64_t value;
|
||||
|
||||
if (!visit_type_uint64(v, name, &value, errp)) {
|
||||
return;
|
||||
}
|
||||
/* 12-bit converter: clamp rather than wrap, so a silly value is obvious. */
|
||||
s->result = value > 0xfff ? 0xfff : value;
|
||||
}
|
||||
|
||||
static void py32_adc_init(Object *obj)
|
||||
@@ -2104,6 +2133,18 @@ static void py32_adc_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
dc->reset = py32_adc_reset;
|
||||
dc->desc = "PY32F071 ADC";
|
||||
|
||||
/*
|
||||
* Settable so battery behaviour can be exercised. The firmware turns this raw
|
||||
* count into gBatteryDisplayLevel via the calibration table in flash, and raises
|
||||
* gLowBattery with a warning popup below a threshold; with a fixed reading none of
|
||||
* that is reachable.
|
||||
*/
|
||||
object_class_property_add(klass, "adc-result", "uint64",
|
||||
py32_adc_get_result, py32_adc_set_result,
|
||||
NULL, NULL);
|
||||
object_class_property_set_description(klass, "adc-result",
|
||||
"raw 12-bit ADC conversion result, which the firmware reads as battery voltage");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in new issue
Block a user