diff --git a/src/gpio-pin.ts b/src/gpio-pin.ts index d81218c654..76a2de9bb0 100644 --- a/src/gpio-pin.ts +++ b/src/gpio-pin.ts @@ -7,6 +7,7 @@ export enum GPIOPinState { Input, InputPullUp, InputPullDown, + InputBusKeeper, } export const FUNCTION_PWM = 4; @@ -186,10 +187,13 @@ export class GPIOPin { return this.outputValue ? GPIOPinState.High : GPIOPinState.Low; } else { // TODO: check what happens when we enable both pullup/pulldown - if (this.pulldownEnabled) { + // ANSWER: It is valid, see: 2.19.4.1. Bus Keeper Mode, datasheet p240 + if (this.pulldownEnabled && this.pullupEnabled) { + // Pull high when high, pull low when low: + return GPIOPinState.InputBusKeeper; + } else if (this.pulldownEnabled) { return GPIOPinState.InputPullDown; - } - if (this.pullupEnabled) { + } else if (this.pullupEnabled) { return GPIOPinState.InputPullUp; } return GPIOPinState.Input; diff --git a/src/peripherals/clocks.ts b/src/peripherals/clocks.ts index f71fa79fc4..deb879bced 100644 --- a/src/peripherals/clocks.ts +++ b/src/peripherals/clocks.ts @@ -1,40 +1,198 @@ import { RP2040 } from '../rp2040.js'; import { BasePeripheral, Peripheral } from './peripheral.js'; +const CLK_GPOUT0_CTRL = 0x00; +const CLK_GPOUT0_DIV = 0x04; +const CLK_GPOUT0_SELECTED = 0x8; +const CLK_GPOUT1_CTRL = 0x0c; +const CLK_GPOUT1_DIV = 0x10; +const CLK_GPOUT1_SELECTED = 0x14; +const CLK_GPOUT2_CTRL = 0x18; +const CLK_GPOUT2_DIV = 0x01c; +const CLK_GPOUT2_SELECTED = 0x20; +const CLK_GPOUT3_CTRL = 0x24; +const CLK_GPOUT3_DIV = 0x28; +const CLK_GPOUT3_SELECTED = 0x2c; const CLK_REF_CTRL = 0x30; +const CLK_REF_DIV = 0x34; const CLK_REF_SELECTED = 0x38; const CLK_SYS_CTRL = 0x3c; +const CLK_SYS_DIV = 0x40; const CLK_SYS_SELECTED = 0x44; +const CLK_PERI_CTRL = 0x48; +const CLK_PERI_DIV = 0x4c; +const CLK_PERI_SELECTED = 0x50; +const CLK_USB_CTRL = 0x54; +const CLK_USB_DIV = 0x58; +const CLK_USB_SELECTED = 0x5c; +const CLK_ADC_CTRL = 0x60; +const CLK_ADC_DIV = 0x64; +const CLK_ADC_SELECTED = 0x68; +const CLK_RTC_CTRL = 0x6c; +const CLK_RTC_DIV = 0x70; +const CLK_RTC_SELECTED = 0x74; +const CLK_SYS_RESUS_CTRL = 0x78; +const CLK_SYS_RESUS_STATUS = 0x7c; export class RPClocks extends BasePeripheral implements Peripheral { + gpout0Ctrl = 0; + gpout0Div = 0x100; + gpout1Ctrl = 0; + gpout1Div = 0x100; + gpout2Ctrl = 0; + gpout2Div = 0x100; + gpout3Ctrl = 0; + gpout3Div = 0x100; refCtrl = 0; + refDiv = 0x100; + periCtrl = 0; + periDiv = 0x100; + usbCtrl = 0; + usbDiv = 0x100; sysCtrl = 0; + sysDiv = 0x100; + adcCtrl = 0; + adcDiv = 0x100; + rtcCtrl = 0; + rtcDiv = 0x100; constructor(rp2040: RP2040, name: string) { super(rp2040, name); } readUint32(offset: number) { switch (offset) { + case CLK_GPOUT0_CTRL: + return this.gpout0Ctrl & 0b100110001110111100000; + case CLK_GPOUT0_DIV: + return this.gpout0Div; + case CLK_GPOUT0_SELECTED: + return 1; + case CLK_GPOUT1_CTRL: + return this.gpout1Ctrl & 0b100110001110111100000; + case CLK_GPOUT1_DIV: + return this.gpout1Div; + case CLK_GPOUT1_SELECTED: + return 1; + case CLK_GPOUT2_CTRL: + return this.gpout2Ctrl & 0b100110001110111100000; + case CLK_GPOUT2_DIV: + return this.gpout2Div; + case CLK_GPOUT2_SELECTED: + return 1; + case CLK_GPOUT3_CTRL: + return this.gpout3Ctrl & 0b100110001110111100000; + case CLK_GPOUT3_DIV: + return this.gpout3Div; + case CLK_GPOUT3_SELECTED: + return 1; case CLK_REF_CTRL: - return this.refCtrl; + return this.refCtrl & 0b000001100011; + case CLK_REF_DIV: + return this.refDiv & 0x30; // b8..9 = int divisor. no frac divisor present case CLK_REF_SELECTED: return 1 << (this.refCtrl & 0x03); case CLK_SYS_CTRL: - return this.sysCtrl; + return this.sysCtrl & 0b000011100001; + case CLK_SYS_DIV: + return this.sysDiv; case CLK_SYS_SELECTED: return 1 << (this.sysCtrl & 0x01); + case CLK_PERI_CTRL: + return this.periCtrl & 0b110011100000; + case CLK_PERI_DIV: + return this.periDiv; + case CLK_PERI_SELECTED: + return 1; + case CLK_USB_CTRL: + return this.usbCtrl & 0b100110000110011100000; + case CLK_USB_DIV: + return this.usbDiv; + case CLK_USB_SELECTED: + return 1; + case CLK_ADC_CTRL: + return this.adcCtrl & 0b100110000110011100000; + case CLK_ADC_DIV: + return this.adcDiv & 0x30; + case CLK_ADC_SELECTED: + return 1; + case CLK_RTC_CTRL: + return this.rtcCtrl & 0b100110000110011100000; + case CLK_RTC_DIV: + return this.rtcDiv & 0x30; + case CLK_RTC_SELECTED: + return 1; + case CLK_SYS_RESUS_CTRL: + return 0xff; + case CLK_SYS_RESUS_STATUS: + return 0; /* clock resus not implemented */ } return super.readUint32(offset); } writeUint32(offset: number, value: number): void { switch (offset) { + case CLK_GPOUT0_CTRL: + this.gpout0Ctrl = value; + break; + case CLK_GPOUT0_DIV: + this.gpout0Div = value; + break; + case CLK_GPOUT1_CTRL: + this.gpout1Ctrl = value; + break; + case CLK_GPOUT1_DIV: + this.gpout1Div = value; + break; + case CLK_GPOUT2_CTRL: + this.gpout2Ctrl = value; + break; + case CLK_GPOUT2_DIV: + this.gpout2Div = value; + break; + case CLK_GPOUT3_CTRL: + this.gpout3Ctrl = value; + break; + case CLK_GPOUT3_DIV: + this.gpout3Div = value; + break; case CLK_REF_CTRL: this.refCtrl = value; break; + case CLK_REF_DIV: + this.refDiv = value; + break; case CLK_SYS_CTRL: this.sysCtrl = value; break; + case CLK_SYS_DIV: + this.sysDiv = value; + break; + case CLK_PERI_CTRL: + this.periCtrl = value; + break; + case CLK_PERI_DIV: + this.periDiv = value; + break; + case CLK_USB_CTRL: + this.usbCtrl = value; + break; + case CLK_USB_DIV: + this.usbDiv = value; + break; + case CLK_ADC_CTRL: + this.adcCtrl = value; + break; + case CLK_ADC_DIV: + this.adcDiv = value; + break; + case CLK_RTC_CTRL: + this.rtcCtrl = value; + break; + case CLK_RTC_DIV: + this.rtcDiv = value; + break; + case CLK_SYS_RESUS_CTRL: + return; /* clock resus not implemented */ default: super.writeUint32(offset, value); break; diff --git a/src/peripherals/i2c.ts b/src/peripherals/i2c.ts index 2fc5929bae..0389309acc 100644 --- a/src/peripherals/i2c.ts +++ b/src/peripherals/i2c.ts @@ -171,6 +171,7 @@ export class RPI2C extends BasePeripheral implements Peripheral { abortSource = 0; intRaw = 0; intEnable = 0; + private spikelen = 0x07; get intStatus() { return this.intRaw & this.intEnable; @@ -428,11 +429,18 @@ export class RPI2C extends BasePeripheral implements Peripheral { return this.txFIFO.itemCount; case IC_RXFLR: return this.rxFIFO.itemCount; + case IC_SDA_HOLD: + return 0x01; case IC_TX_ABRT_SOURCE: { const value = this.abortSource; this.abortSource &= ABRT_SBYTE_NORSTRT; // Clear IC_TX_ABRT_SOURCE, expect for bit 9 return value; } + case IC_ENABLE_STATUS: + // I2C status - read only. bit 0 reflects IC_ENABLE, bit 1,2 relate to i2c slave mode. + return this.enable & 0x1; + case IC_FS_SPKLEN: + return this.spikelen & 0xff; case IC_COMP_PARAM_1: // From the datasheet: // Note This register is not implemented and therefore reads as 0. If it was implemented it would be a constant read-only @@ -489,6 +497,14 @@ export class RPI2C extends BasePeripheral implements Peripheral { this.fsClockLowPeriod = value & 0xffff; return; + case IC_SDA_HOLD: + if (!(value & ENABLE)) { + if (value != 0x1) { + this.warn('Unimplemented write to IC_SDA_HOLD'); + } + } + return; + case IC_RX_TL: this.rxThreshold = value & 0xff; if (this.rxThreshold > this.rxFIFO.size) { @@ -522,6 +538,12 @@ export class RPI2C extends BasePeripheral implements Peripheral { this.nextCommand(); // TX_CMD_BLOCK may have changed return; + case IC_FS_SPKLEN: + if (!(value & ENABLE) && value > 0) { + this.spikelen = value; + } + return; + default: super.writeUint32(offset, value); } diff --git a/src/peripherals/peripheral.ts b/src/peripherals/peripheral.ts index cafb9942f9..a443493f66 100644 --- a/src/peripherals/peripheral.ts +++ b/src/peripherals/peripheral.ts @@ -34,7 +34,7 @@ export class BasePeripheral implements Peripheral { ) {} readUint32(offset: number) { - this.warn(`Unimplemented peripheral read from ${offset.toString(16)}`); + this.warn(`Unimplemented peripheral read from 0x${offset.toString(16)}`); if (offset > 0x1000) { this.warn('Unimplemented read from peripheral in the atomic operation region'); } @@ -42,7 +42,9 @@ export class BasePeripheral implements Peripheral { } writeUint32(offset: number, value: number) { - this.warn(`Unimplemented peripheral write to ${offset.toString(16)}: ${value}`); + this.warn( + `Unimplemented peripheral write to 0x${offset.toString(16)}: 0x${value.toString(16)}`, + ); } writeUint32Atomic(offset: number, value: number, atomicType: number) { diff --git a/src/peripherals/ssi.ts b/src/peripherals/ssi.ts index 43c330174b..e95ef5acd0 100644 --- a/src/peripherals/ssi.ts +++ b/src/peripherals/ssi.ts @@ -1,33 +1,79 @@ import { BasePeripheral, Peripheral } from './peripheral.js'; +/* See RP2040 datasheet sect 4.10.13 */ +const SSI_CTRLR0 = 0x00000000; +const SSI_CTRLR1 = 0x00000004; +const SSI_SSIENR = 0x00000008; +const SSI_MWCR = 0x0000000c; +const SSI_SER = 0x00000010; +const SSI_BAUDR = 0x00000014; +const SSI_TXFTLR = 0x00000018; +const SSI_RXFTLR = 0x0000001c; const SSI_TXFLR = 0x00000020; const SSI_RXFLR = 0x00000024; const SSI_SR = 0x00000028; -const SSI_DR0 = 0x00000060; const SSI_SR_TFNF_BITS = 0x00000002; const SSI_SR_TFE_BITS = 0x00000004; const SSI_SR_RFNE_BITS = 0x00000008; +const SSI_IMR = 0x0000002c; +const SSI_ISR = 0x00000030; +const SSI_RISR = 0x00000034; +const SSI_TXOICR = 0x00000038; +const SSI_RXOICR = 0x0000003c; +const SSI_RXUICR = 0x00000040; +const SSI_MSTICR = 0x00000044; +const SSI_ICR = 0x00000048; +const SSI_DMACR = 0x0000004c; +const SSI_DMATDLR = 0x00000050; +const SSI_DMARDLR = 0x00000054; /** Identification register */ const SSI_IDR = 0x00000058; const SSI_VERSION_ID = 0x0000005c; +const SSI_DR0 = 0x00000060; +const SSI_RX_SAMPLE_DLY = 0x000000f0; +const SSI_SPI_CTRL_R0 = 0x000000f4; +const SSI_TXD_DRIVE_EDGE = 0x000000f8; const CMD_READ_STATUS = 0x05; export class RPSSI extends BasePeripheral implements Peripheral { private dr0 = 0; + private txflr = 0; + private rxflr = 0; + private baudr = 0; + private crtlr0 = 0; + private crtlr1 = 0; + private ssienr = 0; + private spictlr0 = 0; + private rxsampldly = 0; + private txddriveedge = 0; readUint32(offset: number) { switch (offset) { case SSI_TXFLR: - return 0; + return this.txflr; case SSI_RXFLR: - return 0; + return this.rxflr; + case SSI_CTRLR0: + return this.crtlr0; /* & 0x017FFFFF = b23,b25..31 reserved */ + case SSI_CTRLR1: + return this.crtlr1; + case SSI_SSIENR: + return this.ssienr; + case SSI_BAUDR: + return this.baudr; case SSI_SR: return SSI_SR_TFE_BITS | SSI_SR_RFNE_BITS | SSI_SR_TFNF_BITS; case SSI_IDR: return 0x51535049; case SSI_VERSION_ID: return 0x3430312a; + case SSI_RX_SAMPLE_DLY: + return this.rxsampldly; + case SSI_TXD_DRIVE_EDGE: + return this.txddriveedge; + case SSI_SPI_CTRL_R0: + return this.spictlr0; /* b6,7,10,19..23 reserved */ case SSI_DR0: return this.dr0; } @@ -36,6 +82,33 @@ export class RPSSI extends BasePeripheral implements Peripheral { writeUint32(offset: number, value: number) { switch (offset) { + case SSI_TXFLR: + this.txflr = value; + return; + case SSI_RXFLR: + this.rxflr = value; + return; + case SSI_CTRLR0: + this.crtlr0 = value; /* & 0x017FFFFF = b23,b25..31 reserved */ + return; + case SSI_CTRLR1: + this.crtlr1 = value; + return; + case SSI_SSIENR: + this.ssienr = value; + return; + case SSI_BAUDR: + this.baudr = value; + return; + case SSI_RX_SAMPLE_DLY: + this.rxsampldly = value & 0xff; + return; + case SSI_TXD_DRIVE_EDGE: + this.txddriveedge = value & 0xff; + return; + case SSI_SPI_CTRL_R0: + this.spictlr0 = value; + return; case SSI_DR0: if (value === CMD_READ_STATUS) { this.dr0 = 0; // tell stage2 that we completed a write diff --git a/src/peripherals/usb.ts b/src/peripherals/usb.ts index 2d154fb2c4..015f6ceb95 100644 --- a/src/peripherals/usb.ts +++ b/src/peripherals/usb.ts @@ -24,6 +24,7 @@ const USB_BUF1_SHIFT = 16; const USB_BUF1_OFFSET = 64; // USB Peripheral Register +const ADDR_ENDP = 0x0; const MAIN_CTRL = 0x40; const SIE_STATUS = 0x50; const BUFF_STATUS = 0x58; @@ -104,6 +105,7 @@ class USBEndpointAlarm { } export class RPUSBController extends BasePeripheral { + private addrEndp = 0; private mainCtrl = 0; private intRaw = 0; private intEnable = 0; @@ -162,6 +164,8 @@ export class RPUSBController extends BasePeripheral { readUint32(offset: number) { switch (offset) { + case ADDR_ENDP: + return this.addrEndp & 0b1111000000001111111; case MAIN_CTRL: return this.mainCtrl; case SIE_STATUS: @@ -184,6 +188,9 @@ export class RPUSBController extends BasePeripheral { writeUint32(offset: number, value: number) { switch (offset) { + case ADDR_ENDP: + this.addrEndp = value; + break; case MAIN_CTRL: this.mainCtrl = value & (SIM_TIMING | CONTROLLER_EN | HOST_NDEVICE); if (value & CONTROLLER_EN && !(value & HOST_NDEVICE)) {