From 322362493647b0f2420ffed35809056cc2b7683a Mon Sep 17 00:00:00 2001 From: Tobias Modschiedler Date: Sat, 8 Jan 2022 21:02:34 +0100 Subject: [PATCH 1/2] feat(DMA): implement DMA sniffing (partially) Implements (parts of) the RP2040 datasheet, chapter 2.5.5.2. Currently, the code disobeys some settings in SNIFF_CTRL. It just assumes OUT_INV = OUT_REV = SNIFF_BSWAP = 0; CALC = 0xf. I.e., it can only do simple summation, no further checksumming. --- src/peripherals/dma.ts | 79 +++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 16 deletions(-) diff --git a/src/peripherals/dma.ts b/src/peripherals/dma.ts index e7f001c..5be9086 100644 --- a/src/peripherals/dma.ts +++ b/src/peripherals/dma.ts @@ -120,6 +120,15 @@ const EN = 1 << 0; const CHn_CTRL_TRIG_WRITE_MASK = 0xffffff; const CHn_CTRL_TRIG_WC_MASK = READ_ERROR | WRITE_ERROR; +// SNIFF_CTRL bits +const OUT_INV = 1 << 11; +const OUT_REV = 1 << 10; +const SNIFF_BSWAP = 1 << 9; +const CALC_MASK = 0xf; +const CALC_SHIFT = 5; +const DMACH_MASK = 0xf; +const DMACH_SHIFT = 1; + export class RPDMAChannel { private ctrl = 0; private readAddr = 0; @@ -158,36 +167,53 @@ export class RPDMAChannel { } transfer8 = () => { - const { rp2040 } = this; - rp2040.writeUint8(this.writeAddr, rp2040.readUint8(this.readAddr)); + const { rp2040, ctrl, dma } = this; + const output = rp2040.readUint8(this.readAddr); + if (ctrl & SNIFF_EN) { + dma.sniffTransfer(this, output); + } + rp2040.writeUint8(this.writeAddr, output); }; transfer16 = () => { - const { rp2040 } = this; - rp2040.writeUint16(this.writeAddr, rp2040.readUint16(this.readAddr)); + const { rp2040, ctrl, dma } = this; + const output = rp2040.readUint16(this.readAddr); + if (ctrl & SNIFF_EN) { + dma.sniffTransfer(this, output); + } + rp2040.writeUint16(this.writeAddr, output); }; transferSwap16 = () => { - const { rp2040 } = this; + const { rp2040, ctrl, dma } = this; const input = rp2040.readUint16(this.readAddr); - rp2040.writeUint16(this.writeAddr, ((input & 0xff) << 8) | (input >> 8)); + const output = ((input & 0xff) << 8) | (input >> 8); + if (ctrl & SNIFF_EN) { + dma.sniffTransfer(this, output); + } + rp2040.writeUint16(this.writeAddr, output); }; transfer32 = () => { - const { rp2040 } = this; - rp2040.writeUint32(this.writeAddr, rp2040.readUint32(this.readAddr)); + const { rp2040, ctrl, dma } = this; + const output = rp2040.readUint32(this.readAddr); + if (ctrl & SNIFF_EN) { + dma.sniffTransfer(this, output); + } + rp2040.writeUint32(this.writeAddr, output); }; transferSwap32 = () => { - const { rp2040 } = this; + const { rp2040, ctrl, dma } = this; const input = rp2040.readUint32(this.readAddr); - rp2040.writeUint32( - this.writeAddr, - ((input & 0x000000ff) << 24) | - ((input & 0x0000ff00) << 8) | - ((input & 0x00ff0000) >> 8) | - ((input >> 24) & 0xff) - ); + const output = ((input & 0x000000ff) << 24) | + ((input & 0x0000ff00) << 8) | + ((input & 0x00ff0000) >> 8) | + ((input >> 24) & 0xff); + if (ctrl & SNIFF_EN) { + dma.sniffTransfer(this, output); + } + rp2040.writeUint32(this.writeAddr, output); }; transfer = () => { @@ -390,6 +416,8 @@ export class RPDMA extends BasePeripheral implements Peripheral { private timer1 = 0; private timer2 = 0; private timer3 = 0; + private sniffCtrl = 0; + private sniffData = 0; readonly dreq: boolean[] = Array(DREQChannel.DREQ_MAX); @@ -429,6 +457,10 @@ export class RPDMA extends BasePeripheral implements Peripheral { return this.intForce1; case INTS1: return this.intStatus1; + case SNIFF_CTRL: + return this.sniffCtrl; + case SNIFF_DATA: + return this.sniffData; case N_CHANNELS: return this.channels.length; } @@ -483,6 +515,12 @@ export class RPDMA extends BasePeripheral implements Peripheral { } } return; + case SNIFF_CTRL: + this.sniffCtrl = value; + return; + case SNIFF_DATA: + this.sniffData = value; + return; case CHAN_ABORT: for (const chan of this.channels) { if (value & (1 << chan.index)) { @@ -549,4 +587,13 @@ export class RPDMA extends BasePeripheral implements Peripheral { this.rp2040.setInterrupt(IRQ.DMA_IRQ0, !!this.intStatus0); this.rp2040.setInterrupt(IRQ.DMA_IRQ1, !!this.intStatus1); } + + sniffTransfer(channel: RPDMAChannel, datum: number) { + const sniffChannel = (this.sniffCtrl >> DMACH_SHIFT) & DMACH_MASK; + if ((this.sniffCtrl & EN) && (channel.index === sniffChannel)) { + // TODO: Actually obey settings in sniffCtrl... + // currently assuming OUT_INV = OUT_REV = SNIFF_BSWAP = 0; CALC = 0xf + this.sniffData += datum; + } + } } From 2d7f9ba99a6ddd58e5c70ec51dc4c5202f6e5222 Mon Sep 17 00:00:00 2001 From: Tobias Modschiedler Date: Sun, 9 Jan 2022 21:13:21 +0100 Subject: [PATCH 2/2] Fix 32-bit overflow in DMA sniffer accumulator --- src/peripherals/dma.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/peripherals/dma.ts b/src/peripherals/dma.ts index 5be9086..0567821 100644 --- a/src/peripherals/dma.ts +++ b/src/peripherals/dma.ts @@ -593,7 +593,7 @@ export class RPDMA extends BasePeripheral implements Peripheral { if ((this.sniffCtrl & EN) && (channel.index === sniffChannel)) { // TODO: Actually obey settings in sniffCtrl... // currently assuming OUT_INV = OUT_REV = SNIFF_BSWAP = 0; CALC = 0xf - this.sniffData += datum; + this.sniffData = (this.sniffData + datum) >>> 0; } } }