Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | 138x 138x 138x 868x 868x 868x 868x 868x 868x 868x 868x 3x 462x 462x 462x 46x 46x 46x 216x 180x 180x 180x 180x 180x 2x 689x 3200757x 800258x 800231x 800231x 800037x 800037x 219x 215x 215x 219x 219x 205x 205x 19x 19x 207x 207x 207x 207x 207x 207x | /**
* BBC Micro Analogue to Digital Converter (ADC)
* Handles input from analogue sources through various channels
*
* @typedef {import('./analogue-source.js').AnalogueSource} AnalogueSource
*/
export const AdcCentreValue = 0x8000;
// The uPD7002 converts to 12 bits; the AUG gives bits 3-0 of the low byte as always zero.
const LowByteResultBits = 0xf0;
const AdcChannelKeys = ["adc0", "adc1", "adc2", "adc3"];
export class Adc {
/**
* Create a new ADC
* @param {object} sysvia - System VIA interface
* @param {object} scheduler - Scheduler for timing operations
*/
constructor(sysvia, scheduler) {
this.sysvia = sysvia;
this.task = scheduler.newTask(this.onComplete.bind(this));
this.status = 0x40;
this.low = 0x00;
this.high = 0x00;
// Initialize channel sources (one source per channel)
this.channelSources = [null, null, null, null];
this.fixedValue = null;
/** @type {import("./replay.js").InputLog | null} */
this.inputLog = null;
}
/**
* Makes every channel read `value` whatever its source, or read its source again
* with null.
* @param {number|null} value
*/
setFixedValue(value) {
this.fixedValue = value;
}
/**
* Reset the ADC state
*/
reset() {
this.status = 0x40;
this.low = 0x00;
this.high = 0x00;
}
/**
* Set the source for a specific channel, disposing of the one it replaces.
* @param {number} channel - The channel number (0-3)
* @param {AnalogueSource} source - The source to assign to the channel
*/
setChannelSource(channel, source) {
const oldSource = this.channelSources[channel];
if (oldSource && oldSource !== source) oldSource.dispose();
this.channelSources[channel] = source;
}
snapshotState() {
return {
status: this.status,
low: this.low,
high: this.high,
taskOffset: this.task.offset(),
};
}
restoreState(state) {
this.status = state.status;
this.low = state.low;
this.high = state.high;
this.task.restoreOffset(state.taskOffset);
if (this.task.scheduled()) {
// Conversion in progress: CB1 should be high (set by write(), cleared by onComplete())
this.sysvia.setcb1(true);
}
}
/**
* Read from the ADC registers
* @param {number} addr - The address to read from
* @returns {number} The value at the address
*/
read(addr) {
return this.peek(addr);
}
/**
* Read from the ADC registers without side effects; reading the ADC has none, so read() is this
* @param {number} addr - The address to read from
* @returns {number} The value at the address
*/
peek(addr) {
switch (addr & 3) {
case 0:
return this.status;
case 1:
return this.high;
case 2:
return this.low;
default:
break;
}
return 0x40;
}
/**
* Write to the ADC control register
* @param {number} addr - The address to write to
* @param {number} val - The value to write
*/
write(addr, val) {
if ((addr & 3) !== 0) return;
// 8 bit conversion takes 4ms whereas 10 bit conversions take 10ms, according to AUG
this.task.cancel();
this.task.schedule(val & 0x08 ? 20000 : 8000);
this.status = (val & 0x0f) | 0x80;
this.sysvia.setcb1(true);
}
sourceValue(channel) {
const source = this.channelSources[channel];
if (!source) return AdcCentreValue;
const value = source.getValue(channel);
return this.inputLog ? this.inputLog.sample(AdcChannelKeys[channel], value) : value;
}
/**
* Called when the ADC conversion is complete
*/
onComplete() {
const channel = this.status & 0x03;
const val = this.fixedValue ?? this.sourceValue(channel);
// The AUG puts the result's top two bits in status bits 5 and 4.
this.status = (this.status & 0x0f) | 0x40 | ((val >>> 10) & 0x30);
this.low = val & LowByteResultBits;
this.high = (val >>> 8) & 0xff;
this.sysvia.setcb1(false);
}
}
|