rp2040js 0.17.17 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/clock/clock.d.ts +11 -11
- package/dist/cjs/clock/clock.js +2 -2
- package/dist/cjs/clock/mock-clock.d.ts +17 -17
- package/dist/cjs/clock/mock-clock.js +52 -52
- package/dist/cjs/clock/realtime-clock.d.ts +23 -23
- package/dist/cjs/clock/realtime-clock.js +73 -73
- package/dist/cjs/cortex-m0-core.d.ts +87 -87
- package/dist/cjs/cortex-m0-core.js +1251 -1251
- package/dist/cjs/gdb/gdb-connection.d.ts +11 -11
- package/dist/cjs/gdb/gdb-connection.js +57 -57
- package/dist/cjs/gdb/gdb-server.d.ts +23 -23
- package/dist/cjs/gdb/gdb-server.js +232 -232
- package/dist/cjs/gdb/gdb-tcp-server.d.ts +10 -10
- package/dist/cjs/gdb/gdb-tcp-server.js +34 -34
- package/dist/cjs/gdb/gdb-utils.d.ts +9 -9
- package/dist/cjs/gdb/gdb-utils.js +48 -48
- package/dist/cjs/gpio-pin.d.ts +56 -56
- package/dist/cjs/gpio-pin.js +216 -216
- package/dist/cjs/index.d.ts +11 -11
- package/dist/cjs/index.js +36 -36
- package/dist/cjs/interpolator.d.ts +36 -36
- package/dist/cjs/interpolator.js +150 -150
- package/dist/cjs/irq.d.ts +29 -29
- package/dist/cjs/irq.js +33 -33
- package/dist/cjs/peripherals/adc.d.ts +52 -52
- package/dist/cjs/peripherals/adc.js +261 -261
- package/dist/cjs/peripherals/busctrl.d.ts +10 -10
- package/dist/cjs/peripherals/busctrl.js +84 -84
- package/dist/cjs/peripherals/clocks.d.ts +9 -9
- package/dist/cjs/peripherals/clocks.js +42 -42
- package/dist/cjs/peripherals/dma.d.ts +109 -109
- package/dist/cjs/peripherals/dma.js +520 -520
- package/dist/cjs/peripherals/i2c.d.ts +54 -54
- package/dist/cjs/peripherals/i2c.js +458 -458
- package/dist/cjs/peripherals/io.d.ts +11 -11
- package/dist/cjs/peripherals/io.js +100 -100
- package/dist/cjs/peripherals/pads.d.ts +13 -13
- package/dist/cjs/peripherals/pads.js +58 -58
- package/dist/cjs/peripherals/peripheral.d.ts +22 -22
- package/dist/cjs/peripherals/peripheral.js +61 -61
- package/dist/cjs/peripherals/pio.d.ts +120 -120
- package/dist/cjs/peripherals/pio.js +1086 -1086
- package/dist/cjs/peripherals/ppb.d.ts +25 -25
- package/dist/cjs/peripherals/ppb.js +229 -229
- package/dist/cjs/peripherals/pwm.d.ts +65 -65
- package/dist/cjs/peripherals/pwm.js +372 -372
- package/dist/cjs/peripherals/reset.d.ts +8 -8
- package/dist/cjs/peripherals/reset.js +40 -40
- package/dist/cjs/peripherals/rtc.d.ts +10 -10
- package/dist/cjs/peripherals/rtc.js +74 -74
- package/dist/cjs/peripherals/spi.d.ts +38 -38
- package/dist/cjs/peripherals/spi.js +240 -240
- package/dist/cjs/peripherals/ssi.d.ts +6 -6
- package/dist/cjs/peripherals/ssi.js +43 -43
- package/dist/cjs/peripherals/syscfg.d.ts +5 -5
- package/dist/cjs/peripherals/syscfg.js +26 -26
- package/dist/cjs/peripherals/sysinfo.d.ts +4 -4
- package/dist/cjs/peripherals/sysinfo.js +22 -22
- package/dist/cjs/peripherals/tbman.d.ts +4 -4
- package/dist/cjs/peripherals/tbman.js +17 -17
- package/dist/cjs/peripherals/timer.d.ts +18 -18
- package/dist/cjs/peripherals/timer.js +156 -156
- package/dist/cjs/peripherals/uart.d.ts +31 -31
- package/dist/cjs/peripherals/uart.js +132 -132
- package/dist/cjs/peripherals/usb.d.ts +29 -29
- package/dist/cjs/peripherals/usb.js +309 -309
- package/dist/cjs/rp2040.d.ts +71 -71
- package/dist/cjs/rp2040.js +361 -361
- package/dist/cjs/sio.d.ts +21 -21
- package/dist/cjs/sio.js +425 -425
- package/dist/cjs/usb/cdc.d.ts +20 -20
- package/dist/cjs/usb/cdc.js +126 -126
- package/dist/cjs/usb/interfaces.d.ts +47 -47
- package/dist/cjs/usb/interfaces.js +46 -46
- package/dist/cjs/usb/setup.d.ts +5 -5
- package/dist/cjs/usb/setup.js +53 -53
- package/dist/cjs/utils/assembler.d.ts +79 -79
- package/dist/cjs/utils/assembler.js +328 -328
- package/dist/cjs/utils/bit.d.ts +3 -3
- package/dist/cjs/utils/bit.js +15 -15
- package/dist/cjs/utils/fifo.d.ts +15 -15
- package/dist/cjs/utils/fifo.js +56 -56
- package/dist/cjs/utils/logging.d.ts +23 -23
- package/dist/cjs/utils/logging.js +48 -48
- package/dist/cjs/utils/pio-assembler.d.ts +45 -45
- package/dist/cjs/utils/pio-assembler.js +87 -87
- package/dist/cjs/utils/time.d.ts +2 -2
- package/dist/cjs/utils/time.js +32 -32
- package/dist/cjs/utils/timer32.d.ts +57 -57
- package/dist/cjs/utils/timer32.js +208 -208
- package/dist/esm/clock/clock.d.ts +11 -11
- package/dist/esm/clock/clock.js +1 -1
- package/dist/esm/clock/mock-clock.d.ts +17 -17
- package/dist/esm/clock/mock-clock.js +47 -47
- package/dist/esm/clock/realtime-clock.d.ts +23 -23
- package/dist/esm/clock/realtime-clock.js +68 -68
- package/dist/esm/cortex-m0-core.d.ts +87 -87
- package/dist/esm/cortex-m0-core.js +1247 -1247
- package/dist/esm/gdb/gdb-connection.d.ts +11 -11
- package/dist/esm/gdb/gdb-connection.js +53 -53
- package/dist/esm/gdb/gdb-server.d.ts +23 -23
- package/dist/esm/gdb/gdb-server.js +228 -228
- package/dist/esm/gdb/gdb-tcp-server.d.ts +10 -10
- package/dist/esm/gdb/gdb-tcp-server.js +30 -30
- package/dist/esm/gdb/gdb-utils.d.ts +9 -9
- package/dist/esm/gdb/gdb-utils.js +36 -36
- package/dist/esm/gpio-pin.d.ts +56 -56
- package/dist/esm/gpio-pin.js +212 -212
- package/dist/esm/index.d.ts +11 -11
- package/dist/esm/index.js +11 -11
- package/dist/esm/interpolator.d.ts +36 -36
- package/dist/esm/interpolator.js +145 -145
- package/dist/esm/irq.d.ts +29 -29
- package/dist/esm/irq.js +30 -30
- package/dist/esm/peripherals/adc.d.ts +52 -52
- package/dist/esm/peripherals/adc.js +257 -257
- package/dist/esm/peripherals/busctrl.d.ts +10 -10
- package/dist/esm/peripherals/busctrl.js +80 -80
- package/dist/esm/peripherals/clocks.d.ts +9 -9
- package/dist/esm/peripherals/clocks.js +38 -38
- package/dist/esm/peripherals/dma.d.ts +109 -109
- package/dist/esm/peripherals/dma.js +515 -515
- package/dist/esm/peripherals/i2c.d.ts +54 -54
- package/dist/esm/peripherals/i2c.js +454 -454
- package/dist/esm/peripherals/io.d.ts +11 -11
- package/dist/esm/peripherals/io.js +96 -96
- package/dist/esm/peripherals/pads.d.ts +13 -13
- package/dist/esm/peripherals/pads.js +54 -54
- package/dist/esm/peripherals/peripheral.d.ts +22 -22
- package/dist/esm/peripherals/peripheral.js +55 -55
- package/dist/esm/peripherals/pio.d.ts +120 -120
- package/dist/esm/peripherals/pio.js +1081 -1081
- package/dist/esm/peripherals/ppb.d.ts +25 -25
- package/dist/esm/peripherals/ppb.js +225 -225
- package/dist/esm/peripherals/pwm.d.ts +65 -65
- package/dist/esm/peripherals/pwm.js +368 -368
- package/dist/esm/peripherals/reset.d.ts +8 -8
- package/dist/esm/peripherals/reset.js +36 -36
- package/dist/esm/peripherals/rtc.d.ts +10 -10
- package/dist/esm/peripherals/rtc.js +70 -70
- package/dist/esm/peripherals/spi.d.ts +38 -38
- package/dist/esm/peripherals/spi.js +236 -236
- package/dist/esm/peripherals/ssi.d.ts +6 -6
- package/dist/esm/peripherals/ssi.js +39 -39
- package/dist/esm/peripherals/syscfg.d.ts +5 -5
- package/dist/esm/peripherals/syscfg.js +22 -22
- package/dist/esm/peripherals/sysinfo.d.ts +4 -4
- package/dist/esm/peripherals/sysinfo.js +18 -18
- package/dist/esm/peripherals/tbman.d.ts +4 -4
- package/dist/esm/peripherals/tbman.js +13 -13
- package/dist/esm/peripherals/timer.d.ts +18 -18
- package/dist/esm/peripherals/timer.js +152 -152
- package/dist/esm/peripherals/uart.d.ts +31 -31
- package/dist/esm/peripherals/uart.js +128 -128
- package/dist/esm/peripherals/usb.d.ts +29 -29
- package/dist/esm/peripherals/usb.js +305 -305
- package/dist/esm/rp2040.d.ts +71 -71
- package/dist/esm/rp2040.js +357 -357
- package/dist/esm/sio.d.ts +21 -21
- package/dist/esm/sio.js +421 -421
- package/dist/esm/usb/cdc.d.ts +20 -20
- package/dist/esm/usb/cdc.js +121 -121
- package/dist/esm/usb/interfaces.d.ts +47 -47
- package/dist/esm/usb/interfaces.js +43 -43
- package/dist/esm/usb/setup.d.ts +5 -5
- package/dist/esm/usb/setup.js +46 -46
- package/dist/esm/utils/assembler.d.ts +79 -79
- package/dist/esm/utils/assembler.js +245 -245
- package/dist/esm/utils/bit.d.ts +3 -3
- package/dist/esm/utils/bit.js +9 -9
- package/dist/esm/utils/fifo.d.ts +15 -15
- package/dist/esm/utils/fifo.js +52 -52
- package/dist/esm/utils/logging.d.ts +23 -23
- package/dist/esm/utils/logging.js +44 -44
- package/dist/esm/utils/pio-assembler.d.ts +45 -45
- package/dist/esm/utils/pio-assembler.js +75 -75
- package/dist/esm/utils/time.d.ts +2 -2
- package/dist/esm/utils/time.js +27 -27
- package/dist/esm/utils/timer32.d.ts +57 -57
- package/dist/esm/utils/timer32.js +203 -203
- package/package.json +33 -22
- package/dist/esm/package.json +0 -1
|
@@ -1,1086 +1,1086 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RPPIO = exports.StateMachine = exports.WaitType = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
// Generic registers
|
|
8
|
-
const CTRL = 0x000;
|
|
9
|
-
const FSTAT = 0x004;
|
|
10
|
-
const FDEBUG = 0x008;
|
|
11
|
-
const FLEVEL = 0x00c;
|
|
12
|
-
const IRQ = 0x030;
|
|
13
|
-
const IRQ_FORCE = 0x034;
|
|
14
|
-
const INPUT_SYNC_BYPASS = 0x038;
|
|
15
|
-
const DBG_PADOUT = 0x03c;
|
|
16
|
-
const DBG_PADOE = 0x040;
|
|
17
|
-
const DBG_CFGINFO = 0x044;
|
|
18
|
-
const INSTR_MEM0 = 0x48;
|
|
19
|
-
const INSTR_MEM31 = 0x0c4;
|
|
20
|
-
const INTR = 0x128; // Raw Interrupts
|
|
21
|
-
const IRQ0_INTE = 0x12c; // Interrupt Enable for irq0
|
|
22
|
-
const IRQ0_INTF = 0x130; // Interrupt Force for irq0
|
|
23
|
-
const IRQ0_INTS = 0x134; // Interrupt status after masking & forcing for irq0
|
|
24
|
-
const IRQ1_INTE = 0x138; // Interrupt Enable for irq1
|
|
25
|
-
const IRQ1_INTF = 0x13c; // Interrupt Force for irq1
|
|
26
|
-
const IRQ1_INTS = 0x140; // Interrupt status after masking & forcing for irq1
|
|
27
|
-
// State-machine specific registers
|
|
28
|
-
const TXF0 = 0x010;
|
|
29
|
-
const TXF1 = 0x014;
|
|
30
|
-
const TXF2 = 0x018;
|
|
31
|
-
const TXF3 = 0x01c;
|
|
32
|
-
const RXF0 = 0x020;
|
|
33
|
-
const RXF1 = 0x024;
|
|
34
|
-
const RXF2 = 0x028;
|
|
35
|
-
const RXF3 = 0x02c;
|
|
36
|
-
const SM0_CLKDIV = 0x0c8; // Clock divisor register for state machine 0
|
|
37
|
-
const SM0_EXECCTRL = 0x0cc; // Execution/behavioural settings for state machine 0
|
|
38
|
-
const SM0_SHIFTCTRL = 0x0d0; // Control behaviour of the input/output shift registers for state machine 0
|
|
39
|
-
const SM0_ADDR = 0x0d4; // Current instruction address of state machine 0
|
|
40
|
-
const SM0_INSTR = 0x0d8; // Write to execute an instruction immediately (including jumps) and then resume execution.
|
|
41
|
-
const SM0_PINCTRL = 0x0dc; //State machine pin control
|
|
42
|
-
const SM1_CLKDIV = 0x0e0;
|
|
43
|
-
const SM1_PINCTRL = 0x0f4;
|
|
44
|
-
const SM2_CLKDIV = 0x0f8;
|
|
45
|
-
const SM2_PINCTRL = 0x10c;
|
|
46
|
-
const SM3_CLKDIV = 0x110;
|
|
47
|
-
const SM3_PINCTRL = 0x124;
|
|
48
|
-
// FSTAT bits
|
|
49
|
-
const FSTAT_TXEMPTY = 1 << 24;
|
|
50
|
-
const FSTAT_TXFULL = 1 << 16;
|
|
51
|
-
const FSTAT_RXEMPTY = 1 << 8;
|
|
52
|
-
const FSTAT_RXFULL = 1 << 0;
|
|
53
|
-
// FDEBUG bits
|
|
54
|
-
const FDEBUG_TXSTALL = 1 << 24;
|
|
55
|
-
const FDEBUG_TXOVER = 1 << 16;
|
|
56
|
-
const FDEBUG_RXUNDER = 1 << 8;
|
|
57
|
-
const FDEBUG_RXSTALL = 1 << 0;
|
|
58
|
-
// SHIFTCTRL bits
|
|
59
|
-
const SHIFTCTRL_AUTOPUSH = 1 << 16;
|
|
60
|
-
const SHIFTCTRL_AUTOPULL = 1 << 17;
|
|
61
|
-
const SHIFTCTRL_IN_SHIFTDIR = 1 << 18; // 1 = shift input shift register to right (data enters from left). 0 = to left
|
|
62
|
-
const SHIFTCTRL_OUT_SHIFTDIR = 1 << 19; // 1 = shift out of output shift register to right. 0 = to left
|
|
63
|
-
// EXECCTRL bits
|
|
64
|
-
const EXECCTRL_STATUS_SEL = 1 << 4;
|
|
65
|
-
const EXECCTRL_SIDE_PINDIR = 1 << 29;
|
|
66
|
-
const EXECCTRL_SIDE_EN = 1 << 30;
|
|
67
|
-
const EXECCTRL_EXEC_STALLED = 1 << 31;
|
|
68
|
-
var WaitType;
|
|
69
|
-
(function (WaitType) {
|
|
70
|
-
WaitType[WaitType["None"] = 0] = "None";
|
|
71
|
-
WaitType[WaitType["Pin"] = 1] = "Pin";
|
|
72
|
-
WaitType[WaitType["rxFIFO"] = 2] = "rxFIFO";
|
|
73
|
-
WaitType[WaitType["txFIFO"] = 3] = "txFIFO";
|
|
74
|
-
WaitType[WaitType["IRQ"] = 4] = "IRQ";
|
|
75
|
-
WaitType[WaitType["Out"] = 5] = "Out";
|
|
76
|
-
})(WaitType
|
|
77
|
-
function bitReverse(x) {
|
|
78
|
-
x = ((x & 0x55555555) << 1) | ((x & 0xaaaaaaaa) >>> 1);
|
|
79
|
-
x = ((x & 0x33333333) << 2) | ((x & 0xcccccccc) >>> 2);
|
|
80
|
-
x = ((x & 0x0f0f0f0f) << 4) | ((x & 0xf0f0f0f0) >>> 4);
|
|
81
|
-
x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >>> 8);
|
|
82
|
-
x = ((x & 0x0000ffff) << 16) | ((x & 0xffff0000) >>> 16);
|
|
83
|
-
return x >>> 0;
|
|
84
|
-
}
|
|
85
|
-
function irqIndex(irq, machineIndex) {
|
|
86
|
-
const rel = !!(irq & 0x10);
|
|
87
|
-
return rel ? (irq & 0x4) | (((irq & 0x3) + machineIndex) & 0x3) : irq & 0x7;
|
|
88
|
-
}
|
|
89
|
-
const dreqRx0 = [
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
];
|
|
95
|
-
const dreqTx0 = [
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
];
|
|
101
|
-
const dreqRx1 = [
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
];
|
|
107
|
-
const dreqTx1 = [
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
];
|
|
113
|
-
class StateMachine {
|
|
114
|
-
constructor(rp2040, pio, index) {
|
|
115
|
-
this.rp2040 = rp2040;
|
|
116
|
-
this.pio = pio;
|
|
117
|
-
this.index = index;
|
|
118
|
-
this.enabled = false;
|
|
119
|
-
// State machine registers
|
|
120
|
-
this.x = 0;
|
|
121
|
-
this.y = 0;
|
|
122
|
-
this.pc = 0;
|
|
123
|
-
this.inputShiftReg = 0;
|
|
124
|
-
this.inputShiftCount = 0;
|
|
125
|
-
this.outputShiftReg = 0;
|
|
126
|
-
this.outputShiftCount = 0;
|
|
127
|
-
this.cycles = 0;
|
|
128
|
-
this.execOpcode = 0;
|
|
129
|
-
this.execValid = false;
|
|
130
|
-
this.updatePC = true;
|
|
131
|
-
this.clockDivInt = 1;
|
|
132
|
-
this.clockDivFrac = 0;
|
|
133
|
-
this.execCtrl = 0x1f << 12;
|
|
134
|
-
this.shiftCtrl = 0b11 << 18;
|
|
135
|
-
this.pinCtrl = 0x5 << 26;
|
|
136
|
-
this.rxFIFO = new
|
|
137
|
-
this.txFIFO = new
|
|
138
|
-
this.outPinValues = 0;
|
|
139
|
-
this.outPinDirection = 0;
|
|
140
|
-
this.waiting = false;
|
|
141
|
-
this.waitType = WaitType.None;
|
|
142
|
-
this.waitIndex = 0;
|
|
143
|
-
this.waitPolarity = false;
|
|
144
|
-
this.waitDelay = -1;
|
|
145
|
-
this.dreqRx = this.pio.dreqRx[this.index];
|
|
146
|
-
this.dreqTx = this.pio.dreqTx[this.index];
|
|
147
|
-
this.updateDMARx();
|
|
148
|
-
this.updateDMATx();
|
|
149
|
-
}
|
|
150
|
-
updateDMATx() {
|
|
151
|
-
if (this.txFIFO.full) {
|
|
152
|
-
this.rp2040.dma.clearDREQ(this.dreqTx);
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
this.rp2040.dma.setDREQ(this.dreqTx);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
updateDMARx() {
|
|
159
|
-
if (this.rxFIFO.empty) {
|
|
160
|
-
this.rp2040.dma.clearDREQ(this.dreqRx);
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
this.rp2040.dma.setDREQ(this.dreqRx);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
writeFIFO(value) {
|
|
167
|
-
if (this.txFIFO.full) {
|
|
168
|
-
this.pio.fdebug |= FDEBUG_TXOVER << this.index;
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
this.txFIFO.push(value);
|
|
172
|
-
this.updateDMATx();
|
|
173
|
-
this.checkWait();
|
|
174
|
-
if (this.txFIFO.full) {
|
|
175
|
-
this.pio.checkInterrupts();
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
readFIFO() {
|
|
179
|
-
if (this.rxFIFO.empty) {
|
|
180
|
-
this.pio.fdebug |= FDEBUG_RXUNDER << this.index;
|
|
181
|
-
return 0;
|
|
182
|
-
}
|
|
183
|
-
const result = this.rxFIFO.pull();
|
|
184
|
-
this.updateDMARx();
|
|
185
|
-
this.checkWait();
|
|
186
|
-
if (this.rxFIFO.empty) {
|
|
187
|
-
this.pio.checkInterrupts();
|
|
188
|
-
}
|
|
189
|
-
return result;
|
|
190
|
-
}
|
|
191
|
-
get status() {
|
|
192
|
-
const statusN = this.execCtrl & 0xf;
|
|
193
|
-
if (this.execCtrl & EXECCTRL_STATUS_SEL) {
|
|
194
|
-
return this.rxFIFO.itemCount < statusN ? 0xffffffff : 0;
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
return this.txFIFO.itemCount < statusN ? 0xffffffff : 0;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
jmpCondition(condition) {
|
|
201
|
-
switch (condition) {
|
|
202
|
-
// (no condition): Always
|
|
203
|
-
case 0b000:
|
|
204
|
-
return true;
|
|
205
|
-
// !X: scratch X zero
|
|
206
|
-
case 0b001:
|
|
207
|
-
return this.x === 0;
|
|
208
|
-
// X--: scratch X non-zero, post-decrement
|
|
209
|
-
case 0b010: {
|
|
210
|
-
const oldX = this.x;
|
|
211
|
-
this.x = (this.x - 1) >>> 0;
|
|
212
|
-
return oldX !== 0;
|
|
213
|
-
}
|
|
214
|
-
// !Y: scratch Y zero
|
|
215
|
-
case 0b011:
|
|
216
|
-
return this.y === 0;
|
|
217
|
-
// Y--: scratch Y non-zero, post-decrement
|
|
218
|
-
case 0b100: {
|
|
219
|
-
const oldY = this.y;
|
|
220
|
-
this.y = (this.y - 1) >>> 0;
|
|
221
|
-
return oldY !== 0;
|
|
222
|
-
}
|
|
223
|
-
// X!=Y: scratch X not equal scratch Y
|
|
224
|
-
case 0b101:
|
|
225
|
-
return this.x >>> 0 !== this.y >>> 0;
|
|
226
|
-
// PIN: branch on input pin
|
|
227
|
-
case 0b110: {
|
|
228
|
-
const { gpio } = this.rp2040;
|
|
229
|
-
const { jmpPin } = this;
|
|
230
|
-
return jmpPin < gpio.length ? gpio[jmpPin].inputValue : false;
|
|
231
|
-
}
|
|
232
|
-
// !OSRE: output shift register not empty
|
|
233
|
-
case 0b111:
|
|
234
|
-
return this.outputShiftCount < this.pullThreshold;
|
|
235
|
-
}
|
|
236
|
-
this.pio.error(`jmpCondition with unsupported condition: ${condition}`);
|
|
237
|
-
return false;
|
|
238
|
-
}
|
|
239
|
-
get inPins() {
|
|
240
|
-
const { gpioValues } = this.rp2040;
|
|
241
|
-
const { inBase } = this;
|
|
242
|
-
return inBase ? (gpioValues << (32 - inBase)) | (gpioValues >>> inBase) : gpioValues;
|
|
243
|
-
}
|
|
244
|
-
inSourceValue(source) {
|
|
245
|
-
switch (source) {
|
|
246
|
-
// PINS
|
|
247
|
-
case 0b000:
|
|
248
|
-
return this.inPins;
|
|
249
|
-
// X (scratch register X)
|
|
250
|
-
case 0b001:
|
|
251
|
-
return this.x;
|
|
252
|
-
// Y (scratch register Y)
|
|
253
|
-
case 0b010:
|
|
254
|
-
return this.y;
|
|
255
|
-
// NULL (all zeroes)
|
|
256
|
-
case 0b011:
|
|
257
|
-
return 0;
|
|
258
|
-
// Reserved
|
|
259
|
-
case 0b100:
|
|
260
|
-
return 0;
|
|
261
|
-
// Reserved for IN, STATUS for MOV
|
|
262
|
-
case 0b101:
|
|
263
|
-
return this.status;
|
|
264
|
-
// ISR
|
|
265
|
-
case 0b110:
|
|
266
|
-
return this.inputShiftReg;
|
|
267
|
-
// OSR
|
|
268
|
-
case 0b111:
|
|
269
|
-
return this.outputShiftReg;
|
|
270
|
-
}
|
|
271
|
-
this.pio.error(`inSourceValue with unsupported source: ${source}`);
|
|
272
|
-
return 0;
|
|
273
|
-
}
|
|
274
|
-
writeOutValue(destination, value, bitCount) {
|
|
275
|
-
switch (destination) {
|
|
276
|
-
// PINS
|
|
277
|
-
case 0b000:
|
|
278
|
-
this.setOutPins(value);
|
|
279
|
-
break;
|
|
280
|
-
// X (scratch register X)
|
|
281
|
-
case 0b001:
|
|
282
|
-
this.x = value;
|
|
283
|
-
break;
|
|
284
|
-
// Y (scratch register Y)
|
|
285
|
-
case 0b010:
|
|
286
|
-
this.y = value;
|
|
287
|
-
break;
|
|
288
|
-
// NULL (discard data)
|
|
289
|
-
case 0b011:
|
|
290
|
-
break;
|
|
291
|
-
// PINDIRS
|
|
292
|
-
case 0b100:
|
|
293
|
-
this.setOutPinDirs(value);
|
|
294
|
-
break;
|
|
295
|
-
// PC
|
|
296
|
-
case 0b101:
|
|
297
|
-
this.pc = value & 0x1f;
|
|
298
|
-
this.updatePC = false;
|
|
299
|
-
break;
|
|
300
|
-
// ISR (also sets ISR shift counter to Bit count)
|
|
301
|
-
case 0b110:
|
|
302
|
-
this.inputShiftReg = value;
|
|
303
|
-
this.inputShiftCount = bitCount;
|
|
304
|
-
break;
|
|
305
|
-
// EXEC (Execute OSR shift data as instruction)
|
|
306
|
-
case 0b111:
|
|
307
|
-
this.execOpcode = value;
|
|
308
|
-
this.execValid = true;
|
|
309
|
-
break;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
get pushThreshold() {
|
|
313
|
-
const value = (this.shiftCtrl >> 20) & 0x1f;
|
|
314
|
-
return value ? value : 32;
|
|
315
|
-
}
|
|
316
|
-
get pullThreshold() {
|
|
317
|
-
const value = (this.shiftCtrl >> 25) & 0x1f;
|
|
318
|
-
return value ? value : 32;
|
|
319
|
-
}
|
|
320
|
-
get sidesetCount() {
|
|
321
|
-
return (this.pinCtrl >> 29) & 0x7;
|
|
322
|
-
}
|
|
323
|
-
get setCount() {
|
|
324
|
-
return (this.pinCtrl >> 26) & 0x7;
|
|
325
|
-
}
|
|
326
|
-
get outCount() {
|
|
327
|
-
return (this.pinCtrl >> 20) & 0x3f;
|
|
328
|
-
}
|
|
329
|
-
get inBase() {
|
|
330
|
-
return (this.pinCtrl >> 15) & 0x1f;
|
|
331
|
-
}
|
|
332
|
-
get sidesetBase() {
|
|
333
|
-
return (this.pinCtrl >> 10) & 0x1f;
|
|
334
|
-
}
|
|
335
|
-
get setBase() {
|
|
336
|
-
return (this.pinCtrl >> 5) & 0x1f;
|
|
337
|
-
}
|
|
338
|
-
get outBase() {
|
|
339
|
-
return (this.pinCtrl >> 0) & 0x1f;
|
|
340
|
-
}
|
|
341
|
-
get jmpPin() {
|
|
342
|
-
return (this.execCtrl >> 24) & 0x1f;
|
|
343
|
-
}
|
|
344
|
-
get wrapTop() {
|
|
345
|
-
return (this.execCtrl >> 12) & 0x1f;
|
|
346
|
-
}
|
|
347
|
-
get wrapBottom() {
|
|
348
|
-
return (this.execCtrl >> 7) & 0x1f;
|
|
349
|
-
}
|
|
350
|
-
setOutPinDirs(value) {
|
|
351
|
-
this.outPinDirection = value;
|
|
352
|
-
this.pio.pinDirectionsChanged(value, this.outBase, this.outCount);
|
|
353
|
-
}
|
|
354
|
-
setOutPins(value) {
|
|
355
|
-
this.outPinValues = value;
|
|
356
|
-
this.pio.pinValuesChanged(value, this.outBase, this.outCount);
|
|
357
|
-
}
|
|
358
|
-
outInstruction(arg) {
|
|
359
|
-
const bitCount = arg & 0x1f;
|
|
360
|
-
const destination = arg >> 5;
|
|
361
|
-
if (bitCount === 0) {
|
|
362
|
-
this.writeOutValue(destination, this.outputShiftReg, 32);
|
|
363
|
-
this.outputShiftCount = 32;
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
if (this.shiftCtrl & SHIFTCTRL_OUT_SHIFTDIR) {
|
|
367
|
-
const value = this.outputShiftReg & ((1 << bitCount) - 1);
|
|
368
|
-
this.outputShiftReg >>>= bitCount;
|
|
369
|
-
this.writeOutValue(destination, value, bitCount);
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
const value = this.outputShiftReg >>> (32 - bitCount);
|
|
373
|
-
this.outputShiftReg <<= bitCount;
|
|
374
|
-
this.writeOutValue(destination, value, bitCount);
|
|
375
|
-
}
|
|
376
|
-
this.outputShiftCount += bitCount;
|
|
377
|
-
if (this.outputShiftCount > 32) {
|
|
378
|
-
this.outputShiftCount = 32;
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
executeInstruction(opcode) {
|
|
383
|
-
const arg = opcode & 0xff;
|
|
384
|
-
switch (opcode >>> 13) {
|
|
385
|
-
/* JMP */
|
|
386
|
-
case 0b000:
|
|
387
|
-
if (this.jmpCondition(arg >> 5)) {
|
|
388
|
-
this.pc = arg & 0x1f;
|
|
389
|
-
this.updatePC = false;
|
|
390
|
-
}
|
|
391
|
-
break;
|
|
392
|
-
/* WAIT */
|
|
393
|
-
case 0b001: {
|
|
394
|
-
const polarity = !!(arg & 0x80);
|
|
395
|
-
const source = (arg >> 5) & 0x3;
|
|
396
|
-
const index = arg & 0x1f;
|
|
397
|
-
switch (source) {
|
|
398
|
-
// GPIO:
|
|
399
|
-
case 0b00:
|
|
400
|
-
this.wait(WaitType.Pin, polarity, index);
|
|
401
|
-
break;
|
|
402
|
-
// PIN:
|
|
403
|
-
case 0b01:
|
|
404
|
-
this.wait(WaitType.Pin, polarity, (index + this.inBase) % 32);
|
|
405
|
-
break;
|
|
406
|
-
// IRQ:
|
|
407
|
-
case 0b10:
|
|
408
|
-
this.wait(WaitType.IRQ, polarity, irqIndex(index, this.index));
|
|
409
|
-
break;
|
|
410
|
-
}
|
|
411
|
-
break;
|
|
412
|
-
}
|
|
413
|
-
/* IN */
|
|
414
|
-
case 0b010: {
|
|
415
|
-
const bitCount = arg & 0x1f;
|
|
416
|
-
let sourceValue = this.inSourceValue(arg >> 5);
|
|
417
|
-
if (bitCount == 0) {
|
|
418
|
-
this.inputShiftReg = sourceValue;
|
|
419
|
-
this.inputShiftCount = 32;
|
|
420
|
-
}
|
|
421
|
-
else {
|
|
422
|
-
sourceValue &= (1 << bitCount) - 1;
|
|
423
|
-
if (this.shiftCtrl & SHIFTCTRL_IN_SHIFTDIR) {
|
|
424
|
-
this.inputShiftReg >>>= bitCount;
|
|
425
|
-
this.inputShiftReg |= sourceValue << (32 - bitCount);
|
|
426
|
-
}
|
|
427
|
-
else {
|
|
428
|
-
this.inputShiftReg <<= bitCount;
|
|
429
|
-
this.inputShiftReg |= sourceValue;
|
|
430
|
-
}
|
|
431
|
-
this.inputShiftCount += bitCount;
|
|
432
|
-
if (this.inputShiftCount > 32) {
|
|
433
|
-
this.inputShiftCount = 32;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
if (this.shiftCtrl & SHIFTCTRL_AUTOPUSH && this.inputShiftCount >= this.pushThreshold) {
|
|
437
|
-
if (!this.rxFIFO.full) {
|
|
438
|
-
this.rxFIFO.push(this.inputShiftReg);
|
|
439
|
-
this.updateDMARx();
|
|
440
|
-
this.pio.checkInterrupts();
|
|
441
|
-
}
|
|
442
|
-
else {
|
|
443
|
-
this.pio.fdebug |= FDEBUG_RXSTALL << this.index;
|
|
444
|
-
this.wait(WaitType.rxFIFO, false, this.inputShiftReg);
|
|
445
|
-
}
|
|
446
|
-
this.inputShiftCount = 0;
|
|
447
|
-
this.inputShiftReg = 0;
|
|
448
|
-
}
|
|
449
|
-
break;
|
|
450
|
-
}
|
|
451
|
-
/* OUT */
|
|
452
|
-
case 0b011: {
|
|
453
|
-
if (this.shiftCtrl & SHIFTCTRL_AUTOPULL && this.outputShiftCount >= this.pullThreshold) {
|
|
454
|
-
this.outputShiftCount = 0;
|
|
455
|
-
if (!this.txFIFO.empty) {
|
|
456
|
-
this.outputShiftReg = this.txFIFO.pull();
|
|
457
|
-
this.updateDMATx();
|
|
458
|
-
this.pio.checkInterrupts();
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
this.pio.fdebug |= FDEBUG_TXSTALL << this.index;
|
|
462
|
-
this.wait(WaitType.Out, false, arg);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
if (!this.waiting) {
|
|
466
|
-
this.outInstruction(arg);
|
|
467
|
-
}
|
|
468
|
-
break;
|
|
469
|
-
}
|
|
470
|
-
/* PUSH/PULL */
|
|
471
|
-
case 0b100: {
|
|
472
|
-
const block = !!(arg & (1 << 5));
|
|
473
|
-
const ifFullOrEmpty = !!(arg & (1 << 6));
|
|
474
|
-
if (arg & 0x1f) {
|
|
475
|
-
// Unknown instruction
|
|
476
|
-
break;
|
|
477
|
-
}
|
|
478
|
-
if (arg & 0x80) {
|
|
479
|
-
// PULL
|
|
480
|
-
if (ifFullOrEmpty &&
|
|
481
|
-
this.shiftCtrl & SHIFTCTRL_AUTOPULL &&
|
|
482
|
-
this.outputShiftCount < this.pullThreshold) {
|
|
483
|
-
break;
|
|
484
|
-
}
|
|
485
|
-
if (!this.txFIFO.empty) {
|
|
486
|
-
this.outputShiftReg = this.txFIFO.pull();
|
|
487
|
-
this.updateDMATx();
|
|
488
|
-
this.pio.checkInterrupts();
|
|
489
|
-
}
|
|
490
|
-
else {
|
|
491
|
-
this.pio.fdebug |= FDEBUG_TXSTALL << this.index;
|
|
492
|
-
if (block) {
|
|
493
|
-
this.wait(WaitType.txFIFO, false, 0);
|
|
494
|
-
}
|
|
495
|
-
else {
|
|
496
|
-
this.outputShiftReg = this.x;
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
this.outputShiftCount = 0;
|
|
500
|
-
}
|
|
501
|
-
else {
|
|
502
|
-
// PUSH
|
|
503
|
-
if (ifFullOrEmpty &&
|
|
504
|
-
this.shiftCtrl & SHIFTCTRL_AUTOPUSH &&
|
|
505
|
-
this.inputShiftCount < this.pushThreshold) {
|
|
506
|
-
break;
|
|
507
|
-
}
|
|
508
|
-
if (!this.rxFIFO.full) {
|
|
509
|
-
this.rxFIFO.push(this.inputShiftReg);
|
|
510
|
-
this.updateDMARx();
|
|
511
|
-
this.pio.checkInterrupts();
|
|
512
|
-
}
|
|
513
|
-
else {
|
|
514
|
-
this.pio.fdebug |= FDEBUG_RXSTALL << this.index;
|
|
515
|
-
if (block) {
|
|
516
|
-
this.wait(WaitType.rxFIFO, false, this.inputShiftReg);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
this.inputShiftReg = 0;
|
|
520
|
-
this.inputShiftCount = 0;
|
|
521
|
-
}
|
|
522
|
-
break;
|
|
523
|
-
}
|
|
524
|
-
/* MOV */
|
|
525
|
-
case 0b101: {
|
|
526
|
-
const source = arg & 0x7;
|
|
527
|
-
const op = (arg >> 3) & 0x3;
|
|
528
|
-
const destination = (arg >> 5) & 0x7;
|
|
529
|
-
const value = this.inSourceValue(source);
|
|
530
|
-
const transformedValue = this.transformMovValue(value, op) >>> 0;
|
|
531
|
-
this.setMovDestination(destination, transformedValue);
|
|
532
|
-
break;
|
|
533
|
-
}
|
|
534
|
-
/* IRQ */
|
|
535
|
-
case 0b110: {
|
|
536
|
-
if (arg & 0x80) {
|
|
537
|
-
// Unknown instruction
|
|
538
|
-
break;
|
|
539
|
-
}
|
|
540
|
-
const clear = !!(arg & 0x40);
|
|
541
|
-
const wait = !!(arg & 0x20);
|
|
542
|
-
const irq = irqIndex(arg & 0x1f, this.index);
|
|
543
|
-
if (clear) {
|
|
544
|
-
this.pio.irq &= ~(1 << irq);
|
|
545
|
-
this.pio.irqUpdated();
|
|
546
|
-
}
|
|
547
|
-
else {
|
|
548
|
-
this.pio.irq |= 1 << irq;
|
|
549
|
-
this.pio.irqUpdated();
|
|
550
|
-
if (wait) {
|
|
551
|
-
this.wait(WaitType.IRQ, false, irq);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
break;
|
|
555
|
-
}
|
|
556
|
-
/* SET */
|
|
557
|
-
case 0b111: {
|
|
558
|
-
const data = arg & 0x1f;
|
|
559
|
-
const destination = arg >> 5;
|
|
560
|
-
switch (destination) {
|
|
561
|
-
case 0b000:
|
|
562
|
-
this.setSetPins(data);
|
|
563
|
-
break;
|
|
564
|
-
case 0b001:
|
|
565
|
-
this.x = data;
|
|
566
|
-
break;
|
|
567
|
-
case 0b010:
|
|
568
|
-
this.y = data;
|
|
569
|
-
break;
|
|
570
|
-
case 0b100:
|
|
571
|
-
this.setSetPinDirs(data);
|
|
572
|
-
break;
|
|
573
|
-
}
|
|
574
|
-
break;
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
this.cycles++;
|
|
578
|
-
const { sidesetCount, execCtrl } = this;
|
|
579
|
-
const delaySideset = (opcode >> 8) & 0x1f;
|
|
580
|
-
const sideEn = !!(execCtrl & EXECCTRL_SIDE_EN);
|
|
581
|
-
const delay = delaySideset & ((1 << (5 - sidesetCount)) - 1);
|
|
582
|
-
if (sidesetCount && (!sideEn || delaySideset & 0x10)) {
|
|
583
|
-
const sideset = delaySideset >> (5 - sidesetCount);
|
|
584
|
-
this.setSideset(sideset, sideEn ? sidesetCount - 1 : sidesetCount);
|
|
585
|
-
}
|
|
586
|
-
if (this.execValid) {
|
|
587
|
-
this.execValid = false;
|
|
588
|
-
this.executeInstruction(this.execOpcode);
|
|
589
|
-
}
|
|
590
|
-
else if (this.waiting) {
|
|
591
|
-
if (this.waitDelay < 0) {
|
|
592
|
-
this.waitDelay = delay;
|
|
593
|
-
}
|
|
594
|
-
this.checkWait();
|
|
595
|
-
}
|
|
596
|
-
else {
|
|
597
|
-
this.cycles += delay;
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
wait(type, polarity, index) {
|
|
601
|
-
this.waiting = true;
|
|
602
|
-
this.waitType = type;
|
|
603
|
-
this.waitPolarity = polarity;
|
|
604
|
-
this.waitIndex = index;
|
|
605
|
-
this.waitDelay = -1;
|
|
606
|
-
this.updatePC = false;
|
|
607
|
-
}
|
|
608
|
-
nextPC() {
|
|
609
|
-
if (this.pc === this.wrapTop) {
|
|
610
|
-
this.pc = this.wrapBottom;
|
|
611
|
-
}
|
|
612
|
-
else {
|
|
613
|
-
this.pc = (this.pc + 1) & 0x1f;
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
step() {
|
|
617
|
-
if (this.waiting) {
|
|
618
|
-
this.checkWait();
|
|
619
|
-
if (this.waiting) {
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
this.updatePC = true;
|
|
624
|
-
this.executeInstruction(this.pio.instructions[this.pc]);
|
|
625
|
-
if (this.updatePC) {
|
|
626
|
-
this.nextPC();
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
setSetPinDirs(value) {
|
|
630
|
-
this.pio.pinDirectionsChanged(value, this.setBase, this.setCount);
|
|
631
|
-
}
|
|
632
|
-
setSetPins(value) {
|
|
633
|
-
this.pio.pinValuesChanged(value, this.setBase, this.setCount);
|
|
634
|
-
}
|
|
635
|
-
setSideset(value, count) {
|
|
636
|
-
if (this.execCtrl & EXECCTRL_SIDE_PINDIR) {
|
|
637
|
-
this.pio.pinDirectionsChanged(value, this.sidesetBase, count);
|
|
638
|
-
}
|
|
639
|
-
else {
|
|
640
|
-
this.pio.pinValuesChanged(value, this.sidesetBase, count);
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
transformMovValue(value, op) {
|
|
644
|
-
switch (op) {
|
|
645
|
-
case 0b00:
|
|
646
|
-
return value;
|
|
647
|
-
case 0b01:
|
|
648
|
-
return ~value;
|
|
649
|
-
case 0b10:
|
|
650
|
-
return bitReverse(value);
|
|
651
|
-
case 0b11:
|
|
652
|
-
default:
|
|
653
|
-
return value; // reserved
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
setMovDestination(destination, value) {
|
|
657
|
-
switch (destination) {
|
|
658
|
-
// PINS
|
|
659
|
-
case 0b000:
|
|
660
|
-
this.setOutPins(value);
|
|
661
|
-
break;
|
|
662
|
-
// X (scratch register X)
|
|
663
|
-
case 0b001:
|
|
664
|
-
this.x = value;
|
|
665
|
-
break;
|
|
666
|
-
// Y (scratch register Y)
|
|
667
|
-
case 0b010:
|
|
668
|
-
this.y = value;
|
|
669
|
-
break;
|
|
670
|
-
// reserved (discard data)
|
|
671
|
-
case 0b011:
|
|
672
|
-
break;
|
|
673
|
-
// EXEC
|
|
674
|
-
case 0b100:
|
|
675
|
-
this.execOpcode = value;
|
|
676
|
-
this.execValid = true;
|
|
677
|
-
break;
|
|
678
|
-
// PC
|
|
679
|
-
case 0b101:
|
|
680
|
-
this.pc = value & 0x1f;
|
|
681
|
-
this.updatePC = false;
|
|
682
|
-
break;
|
|
683
|
-
// ISR (Input shift counter is reset to 0 by this operation, i.e. empty)
|
|
684
|
-
case 0b110:
|
|
685
|
-
this.inputShiftReg = value;
|
|
686
|
-
this.inputShiftCount = 0;
|
|
687
|
-
break;
|
|
688
|
-
// OSR (Output shift counter is reset to 0 by this operation, i.e. full)
|
|
689
|
-
case 0b111:
|
|
690
|
-
this.outputShiftReg = value;
|
|
691
|
-
this.outputShiftCount = 0;
|
|
692
|
-
break;
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
readUint32(offset) {
|
|
696
|
-
switch (offset + SM0_CLKDIV) {
|
|
697
|
-
case SM0_CLKDIV:
|
|
698
|
-
return (this.clockDivInt << 16) | (this.clockDivFrac << 8);
|
|
699
|
-
case SM0_EXECCTRL:
|
|
700
|
-
return this.execCtrl;
|
|
701
|
-
case SM0_SHIFTCTRL:
|
|
702
|
-
return this.shiftCtrl;
|
|
703
|
-
case SM0_ADDR:
|
|
704
|
-
return this.pc;
|
|
705
|
-
case SM0_INSTR:
|
|
706
|
-
return this.pio.instructions[this.pc];
|
|
707
|
-
case SM0_PINCTRL:
|
|
708
|
-
return this.pinCtrl;
|
|
709
|
-
}
|
|
710
|
-
this.pio.error(`Read from invalid state machine register: ${offset}`);
|
|
711
|
-
return 0;
|
|
712
|
-
}
|
|
713
|
-
writeUint32(offset, value) {
|
|
714
|
-
switch (offset + SM0_CLKDIV) {
|
|
715
|
-
case SM0_CLKDIV:
|
|
716
|
-
this.clockDivFrac = (value >>> 8) & 0xff;
|
|
717
|
-
this.clockDivInt = value >>> 16;
|
|
718
|
-
break;
|
|
719
|
-
case SM0_EXECCTRL:
|
|
720
|
-
this.execCtrl = ((value & 0x7fffffff) | (this.execCtrl & 0x80000000)) >>> 0;
|
|
721
|
-
break;
|
|
722
|
-
case SM0_SHIFTCTRL:
|
|
723
|
-
this.shiftCtrl = value;
|
|
724
|
-
break;
|
|
725
|
-
case SM0_ADDR:
|
|
726
|
-
/* read-only */
|
|
727
|
-
break;
|
|
728
|
-
case SM0_INSTR:
|
|
729
|
-
this.executeInstruction(value & 0xffff);
|
|
730
|
-
if (this.waiting) {
|
|
731
|
-
this.execCtrl |= EXECCTRL_EXEC_STALLED;
|
|
732
|
-
}
|
|
733
|
-
break;
|
|
734
|
-
case SM0_PINCTRL:
|
|
735
|
-
this.pinCtrl = value;
|
|
736
|
-
break;
|
|
737
|
-
default:
|
|
738
|
-
this.pio.error(`Write to invalid state machine register: ${offset}`);
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
get fifoStat() {
|
|
742
|
-
const result = (this.txFIFO.empty ? FSTAT_TXEMPTY : 0) |
|
|
743
|
-
(this.txFIFO.full ? FSTAT_TXFULL : 0) |
|
|
744
|
-
(this.rxFIFO.empty ? FSTAT_RXEMPTY : 0) |
|
|
745
|
-
(this.rxFIFO.full ? FSTAT_RXFULL : 0);
|
|
746
|
-
return result << this.index;
|
|
747
|
-
}
|
|
748
|
-
restart() {
|
|
749
|
-
this.cycles = 0;
|
|
750
|
-
this.inputShiftCount = 0;
|
|
751
|
-
this.outputShiftCount = 32;
|
|
752
|
-
this.inputShiftReg = 0;
|
|
753
|
-
this.waiting = false;
|
|
754
|
-
// TODO any pin write left asserted due to OUT_STICKY.
|
|
755
|
-
}
|
|
756
|
-
clkDivRestart() {
|
|
757
|
-
this.pio.warn('clkDivRestart not implemented');
|
|
758
|
-
}
|
|
759
|
-
checkWait() {
|
|
760
|
-
if (!this.waiting) {
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
|
-
switch (this.waitType) {
|
|
764
|
-
case WaitType.IRQ: {
|
|
765
|
-
const irqValue = !!(this.pio.irq & (1 << this.waitIndex));
|
|
766
|
-
if (irqValue === this.waitPolarity) {
|
|
767
|
-
this.waiting = false;
|
|
768
|
-
if (irqValue) {
|
|
769
|
-
this.pio.irq &= ~(1 << this.waitIndex);
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
break;
|
|
773
|
-
}
|
|
774
|
-
case WaitType.Pin: {
|
|
775
|
-
if (this.waitIndex < this.rp2040.gpio.length &&
|
|
776
|
-
this.rp2040.gpio[this.waitIndex].inputValue === this.waitPolarity) {
|
|
777
|
-
this.waiting = false;
|
|
778
|
-
}
|
|
779
|
-
break;
|
|
780
|
-
}
|
|
781
|
-
case WaitType.rxFIFO: {
|
|
782
|
-
if (!this.rxFIFO.full) {
|
|
783
|
-
this.rxFIFO.push(this.waitIndex);
|
|
784
|
-
this.waiting = false;
|
|
785
|
-
this.updateDMARx();
|
|
786
|
-
this.pio.checkInterrupts();
|
|
787
|
-
}
|
|
788
|
-
break;
|
|
789
|
-
}
|
|
790
|
-
case WaitType.txFIFO: {
|
|
791
|
-
if (!this.txFIFO.empty) {
|
|
792
|
-
this.outputShiftReg = this.txFIFO.pull();
|
|
793
|
-
this.waiting = false;
|
|
794
|
-
this.updateDMATx();
|
|
795
|
-
this.pio.checkInterrupts();
|
|
796
|
-
}
|
|
797
|
-
break;
|
|
798
|
-
}
|
|
799
|
-
case WaitType.Out: {
|
|
800
|
-
if (!this.txFIFO.empty) {
|
|
801
|
-
this.outputShiftReg = this.txFIFO.pull();
|
|
802
|
-
this.outInstruction(this.waitIndex);
|
|
803
|
-
this.waiting = false;
|
|
804
|
-
this.updateDMATx();
|
|
805
|
-
this.pio.checkInterrupts();
|
|
806
|
-
}
|
|
807
|
-
break;
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
if (!this.waiting) {
|
|
811
|
-
this.nextPC();
|
|
812
|
-
this.cycles += this.waitDelay;
|
|
813
|
-
this.execCtrl &= ~EXECCTRL_EXEC_STALLED;
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
exports.StateMachine = StateMachine;
|
|
818
|
-
class RPPIO extends
|
|
819
|
-
constructor(rp2040, name, firstIrq, index) {
|
|
820
|
-
super(rp2040, name);
|
|
821
|
-
this.firstIrq = firstIrq;
|
|
822
|
-
this.index = index;
|
|
823
|
-
this.instructions = new Uint32Array(32);
|
|
824
|
-
this.dreqRx = this.index ? dreqRx1 : dreqRx0;
|
|
825
|
-
this.dreqTx = this.index ? dreqTx1 : dreqTx0;
|
|
826
|
-
this.machines = [
|
|
827
|
-
new StateMachine(this.rp2040, this, 0),
|
|
828
|
-
new StateMachine(this.rp2040, this, 1),
|
|
829
|
-
new StateMachine(this.rp2040, this, 2),
|
|
830
|
-
new StateMachine(this.rp2040, this, 3),
|
|
831
|
-
];
|
|
832
|
-
this.stopped = true;
|
|
833
|
-
this.fdebug = 0;
|
|
834
|
-
this.inputSyncBypass = 0;
|
|
835
|
-
this.irq = 0;
|
|
836
|
-
this.pinValues = 0;
|
|
837
|
-
this.pinDirections = 0;
|
|
838
|
-
this.oldPinValues = 0;
|
|
839
|
-
this.oldPinDirections = 0;
|
|
840
|
-
this.runTimer = null;
|
|
841
|
-
this.irq0IntEnable = 0;
|
|
842
|
-
this.irq0IntForce = 0;
|
|
843
|
-
this.irq1IntEnable = 0;
|
|
844
|
-
this.irq1IntForce = 0;
|
|
845
|
-
}
|
|
846
|
-
get intRaw() {
|
|
847
|
-
return (((this.irq & 0xf) << 8) |
|
|
848
|
-
(!this.machines[3].txFIFO.full ? 0x80 : 0) |
|
|
849
|
-
(!this.machines[2].txFIFO.full ? 0x40 : 0) |
|
|
850
|
-
(!this.machines[1].txFIFO.full ? 0x20 : 0) |
|
|
851
|
-
(!this.machines[0].txFIFO.full ? 0x10 : 0) |
|
|
852
|
-
(!this.machines[3].rxFIFO.empty ? 0x08 : 0) |
|
|
853
|
-
(!this.machines[2].rxFIFO.empty ? 0x04 : 0) |
|
|
854
|
-
(!this.machines[1].rxFIFO.empty ? 0x02 : 0) |
|
|
855
|
-
(!this.machines[0].rxFIFO.empty ? 0x01 : 0));
|
|
856
|
-
}
|
|
857
|
-
get irq0IntStatus() {
|
|
858
|
-
return (this.intRaw & this.irq0IntEnable) | this.irq0IntForce;
|
|
859
|
-
}
|
|
860
|
-
get irq1IntStatus() {
|
|
861
|
-
return (this.intRaw & this.irq1IntEnable) | this.irq1IntForce;
|
|
862
|
-
}
|
|
863
|
-
readUint32(offset) {
|
|
864
|
-
if (offset >= SM0_CLKDIV && offset <= SM0_PINCTRL) {
|
|
865
|
-
return this.machines[0].readUint32(offset - SM0_CLKDIV);
|
|
866
|
-
}
|
|
867
|
-
if (offset >= SM1_CLKDIV && offset <= SM1_PINCTRL) {
|
|
868
|
-
return this.machines[1].readUint32(offset - SM1_CLKDIV);
|
|
869
|
-
}
|
|
870
|
-
if (offset >= SM2_CLKDIV && offset <= SM2_PINCTRL) {
|
|
871
|
-
return this.machines[2].readUint32(offset - SM2_CLKDIV);
|
|
872
|
-
}
|
|
873
|
-
if (offset >= SM3_CLKDIV && offset <= SM3_PINCTRL) {
|
|
874
|
-
return this.machines[3].readUint32(offset - SM3_CLKDIV);
|
|
875
|
-
}
|
|
876
|
-
switch (offset) {
|
|
877
|
-
case CTRL:
|
|
878
|
-
return ((this.machines[0].enabled ? 1 << 0 : 0) |
|
|
879
|
-
(this.machines[1].enabled ? 1 << 1 : 0) |
|
|
880
|
-
(this.machines[2].enabled ? 1 << 2 : 0) |
|
|
881
|
-
(this.machines[3].enabled ? 1 << 3 : 0));
|
|
882
|
-
case FSTAT:
|
|
883
|
-
return (this.machines[0].fifoStat |
|
|
884
|
-
this.machines[1].fifoStat |
|
|
885
|
-
this.machines[2].fifoStat |
|
|
886
|
-
this.machines[3].fifoStat);
|
|
887
|
-
case FDEBUG:
|
|
888
|
-
return this.fdebug;
|
|
889
|
-
case FLEVEL:
|
|
890
|
-
return ((this.machines[0].txFIFO.itemCount & 0xf) |
|
|
891
|
-
((this.machines[0].rxFIFO.itemCount & 0xf) << 4) |
|
|
892
|
-
((this.machines[1].txFIFO.itemCount & 0xf) << 8) |
|
|
893
|
-
((this.machines[1].rxFIFO.itemCount & 0xf) << 12) |
|
|
894
|
-
((this.machines[2].txFIFO.itemCount & 0xf) << 16) |
|
|
895
|
-
((this.machines[2].rxFIFO.itemCount & 0xf) << 20) |
|
|
896
|
-
((this.machines[3].txFIFO.itemCount & 0xf) << 24) |
|
|
897
|
-
((this.machines[3].rxFIFO.itemCount & 0xf) << 28));
|
|
898
|
-
case RXF0:
|
|
899
|
-
return this.machines[0].readFIFO();
|
|
900
|
-
case RXF1:
|
|
901
|
-
return this.machines[1].readFIFO();
|
|
902
|
-
case RXF2:
|
|
903
|
-
return this.machines[2].readFIFO();
|
|
904
|
-
case RXF3:
|
|
905
|
-
return this.machines[3].readFIFO();
|
|
906
|
-
case IRQ:
|
|
907
|
-
return this.irq;
|
|
908
|
-
case IRQ_FORCE:
|
|
909
|
-
return 0;
|
|
910
|
-
case INPUT_SYNC_BYPASS:
|
|
911
|
-
return this.inputSyncBypass;
|
|
912
|
-
case DBG_PADOUT:
|
|
913
|
-
return this.pinValues;
|
|
914
|
-
case DBG_PADOE:
|
|
915
|
-
return this.pinDirections;
|
|
916
|
-
case DBG_CFGINFO:
|
|
917
|
-
return 0x200404;
|
|
918
|
-
case INTR:
|
|
919
|
-
return this.intRaw;
|
|
920
|
-
case IRQ0_INTE:
|
|
921
|
-
return this.irq0IntEnable;
|
|
922
|
-
case IRQ0_INTF:
|
|
923
|
-
return this.irq0IntForce;
|
|
924
|
-
case IRQ0_INTS:
|
|
925
|
-
return this.irq0IntStatus;
|
|
926
|
-
case IRQ1_INTE:
|
|
927
|
-
return this.irq1IntEnable;
|
|
928
|
-
case IRQ1_INTF:
|
|
929
|
-
return this.irq1IntForce;
|
|
930
|
-
case IRQ1_INTS:
|
|
931
|
-
return this.irq1IntStatus;
|
|
932
|
-
}
|
|
933
|
-
return super.readUint32(offset);
|
|
934
|
-
}
|
|
935
|
-
writeUint32(offset, value) {
|
|
936
|
-
if (offset >= INSTR_MEM0 && offset <= INSTR_MEM31) {
|
|
937
|
-
const index = (offset - INSTR_MEM0) >> 2;
|
|
938
|
-
this.instructions[index] = value & 0xffff;
|
|
939
|
-
return;
|
|
940
|
-
}
|
|
941
|
-
if (offset >= SM0_CLKDIV && offset <= SM0_PINCTRL) {
|
|
942
|
-
this.machines[0].writeUint32(offset - SM0_CLKDIV, value);
|
|
943
|
-
return;
|
|
944
|
-
}
|
|
945
|
-
if (offset >= SM1_CLKDIV && offset <= SM1_PINCTRL) {
|
|
946
|
-
this.machines[1].writeUint32(offset - SM1_CLKDIV, value);
|
|
947
|
-
return;
|
|
948
|
-
}
|
|
949
|
-
if (offset >= SM2_CLKDIV && offset <= SM2_PINCTRL) {
|
|
950
|
-
this.machines[2].writeUint32(offset - SM2_CLKDIV, value);
|
|
951
|
-
return;
|
|
952
|
-
}
|
|
953
|
-
if (offset >= SM3_CLKDIV && offset <= SM3_PINCTRL) {
|
|
954
|
-
this.machines[3].writeUint32(offset - SM3_CLKDIV, value);
|
|
955
|
-
return;
|
|
956
|
-
}
|
|
957
|
-
switch (offset) {
|
|
958
|
-
case CTRL: {
|
|
959
|
-
for (let index = 0; index < 4; index++) {
|
|
960
|
-
this.machines[index].enabled = value & (1 << index) ? true : false;
|
|
961
|
-
if (value & (1 << (4 + index))) {
|
|
962
|
-
this.machines[index].restart();
|
|
963
|
-
}
|
|
964
|
-
if (value & (1 << (8 + index))) {
|
|
965
|
-
this.machines[index].clkDivRestart();
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
const shouldRun = value & 0xf;
|
|
969
|
-
if (this.stopped && shouldRun) {
|
|
970
|
-
this.stopped = false;
|
|
971
|
-
this.run();
|
|
972
|
-
}
|
|
973
|
-
if (!shouldRun) {
|
|
974
|
-
this.stopped = true;
|
|
975
|
-
}
|
|
976
|
-
break;
|
|
977
|
-
}
|
|
978
|
-
case FDEBUG:
|
|
979
|
-
this.fdebug &= ~this.rawWriteValue;
|
|
980
|
-
break;
|
|
981
|
-
case TXF0:
|
|
982
|
-
this.machines[0].writeFIFO(value);
|
|
983
|
-
break;
|
|
984
|
-
case TXF1:
|
|
985
|
-
this.machines[1].writeFIFO(value);
|
|
986
|
-
break;
|
|
987
|
-
case TXF2:
|
|
988
|
-
this.machines[2].writeFIFO(value);
|
|
989
|
-
break;
|
|
990
|
-
case TXF3:
|
|
991
|
-
this.machines[3].writeFIFO(value);
|
|
992
|
-
break;
|
|
993
|
-
case IRQ:
|
|
994
|
-
this.irq &= ~this.rawWriteValue;
|
|
995
|
-
this.irqUpdated();
|
|
996
|
-
break;
|
|
997
|
-
case INPUT_SYNC_BYPASS:
|
|
998
|
-
this.inputSyncBypass = value;
|
|
999
|
-
break;
|
|
1000
|
-
case IRQ_FORCE:
|
|
1001
|
-
this.irq |= value;
|
|
1002
|
-
this.irqUpdated();
|
|
1003
|
-
break;
|
|
1004
|
-
case IRQ0_INTE:
|
|
1005
|
-
this.irq0IntEnable = value & 0xfff;
|
|
1006
|
-
this.checkInterrupts();
|
|
1007
|
-
break;
|
|
1008
|
-
case IRQ0_INTF:
|
|
1009
|
-
this.irq0IntForce = value & 0xfff;
|
|
1010
|
-
this.checkInterrupts();
|
|
1011
|
-
break;
|
|
1012
|
-
case IRQ1_INTE:
|
|
1013
|
-
this.irq1IntEnable = value & 0xfff;
|
|
1014
|
-
this.checkInterrupts();
|
|
1015
|
-
break;
|
|
1016
|
-
case IRQ1_INTF:
|
|
1017
|
-
this.irq1IntForce = value & 0xfff;
|
|
1018
|
-
this.checkInterrupts();
|
|
1019
|
-
break;
|
|
1020
|
-
default:
|
|
1021
|
-
super.writeUint32(offset, value);
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
pinValuesChanged(value, firstPin, count) {
|
|
1025
|
-
// TODO: wrapping after pin 31
|
|
1026
|
-
const mask = count > 31 ? 0xffffffff : ((1 << count) - 1) << firstPin;
|
|
1027
|
-
const newValue = ((this.pinValues & ~mask) | ((value << firstPin) & mask)) & 0x3fffffff;
|
|
1028
|
-
this.pinValues = newValue;
|
|
1029
|
-
}
|
|
1030
|
-
pinDirectionsChanged(value, firstPin, count) {
|
|
1031
|
-
// TODO: wrapping after pin 31
|
|
1032
|
-
const mask = count > 31 ? 0xffffffff : ((1 << count) - 1) << firstPin;
|
|
1033
|
-
const newValue = ((this.pinDirections & ~mask) | ((value << firstPin) & mask)) & 0x3fffffff;
|
|
1034
|
-
this.pinDirections = newValue;
|
|
1035
|
-
}
|
|
1036
|
-
checkInterrupts() {
|
|
1037
|
-
const { firstIrq } = this;
|
|
1038
|
-
this.rp2040.setInterrupt(firstIrq, !!this.irq0IntStatus);
|
|
1039
|
-
this.rp2040.setInterrupt(firstIrq + 1, !!this.irq1IntStatus);
|
|
1040
|
-
}
|
|
1041
|
-
irqUpdated() {
|
|
1042
|
-
for (const machine of this.machines) {
|
|
1043
|
-
machine.checkWait();
|
|
1044
|
-
}
|
|
1045
|
-
this.checkInterrupts();
|
|
1046
|
-
}
|
|
1047
|
-
checkChangedPins() {
|
|
1048
|
-
const changedPins = (this.oldPinDirections ^ this.pinDirections) | (this.oldPinValues ^ this.pinValues);
|
|
1049
|
-
if (changedPins) {
|
|
1050
|
-
this.oldPinDirections = this.pinDirections;
|
|
1051
|
-
this.oldPinValues = this.pinValues;
|
|
1052
|
-
// Notify GPIO about the changed pins
|
|
1053
|
-
const { gpio } = this.rp2040;
|
|
1054
|
-
for (let gpioIndex = 0; gpioIndex < gpio.length; gpioIndex++) {
|
|
1055
|
-
if (changedPins & (1 << gpioIndex)) {
|
|
1056
|
-
gpio[gpioIndex].checkForUpdates();
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
step() {
|
|
1062
|
-
for (const machine of this.machines) {
|
|
1063
|
-
machine.step();
|
|
1064
|
-
}
|
|
1065
|
-
this.checkChangedPins();
|
|
1066
|
-
}
|
|
1067
|
-
run() {
|
|
1068
|
-
for (let i = 0; i < 1000 && !this.stopped; i++) {
|
|
1069
|
-
this.step();
|
|
1070
|
-
}
|
|
1071
|
-
if (!this.stopped) {
|
|
1072
|
-
this.runTimer = setTimeout(() => this.run(), 0);
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
stop() {
|
|
1076
|
-
for (const machine of this.machines) {
|
|
1077
|
-
machine.enabled = false;
|
|
1078
|
-
}
|
|
1079
|
-
this.stopped = true;
|
|
1080
|
-
if (this.runTimer) {
|
|
1081
|
-
clearTimeout(this.runTimer);
|
|
1082
|
-
this.runTimer = null;
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
exports.RPPIO = RPPIO;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RPPIO = exports.StateMachine = exports.WaitType = void 0;
|
|
4
|
+
const fifo_js_1 = require("../utils/fifo.js");
|
|
5
|
+
const dma_js_1 = require("./dma.js");
|
|
6
|
+
const peripheral_js_1 = require("./peripheral.js");
|
|
7
|
+
// Generic registers
|
|
8
|
+
const CTRL = 0x000;
|
|
9
|
+
const FSTAT = 0x004;
|
|
10
|
+
const FDEBUG = 0x008;
|
|
11
|
+
const FLEVEL = 0x00c;
|
|
12
|
+
const IRQ = 0x030;
|
|
13
|
+
const IRQ_FORCE = 0x034;
|
|
14
|
+
const INPUT_SYNC_BYPASS = 0x038;
|
|
15
|
+
const DBG_PADOUT = 0x03c;
|
|
16
|
+
const DBG_PADOE = 0x040;
|
|
17
|
+
const DBG_CFGINFO = 0x044;
|
|
18
|
+
const INSTR_MEM0 = 0x48;
|
|
19
|
+
const INSTR_MEM31 = 0x0c4;
|
|
20
|
+
const INTR = 0x128; // Raw Interrupts
|
|
21
|
+
const IRQ0_INTE = 0x12c; // Interrupt Enable for irq0
|
|
22
|
+
const IRQ0_INTF = 0x130; // Interrupt Force for irq0
|
|
23
|
+
const IRQ0_INTS = 0x134; // Interrupt status after masking & forcing for irq0
|
|
24
|
+
const IRQ1_INTE = 0x138; // Interrupt Enable for irq1
|
|
25
|
+
const IRQ1_INTF = 0x13c; // Interrupt Force for irq1
|
|
26
|
+
const IRQ1_INTS = 0x140; // Interrupt status after masking & forcing for irq1
|
|
27
|
+
// State-machine specific registers
|
|
28
|
+
const TXF0 = 0x010;
|
|
29
|
+
const TXF1 = 0x014;
|
|
30
|
+
const TXF2 = 0x018;
|
|
31
|
+
const TXF3 = 0x01c;
|
|
32
|
+
const RXF0 = 0x020;
|
|
33
|
+
const RXF1 = 0x024;
|
|
34
|
+
const RXF2 = 0x028;
|
|
35
|
+
const RXF3 = 0x02c;
|
|
36
|
+
const SM0_CLKDIV = 0x0c8; // Clock divisor register for state machine 0
|
|
37
|
+
const SM0_EXECCTRL = 0x0cc; // Execution/behavioural settings for state machine 0
|
|
38
|
+
const SM0_SHIFTCTRL = 0x0d0; // Control behaviour of the input/output shift registers for state machine 0
|
|
39
|
+
const SM0_ADDR = 0x0d4; // Current instruction address of state machine 0
|
|
40
|
+
const SM0_INSTR = 0x0d8; // Write to execute an instruction immediately (including jumps) and then resume execution.
|
|
41
|
+
const SM0_PINCTRL = 0x0dc; //State machine pin control
|
|
42
|
+
const SM1_CLKDIV = 0x0e0;
|
|
43
|
+
const SM1_PINCTRL = 0x0f4;
|
|
44
|
+
const SM2_CLKDIV = 0x0f8;
|
|
45
|
+
const SM2_PINCTRL = 0x10c;
|
|
46
|
+
const SM3_CLKDIV = 0x110;
|
|
47
|
+
const SM3_PINCTRL = 0x124;
|
|
48
|
+
// FSTAT bits
|
|
49
|
+
const FSTAT_TXEMPTY = 1 << 24;
|
|
50
|
+
const FSTAT_TXFULL = 1 << 16;
|
|
51
|
+
const FSTAT_RXEMPTY = 1 << 8;
|
|
52
|
+
const FSTAT_RXFULL = 1 << 0;
|
|
53
|
+
// FDEBUG bits
|
|
54
|
+
const FDEBUG_TXSTALL = 1 << 24;
|
|
55
|
+
const FDEBUG_TXOVER = 1 << 16;
|
|
56
|
+
const FDEBUG_RXUNDER = 1 << 8;
|
|
57
|
+
const FDEBUG_RXSTALL = 1 << 0;
|
|
58
|
+
// SHIFTCTRL bits
|
|
59
|
+
const SHIFTCTRL_AUTOPUSH = 1 << 16;
|
|
60
|
+
const SHIFTCTRL_AUTOPULL = 1 << 17;
|
|
61
|
+
const SHIFTCTRL_IN_SHIFTDIR = 1 << 18; // 1 = shift input shift register to right (data enters from left). 0 = to left
|
|
62
|
+
const SHIFTCTRL_OUT_SHIFTDIR = 1 << 19; // 1 = shift out of output shift register to right. 0 = to left
|
|
63
|
+
// EXECCTRL bits
|
|
64
|
+
const EXECCTRL_STATUS_SEL = 1 << 4;
|
|
65
|
+
const EXECCTRL_SIDE_PINDIR = 1 << 29;
|
|
66
|
+
const EXECCTRL_SIDE_EN = 1 << 30;
|
|
67
|
+
const EXECCTRL_EXEC_STALLED = 1 << 31;
|
|
68
|
+
var WaitType;
|
|
69
|
+
(function (WaitType) {
|
|
70
|
+
WaitType[WaitType["None"] = 0] = "None";
|
|
71
|
+
WaitType[WaitType["Pin"] = 1] = "Pin";
|
|
72
|
+
WaitType[WaitType["rxFIFO"] = 2] = "rxFIFO";
|
|
73
|
+
WaitType[WaitType["txFIFO"] = 3] = "txFIFO";
|
|
74
|
+
WaitType[WaitType["IRQ"] = 4] = "IRQ";
|
|
75
|
+
WaitType[WaitType["Out"] = 5] = "Out";
|
|
76
|
+
})(WaitType || (exports.WaitType = WaitType = {}));
|
|
77
|
+
function bitReverse(x) {
|
|
78
|
+
x = ((x & 0x55555555) << 1) | ((x & 0xaaaaaaaa) >>> 1);
|
|
79
|
+
x = ((x & 0x33333333) << 2) | ((x & 0xcccccccc) >>> 2);
|
|
80
|
+
x = ((x & 0x0f0f0f0f) << 4) | ((x & 0xf0f0f0f0) >>> 4);
|
|
81
|
+
x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >>> 8);
|
|
82
|
+
x = ((x & 0x0000ffff) << 16) | ((x & 0xffff0000) >>> 16);
|
|
83
|
+
return x >>> 0;
|
|
84
|
+
}
|
|
85
|
+
function irqIndex(irq, machineIndex) {
|
|
86
|
+
const rel = !!(irq & 0x10);
|
|
87
|
+
return rel ? (irq & 0x4) | (((irq & 0x3) + machineIndex) & 0x3) : irq & 0x7;
|
|
88
|
+
}
|
|
89
|
+
const dreqRx0 = [
|
|
90
|
+
dma_js_1.DREQChannel.DREQ_PIO0_RX0,
|
|
91
|
+
dma_js_1.DREQChannel.DREQ_PIO0_RX1,
|
|
92
|
+
dma_js_1.DREQChannel.DREQ_PIO0_RX2,
|
|
93
|
+
dma_js_1.DREQChannel.DREQ_PIO0_RX3,
|
|
94
|
+
];
|
|
95
|
+
const dreqTx0 = [
|
|
96
|
+
dma_js_1.DREQChannel.DREQ_PIO0_TX0,
|
|
97
|
+
dma_js_1.DREQChannel.DREQ_PIO0_TX1,
|
|
98
|
+
dma_js_1.DREQChannel.DREQ_PIO0_TX2,
|
|
99
|
+
dma_js_1.DREQChannel.DREQ_PIO0_TX3,
|
|
100
|
+
];
|
|
101
|
+
const dreqRx1 = [
|
|
102
|
+
dma_js_1.DREQChannel.DREQ_PIO1_RX0,
|
|
103
|
+
dma_js_1.DREQChannel.DREQ_PIO1_RX1,
|
|
104
|
+
dma_js_1.DREQChannel.DREQ_PIO1_RX2,
|
|
105
|
+
dma_js_1.DREQChannel.DREQ_PIO1_RX3,
|
|
106
|
+
];
|
|
107
|
+
const dreqTx1 = [
|
|
108
|
+
dma_js_1.DREQChannel.DREQ_PIO1_TX0,
|
|
109
|
+
dma_js_1.DREQChannel.DREQ_PIO1_TX1,
|
|
110
|
+
dma_js_1.DREQChannel.DREQ_PIO1_TX2,
|
|
111
|
+
dma_js_1.DREQChannel.DREQ_PIO1_TX3,
|
|
112
|
+
];
|
|
113
|
+
class StateMachine {
|
|
114
|
+
constructor(rp2040, pio, index) {
|
|
115
|
+
this.rp2040 = rp2040;
|
|
116
|
+
this.pio = pio;
|
|
117
|
+
this.index = index;
|
|
118
|
+
this.enabled = false;
|
|
119
|
+
// State machine registers
|
|
120
|
+
this.x = 0;
|
|
121
|
+
this.y = 0;
|
|
122
|
+
this.pc = 0;
|
|
123
|
+
this.inputShiftReg = 0;
|
|
124
|
+
this.inputShiftCount = 0;
|
|
125
|
+
this.outputShiftReg = 0;
|
|
126
|
+
this.outputShiftCount = 0;
|
|
127
|
+
this.cycles = 0;
|
|
128
|
+
this.execOpcode = 0;
|
|
129
|
+
this.execValid = false;
|
|
130
|
+
this.updatePC = true;
|
|
131
|
+
this.clockDivInt = 1;
|
|
132
|
+
this.clockDivFrac = 0;
|
|
133
|
+
this.execCtrl = 0x1f << 12;
|
|
134
|
+
this.shiftCtrl = 0b11 << 18;
|
|
135
|
+
this.pinCtrl = 0x5 << 26;
|
|
136
|
+
this.rxFIFO = new fifo_js_1.FIFO(4);
|
|
137
|
+
this.txFIFO = new fifo_js_1.FIFO(4);
|
|
138
|
+
this.outPinValues = 0;
|
|
139
|
+
this.outPinDirection = 0;
|
|
140
|
+
this.waiting = false;
|
|
141
|
+
this.waitType = WaitType.None;
|
|
142
|
+
this.waitIndex = 0;
|
|
143
|
+
this.waitPolarity = false;
|
|
144
|
+
this.waitDelay = -1;
|
|
145
|
+
this.dreqRx = this.pio.dreqRx[this.index];
|
|
146
|
+
this.dreqTx = this.pio.dreqTx[this.index];
|
|
147
|
+
this.updateDMARx();
|
|
148
|
+
this.updateDMATx();
|
|
149
|
+
}
|
|
150
|
+
updateDMATx() {
|
|
151
|
+
if (this.txFIFO.full) {
|
|
152
|
+
this.rp2040.dma.clearDREQ(this.dreqTx);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
this.rp2040.dma.setDREQ(this.dreqTx);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
updateDMARx() {
|
|
159
|
+
if (this.rxFIFO.empty) {
|
|
160
|
+
this.rp2040.dma.clearDREQ(this.dreqRx);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
this.rp2040.dma.setDREQ(this.dreqRx);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
writeFIFO(value) {
|
|
167
|
+
if (this.txFIFO.full) {
|
|
168
|
+
this.pio.fdebug |= FDEBUG_TXOVER << this.index;
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
this.txFIFO.push(value);
|
|
172
|
+
this.updateDMATx();
|
|
173
|
+
this.checkWait();
|
|
174
|
+
if (this.txFIFO.full) {
|
|
175
|
+
this.pio.checkInterrupts();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
readFIFO() {
|
|
179
|
+
if (this.rxFIFO.empty) {
|
|
180
|
+
this.pio.fdebug |= FDEBUG_RXUNDER << this.index;
|
|
181
|
+
return 0;
|
|
182
|
+
}
|
|
183
|
+
const result = this.rxFIFO.pull();
|
|
184
|
+
this.updateDMARx();
|
|
185
|
+
this.checkWait();
|
|
186
|
+
if (this.rxFIFO.empty) {
|
|
187
|
+
this.pio.checkInterrupts();
|
|
188
|
+
}
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
get status() {
|
|
192
|
+
const statusN = this.execCtrl & 0xf;
|
|
193
|
+
if (this.execCtrl & EXECCTRL_STATUS_SEL) {
|
|
194
|
+
return this.rxFIFO.itemCount < statusN ? 0xffffffff : 0;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
return this.txFIFO.itemCount < statusN ? 0xffffffff : 0;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
jmpCondition(condition) {
|
|
201
|
+
switch (condition) {
|
|
202
|
+
// (no condition): Always
|
|
203
|
+
case 0b000:
|
|
204
|
+
return true;
|
|
205
|
+
// !X: scratch X zero
|
|
206
|
+
case 0b001:
|
|
207
|
+
return this.x === 0;
|
|
208
|
+
// X--: scratch X non-zero, post-decrement
|
|
209
|
+
case 0b010: {
|
|
210
|
+
const oldX = this.x;
|
|
211
|
+
this.x = (this.x - 1) >>> 0;
|
|
212
|
+
return oldX !== 0;
|
|
213
|
+
}
|
|
214
|
+
// !Y: scratch Y zero
|
|
215
|
+
case 0b011:
|
|
216
|
+
return this.y === 0;
|
|
217
|
+
// Y--: scratch Y non-zero, post-decrement
|
|
218
|
+
case 0b100: {
|
|
219
|
+
const oldY = this.y;
|
|
220
|
+
this.y = (this.y - 1) >>> 0;
|
|
221
|
+
return oldY !== 0;
|
|
222
|
+
}
|
|
223
|
+
// X!=Y: scratch X not equal scratch Y
|
|
224
|
+
case 0b101:
|
|
225
|
+
return this.x >>> 0 !== this.y >>> 0;
|
|
226
|
+
// PIN: branch on input pin
|
|
227
|
+
case 0b110: {
|
|
228
|
+
const { gpio } = this.rp2040;
|
|
229
|
+
const { jmpPin } = this;
|
|
230
|
+
return jmpPin < gpio.length ? gpio[jmpPin].inputValue : false;
|
|
231
|
+
}
|
|
232
|
+
// !OSRE: output shift register not empty
|
|
233
|
+
case 0b111:
|
|
234
|
+
return this.outputShiftCount < this.pullThreshold;
|
|
235
|
+
}
|
|
236
|
+
this.pio.error(`jmpCondition with unsupported condition: ${condition}`);
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
get inPins() {
|
|
240
|
+
const { gpioValues } = this.rp2040;
|
|
241
|
+
const { inBase } = this;
|
|
242
|
+
return inBase ? (gpioValues << (32 - inBase)) | (gpioValues >>> inBase) : gpioValues;
|
|
243
|
+
}
|
|
244
|
+
inSourceValue(source) {
|
|
245
|
+
switch (source) {
|
|
246
|
+
// PINS
|
|
247
|
+
case 0b000:
|
|
248
|
+
return this.inPins;
|
|
249
|
+
// X (scratch register X)
|
|
250
|
+
case 0b001:
|
|
251
|
+
return this.x;
|
|
252
|
+
// Y (scratch register Y)
|
|
253
|
+
case 0b010:
|
|
254
|
+
return this.y;
|
|
255
|
+
// NULL (all zeroes)
|
|
256
|
+
case 0b011:
|
|
257
|
+
return 0;
|
|
258
|
+
// Reserved
|
|
259
|
+
case 0b100:
|
|
260
|
+
return 0;
|
|
261
|
+
// Reserved for IN, STATUS for MOV
|
|
262
|
+
case 0b101:
|
|
263
|
+
return this.status;
|
|
264
|
+
// ISR
|
|
265
|
+
case 0b110:
|
|
266
|
+
return this.inputShiftReg;
|
|
267
|
+
// OSR
|
|
268
|
+
case 0b111:
|
|
269
|
+
return this.outputShiftReg;
|
|
270
|
+
}
|
|
271
|
+
this.pio.error(`inSourceValue with unsupported source: ${source}`);
|
|
272
|
+
return 0;
|
|
273
|
+
}
|
|
274
|
+
writeOutValue(destination, value, bitCount) {
|
|
275
|
+
switch (destination) {
|
|
276
|
+
// PINS
|
|
277
|
+
case 0b000:
|
|
278
|
+
this.setOutPins(value);
|
|
279
|
+
break;
|
|
280
|
+
// X (scratch register X)
|
|
281
|
+
case 0b001:
|
|
282
|
+
this.x = value;
|
|
283
|
+
break;
|
|
284
|
+
// Y (scratch register Y)
|
|
285
|
+
case 0b010:
|
|
286
|
+
this.y = value;
|
|
287
|
+
break;
|
|
288
|
+
// NULL (discard data)
|
|
289
|
+
case 0b011:
|
|
290
|
+
break;
|
|
291
|
+
// PINDIRS
|
|
292
|
+
case 0b100:
|
|
293
|
+
this.setOutPinDirs(value);
|
|
294
|
+
break;
|
|
295
|
+
// PC
|
|
296
|
+
case 0b101:
|
|
297
|
+
this.pc = value & 0x1f;
|
|
298
|
+
this.updatePC = false;
|
|
299
|
+
break;
|
|
300
|
+
// ISR (also sets ISR shift counter to Bit count)
|
|
301
|
+
case 0b110:
|
|
302
|
+
this.inputShiftReg = value;
|
|
303
|
+
this.inputShiftCount = bitCount;
|
|
304
|
+
break;
|
|
305
|
+
// EXEC (Execute OSR shift data as instruction)
|
|
306
|
+
case 0b111:
|
|
307
|
+
this.execOpcode = value;
|
|
308
|
+
this.execValid = true;
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
get pushThreshold() {
|
|
313
|
+
const value = (this.shiftCtrl >> 20) & 0x1f;
|
|
314
|
+
return value ? value : 32;
|
|
315
|
+
}
|
|
316
|
+
get pullThreshold() {
|
|
317
|
+
const value = (this.shiftCtrl >> 25) & 0x1f;
|
|
318
|
+
return value ? value : 32;
|
|
319
|
+
}
|
|
320
|
+
get sidesetCount() {
|
|
321
|
+
return (this.pinCtrl >> 29) & 0x7;
|
|
322
|
+
}
|
|
323
|
+
get setCount() {
|
|
324
|
+
return (this.pinCtrl >> 26) & 0x7;
|
|
325
|
+
}
|
|
326
|
+
get outCount() {
|
|
327
|
+
return (this.pinCtrl >> 20) & 0x3f;
|
|
328
|
+
}
|
|
329
|
+
get inBase() {
|
|
330
|
+
return (this.pinCtrl >> 15) & 0x1f;
|
|
331
|
+
}
|
|
332
|
+
get sidesetBase() {
|
|
333
|
+
return (this.pinCtrl >> 10) & 0x1f;
|
|
334
|
+
}
|
|
335
|
+
get setBase() {
|
|
336
|
+
return (this.pinCtrl >> 5) & 0x1f;
|
|
337
|
+
}
|
|
338
|
+
get outBase() {
|
|
339
|
+
return (this.pinCtrl >> 0) & 0x1f;
|
|
340
|
+
}
|
|
341
|
+
get jmpPin() {
|
|
342
|
+
return (this.execCtrl >> 24) & 0x1f;
|
|
343
|
+
}
|
|
344
|
+
get wrapTop() {
|
|
345
|
+
return (this.execCtrl >> 12) & 0x1f;
|
|
346
|
+
}
|
|
347
|
+
get wrapBottom() {
|
|
348
|
+
return (this.execCtrl >> 7) & 0x1f;
|
|
349
|
+
}
|
|
350
|
+
setOutPinDirs(value) {
|
|
351
|
+
this.outPinDirection = value;
|
|
352
|
+
this.pio.pinDirectionsChanged(value, this.outBase, this.outCount);
|
|
353
|
+
}
|
|
354
|
+
setOutPins(value) {
|
|
355
|
+
this.outPinValues = value;
|
|
356
|
+
this.pio.pinValuesChanged(value, this.outBase, this.outCount);
|
|
357
|
+
}
|
|
358
|
+
outInstruction(arg) {
|
|
359
|
+
const bitCount = arg & 0x1f;
|
|
360
|
+
const destination = arg >> 5;
|
|
361
|
+
if (bitCount === 0) {
|
|
362
|
+
this.writeOutValue(destination, this.outputShiftReg, 32);
|
|
363
|
+
this.outputShiftCount = 32;
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
if (this.shiftCtrl & SHIFTCTRL_OUT_SHIFTDIR) {
|
|
367
|
+
const value = this.outputShiftReg & ((1 << bitCount) - 1);
|
|
368
|
+
this.outputShiftReg >>>= bitCount;
|
|
369
|
+
this.writeOutValue(destination, value, bitCount);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
const value = this.outputShiftReg >>> (32 - bitCount);
|
|
373
|
+
this.outputShiftReg <<= bitCount;
|
|
374
|
+
this.writeOutValue(destination, value, bitCount);
|
|
375
|
+
}
|
|
376
|
+
this.outputShiftCount += bitCount;
|
|
377
|
+
if (this.outputShiftCount > 32) {
|
|
378
|
+
this.outputShiftCount = 32;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
executeInstruction(opcode) {
|
|
383
|
+
const arg = opcode & 0xff;
|
|
384
|
+
switch (opcode >>> 13) {
|
|
385
|
+
/* JMP */
|
|
386
|
+
case 0b000:
|
|
387
|
+
if (this.jmpCondition(arg >> 5)) {
|
|
388
|
+
this.pc = arg & 0x1f;
|
|
389
|
+
this.updatePC = false;
|
|
390
|
+
}
|
|
391
|
+
break;
|
|
392
|
+
/* WAIT */
|
|
393
|
+
case 0b001: {
|
|
394
|
+
const polarity = !!(arg & 0x80);
|
|
395
|
+
const source = (arg >> 5) & 0x3;
|
|
396
|
+
const index = arg & 0x1f;
|
|
397
|
+
switch (source) {
|
|
398
|
+
// GPIO:
|
|
399
|
+
case 0b00:
|
|
400
|
+
this.wait(WaitType.Pin, polarity, index);
|
|
401
|
+
break;
|
|
402
|
+
// PIN:
|
|
403
|
+
case 0b01:
|
|
404
|
+
this.wait(WaitType.Pin, polarity, (index + this.inBase) % 32);
|
|
405
|
+
break;
|
|
406
|
+
// IRQ:
|
|
407
|
+
case 0b10:
|
|
408
|
+
this.wait(WaitType.IRQ, polarity, irqIndex(index, this.index));
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
/* IN */
|
|
414
|
+
case 0b010: {
|
|
415
|
+
const bitCount = arg & 0x1f;
|
|
416
|
+
let sourceValue = this.inSourceValue(arg >> 5);
|
|
417
|
+
if (bitCount == 0) {
|
|
418
|
+
this.inputShiftReg = sourceValue;
|
|
419
|
+
this.inputShiftCount = 32;
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
sourceValue &= (1 << bitCount) - 1;
|
|
423
|
+
if (this.shiftCtrl & SHIFTCTRL_IN_SHIFTDIR) {
|
|
424
|
+
this.inputShiftReg >>>= bitCount;
|
|
425
|
+
this.inputShiftReg |= sourceValue << (32 - bitCount);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
this.inputShiftReg <<= bitCount;
|
|
429
|
+
this.inputShiftReg |= sourceValue;
|
|
430
|
+
}
|
|
431
|
+
this.inputShiftCount += bitCount;
|
|
432
|
+
if (this.inputShiftCount > 32) {
|
|
433
|
+
this.inputShiftCount = 32;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (this.shiftCtrl & SHIFTCTRL_AUTOPUSH && this.inputShiftCount >= this.pushThreshold) {
|
|
437
|
+
if (!this.rxFIFO.full) {
|
|
438
|
+
this.rxFIFO.push(this.inputShiftReg);
|
|
439
|
+
this.updateDMARx();
|
|
440
|
+
this.pio.checkInterrupts();
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
this.pio.fdebug |= FDEBUG_RXSTALL << this.index;
|
|
444
|
+
this.wait(WaitType.rxFIFO, false, this.inputShiftReg);
|
|
445
|
+
}
|
|
446
|
+
this.inputShiftCount = 0;
|
|
447
|
+
this.inputShiftReg = 0;
|
|
448
|
+
}
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
/* OUT */
|
|
452
|
+
case 0b011: {
|
|
453
|
+
if (this.shiftCtrl & SHIFTCTRL_AUTOPULL && this.outputShiftCount >= this.pullThreshold) {
|
|
454
|
+
this.outputShiftCount = 0;
|
|
455
|
+
if (!this.txFIFO.empty) {
|
|
456
|
+
this.outputShiftReg = this.txFIFO.pull();
|
|
457
|
+
this.updateDMATx();
|
|
458
|
+
this.pio.checkInterrupts();
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
this.pio.fdebug |= FDEBUG_TXSTALL << this.index;
|
|
462
|
+
this.wait(WaitType.Out, false, arg);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (!this.waiting) {
|
|
466
|
+
this.outInstruction(arg);
|
|
467
|
+
}
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
/* PUSH/PULL */
|
|
471
|
+
case 0b100: {
|
|
472
|
+
const block = !!(arg & (1 << 5));
|
|
473
|
+
const ifFullOrEmpty = !!(arg & (1 << 6));
|
|
474
|
+
if (arg & 0x1f) {
|
|
475
|
+
// Unknown instruction
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
if (arg & 0x80) {
|
|
479
|
+
// PULL
|
|
480
|
+
if (ifFullOrEmpty &&
|
|
481
|
+
this.shiftCtrl & SHIFTCTRL_AUTOPULL &&
|
|
482
|
+
this.outputShiftCount < this.pullThreshold) {
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
if (!this.txFIFO.empty) {
|
|
486
|
+
this.outputShiftReg = this.txFIFO.pull();
|
|
487
|
+
this.updateDMATx();
|
|
488
|
+
this.pio.checkInterrupts();
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
this.pio.fdebug |= FDEBUG_TXSTALL << this.index;
|
|
492
|
+
if (block) {
|
|
493
|
+
this.wait(WaitType.txFIFO, false, 0);
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
this.outputShiftReg = this.x;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
this.outputShiftCount = 0;
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
// PUSH
|
|
503
|
+
if (ifFullOrEmpty &&
|
|
504
|
+
this.shiftCtrl & SHIFTCTRL_AUTOPUSH &&
|
|
505
|
+
this.inputShiftCount < this.pushThreshold) {
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
if (!this.rxFIFO.full) {
|
|
509
|
+
this.rxFIFO.push(this.inputShiftReg);
|
|
510
|
+
this.updateDMARx();
|
|
511
|
+
this.pio.checkInterrupts();
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
this.pio.fdebug |= FDEBUG_RXSTALL << this.index;
|
|
515
|
+
if (block) {
|
|
516
|
+
this.wait(WaitType.rxFIFO, false, this.inputShiftReg);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
this.inputShiftReg = 0;
|
|
520
|
+
this.inputShiftCount = 0;
|
|
521
|
+
}
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
/* MOV */
|
|
525
|
+
case 0b101: {
|
|
526
|
+
const source = arg & 0x7;
|
|
527
|
+
const op = (arg >> 3) & 0x3;
|
|
528
|
+
const destination = (arg >> 5) & 0x7;
|
|
529
|
+
const value = this.inSourceValue(source);
|
|
530
|
+
const transformedValue = this.transformMovValue(value, op) >>> 0;
|
|
531
|
+
this.setMovDestination(destination, transformedValue);
|
|
532
|
+
break;
|
|
533
|
+
}
|
|
534
|
+
/* IRQ */
|
|
535
|
+
case 0b110: {
|
|
536
|
+
if (arg & 0x80) {
|
|
537
|
+
// Unknown instruction
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
const clear = !!(arg & 0x40);
|
|
541
|
+
const wait = !!(arg & 0x20);
|
|
542
|
+
const irq = irqIndex(arg & 0x1f, this.index);
|
|
543
|
+
if (clear) {
|
|
544
|
+
this.pio.irq &= ~(1 << irq);
|
|
545
|
+
this.pio.irqUpdated();
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
this.pio.irq |= 1 << irq;
|
|
549
|
+
this.pio.irqUpdated();
|
|
550
|
+
if (wait) {
|
|
551
|
+
this.wait(WaitType.IRQ, false, irq);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
/* SET */
|
|
557
|
+
case 0b111: {
|
|
558
|
+
const data = arg & 0x1f;
|
|
559
|
+
const destination = arg >> 5;
|
|
560
|
+
switch (destination) {
|
|
561
|
+
case 0b000:
|
|
562
|
+
this.setSetPins(data);
|
|
563
|
+
break;
|
|
564
|
+
case 0b001:
|
|
565
|
+
this.x = data;
|
|
566
|
+
break;
|
|
567
|
+
case 0b010:
|
|
568
|
+
this.y = data;
|
|
569
|
+
break;
|
|
570
|
+
case 0b100:
|
|
571
|
+
this.setSetPinDirs(data);
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
this.cycles++;
|
|
578
|
+
const { sidesetCount, execCtrl } = this;
|
|
579
|
+
const delaySideset = (opcode >> 8) & 0x1f;
|
|
580
|
+
const sideEn = !!(execCtrl & EXECCTRL_SIDE_EN);
|
|
581
|
+
const delay = delaySideset & ((1 << (5 - sidesetCount)) - 1);
|
|
582
|
+
if (sidesetCount && (!sideEn || delaySideset & 0x10)) {
|
|
583
|
+
const sideset = delaySideset >> (5 - sidesetCount);
|
|
584
|
+
this.setSideset(sideset, sideEn ? sidesetCount - 1 : sidesetCount);
|
|
585
|
+
}
|
|
586
|
+
if (this.execValid) {
|
|
587
|
+
this.execValid = false;
|
|
588
|
+
this.executeInstruction(this.execOpcode);
|
|
589
|
+
}
|
|
590
|
+
else if (this.waiting) {
|
|
591
|
+
if (this.waitDelay < 0) {
|
|
592
|
+
this.waitDelay = delay;
|
|
593
|
+
}
|
|
594
|
+
this.checkWait();
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
this.cycles += delay;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
wait(type, polarity, index) {
|
|
601
|
+
this.waiting = true;
|
|
602
|
+
this.waitType = type;
|
|
603
|
+
this.waitPolarity = polarity;
|
|
604
|
+
this.waitIndex = index;
|
|
605
|
+
this.waitDelay = -1;
|
|
606
|
+
this.updatePC = false;
|
|
607
|
+
}
|
|
608
|
+
nextPC() {
|
|
609
|
+
if (this.pc === this.wrapTop) {
|
|
610
|
+
this.pc = this.wrapBottom;
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
this.pc = (this.pc + 1) & 0x1f;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
step() {
|
|
617
|
+
if (this.waiting) {
|
|
618
|
+
this.checkWait();
|
|
619
|
+
if (this.waiting) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
this.updatePC = true;
|
|
624
|
+
this.executeInstruction(this.pio.instructions[this.pc]);
|
|
625
|
+
if (this.updatePC) {
|
|
626
|
+
this.nextPC();
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
setSetPinDirs(value) {
|
|
630
|
+
this.pio.pinDirectionsChanged(value, this.setBase, this.setCount);
|
|
631
|
+
}
|
|
632
|
+
setSetPins(value) {
|
|
633
|
+
this.pio.pinValuesChanged(value, this.setBase, this.setCount);
|
|
634
|
+
}
|
|
635
|
+
setSideset(value, count) {
|
|
636
|
+
if (this.execCtrl & EXECCTRL_SIDE_PINDIR) {
|
|
637
|
+
this.pio.pinDirectionsChanged(value, this.sidesetBase, count);
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
this.pio.pinValuesChanged(value, this.sidesetBase, count);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
transformMovValue(value, op) {
|
|
644
|
+
switch (op) {
|
|
645
|
+
case 0b00:
|
|
646
|
+
return value;
|
|
647
|
+
case 0b01:
|
|
648
|
+
return ~value;
|
|
649
|
+
case 0b10:
|
|
650
|
+
return bitReverse(value);
|
|
651
|
+
case 0b11:
|
|
652
|
+
default:
|
|
653
|
+
return value; // reserved
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
setMovDestination(destination, value) {
|
|
657
|
+
switch (destination) {
|
|
658
|
+
// PINS
|
|
659
|
+
case 0b000:
|
|
660
|
+
this.setOutPins(value);
|
|
661
|
+
break;
|
|
662
|
+
// X (scratch register X)
|
|
663
|
+
case 0b001:
|
|
664
|
+
this.x = value;
|
|
665
|
+
break;
|
|
666
|
+
// Y (scratch register Y)
|
|
667
|
+
case 0b010:
|
|
668
|
+
this.y = value;
|
|
669
|
+
break;
|
|
670
|
+
// reserved (discard data)
|
|
671
|
+
case 0b011:
|
|
672
|
+
break;
|
|
673
|
+
// EXEC
|
|
674
|
+
case 0b100:
|
|
675
|
+
this.execOpcode = value;
|
|
676
|
+
this.execValid = true;
|
|
677
|
+
break;
|
|
678
|
+
// PC
|
|
679
|
+
case 0b101:
|
|
680
|
+
this.pc = value & 0x1f;
|
|
681
|
+
this.updatePC = false;
|
|
682
|
+
break;
|
|
683
|
+
// ISR (Input shift counter is reset to 0 by this operation, i.e. empty)
|
|
684
|
+
case 0b110:
|
|
685
|
+
this.inputShiftReg = value;
|
|
686
|
+
this.inputShiftCount = 0;
|
|
687
|
+
break;
|
|
688
|
+
// OSR (Output shift counter is reset to 0 by this operation, i.e. full)
|
|
689
|
+
case 0b111:
|
|
690
|
+
this.outputShiftReg = value;
|
|
691
|
+
this.outputShiftCount = 0;
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
readUint32(offset) {
|
|
696
|
+
switch (offset + SM0_CLKDIV) {
|
|
697
|
+
case SM0_CLKDIV:
|
|
698
|
+
return (this.clockDivInt << 16) | (this.clockDivFrac << 8);
|
|
699
|
+
case SM0_EXECCTRL:
|
|
700
|
+
return this.execCtrl;
|
|
701
|
+
case SM0_SHIFTCTRL:
|
|
702
|
+
return this.shiftCtrl;
|
|
703
|
+
case SM0_ADDR:
|
|
704
|
+
return this.pc;
|
|
705
|
+
case SM0_INSTR:
|
|
706
|
+
return this.pio.instructions[this.pc];
|
|
707
|
+
case SM0_PINCTRL:
|
|
708
|
+
return this.pinCtrl;
|
|
709
|
+
}
|
|
710
|
+
this.pio.error(`Read from invalid state machine register: ${offset}`);
|
|
711
|
+
return 0;
|
|
712
|
+
}
|
|
713
|
+
writeUint32(offset, value) {
|
|
714
|
+
switch (offset + SM0_CLKDIV) {
|
|
715
|
+
case SM0_CLKDIV:
|
|
716
|
+
this.clockDivFrac = (value >>> 8) & 0xff;
|
|
717
|
+
this.clockDivInt = value >>> 16;
|
|
718
|
+
break;
|
|
719
|
+
case SM0_EXECCTRL:
|
|
720
|
+
this.execCtrl = ((value & 0x7fffffff) | (this.execCtrl & 0x80000000)) >>> 0;
|
|
721
|
+
break;
|
|
722
|
+
case SM0_SHIFTCTRL:
|
|
723
|
+
this.shiftCtrl = value;
|
|
724
|
+
break;
|
|
725
|
+
case SM0_ADDR:
|
|
726
|
+
/* read-only */
|
|
727
|
+
break;
|
|
728
|
+
case SM0_INSTR:
|
|
729
|
+
this.executeInstruction(value & 0xffff);
|
|
730
|
+
if (this.waiting) {
|
|
731
|
+
this.execCtrl |= EXECCTRL_EXEC_STALLED;
|
|
732
|
+
}
|
|
733
|
+
break;
|
|
734
|
+
case SM0_PINCTRL:
|
|
735
|
+
this.pinCtrl = value;
|
|
736
|
+
break;
|
|
737
|
+
default:
|
|
738
|
+
this.pio.error(`Write to invalid state machine register: ${offset}`);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
get fifoStat() {
|
|
742
|
+
const result = (this.txFIFO.empty ? FSTAT_TXEMPTY : 0) |
|
|
743
|
+
(this.txFIFO.full ? FSTAT_TXFULL : 0) |
|
|
744
|
+
(this.rxFIFO.empty ? FSTAT_RXEMPTY : 0) |
|
|
745
|
+
(this.rxFIFO.full ? FSTAT_RXFULL : 0);
|
|
746
|
+
return result << this.index;
|
|
747
|
+
}
|
|
748
|
+
restart() {
|
|
749
|
+
this.cycles = 0;
|
|
750
|
+
this.inputShiftCount = 0;
|
|
751
|
+
this.outputShiftCount = 32;
|
|
752
|
+
this.inputShiftReg = 0;
|
|
753
|
+
this.waiting = false;
|
|
754
|
+
// TODO any pin write left asserted due to OUT_STICKY.
|
|
755
|
+
}
|
|
756
|
+
clkDivRestart() {
|
|
757
|
+
this.pio.warn('clkDivRestart not implemented');
|
|
758
|
+
}
|
|
759
|
+
checkWait() {
|
|
760
|
+
if (!this.waiting) {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
switch (this.waitType) {
|
|
764
|
+
case WaitType.IRQ: {
|
|
765
|
+
const irqValue = !!(this.pio.irq & (1 << this.waitIndex));
|
|
766
|
+
if (irqValue === this.waitPolarity) {
|
|
767
|
+
this.waiting = false;
|
|
768
|
+
if (irqValue) {
|
|
769
|
+
this.pio.irq &= ~(1 << this.waitIndex);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
774
|
+
case WaitType.Pin: {
|
|
775
|
+
if (this.waitIndex < this.rp2040.gpio.length &&
|
|
776
|
+
this.rp2040.gpio[this.waitIndex].inputValue === this.waitPolarity) {
|
|
777
|
+
this.waiting = false;
|
|
778
|
+
}
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
case WaitType.rxFIFO: {
|
|
782
|
+
if (!this.rxFIFO.full) {
|
|
783
|
+
this.rxFIFO.push(this.waitIndex);
|
|
784
|
+
this.waiting = false;
|
|
785
|
+
this.updateDMARx();
|
|
786
|
+
this.pio.checkInterrupts();
|
|
787
|
+
}
|
|
788
|
+
break;
|
|
789
|
+
}
|
|
790
|
+
case WaitType.txFIFO: {
|
|
791
|
+
if (!this.txFIFO.empty) {
|
|
792
|
+
this.outputShiftReg = this.txFIFO.pull();
|
|
793
|
+
this.waiting = false;
|
|
794
|
+
this.updateDMATx();
|
|
795
|
+
this.pio.checkInterrupts();
|
|
796
|
+
}
|
|
797
|
+
break;
|
|
798
|
+
}
|
|
799
|
+
case WaitType.Out: {
|
|
800
|
+
if (!this.txFIFO.empty) {
|
|
801
|
+
this.outputShiftReg = this.txFIFO.pull();
|
|
802
|
+
this.outInstruction(this.waitIndex);
|
|
803
|
+
this.waiting = false;
|
|
804
|
+
this.updateDMATx();
|
|
805
|
+
this.pio.checkInterrupts();
|
|
806
|
+
}
|
|
807
|
+
break;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
if (!this.waiting) {
|
|
811
|
+
this.nextPC();
|
|
812
|
+
this.cycles += this.waitDelay;
|
|
813
|
+
this.execCtrl &= ~EXECCTRL_EXEC_STALLED;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
exports.StateMachine = StateMachine;
|
|
818
|
+
class RPPIO extends peripheral_js_1.BasePeripheral {
|
|
819
|
+
constructor(rp2040, name, firstIrq, index) {
|
|
820
|
+
super(rp2040, name);
|
|
821
|
+
this.firstIrq = firstIrq;
|
|
822
|
+
this.index = index;
|
|
823
|
+
this.instructions = new Uint32Array(32);
|
|
824
|
+
this.dreqRx = this.index ? dreqRx1 : dreqRx0;
|
|
825
|
+
this.dreqTx = this.index ? dreqTx1 : dreqTx0;
|
|
826
|
+
this.machines = [
|
|
827
|
+
new StateMachine(this.rp2040, this, 0),
|
|
828
|
+
new StateMachine(this.rp2040, this, 1),
|
|
829
|
+
new StateMachine(this.rp2040, this, 2),
|
|
830
|
+
new StateMachine(this.rp2040, this, 3),
|
|
831
|
+
];
|
|
832
|
+
this.stopped = true;
|
|
833
|
+
this.fdebug = 0;
|
|
834
|
+
this.inputSyncBypass = 0;
|
|
835
|
+
this.irq = 0;
|
|
836
|
+
this.pinValues = 0;
|
|
837
|
+
this.pinDirections = 0;
|
|
838
|
+
this.oldPinValues = 0;
|
|
839
|
+
this.oldPinDirections = 0;
|
|
840
|
+
this.runTimer = null;
|
|
841
|
+
this.irq0IntEnable = 0;
|
|
842
|
+
this.irq0IntForce = 0;
|
|
843
|
+
this.irq1IntEnable = 0;
|
|
844
|
+
this.irq1IntForce = 0;
|
|
845
|
+
}
|
|
846
|
+
get intRaw() {
|
|
847
|
+
return (((this.irq & 0xf) << 8) |
|
|
848
|
+
(!this.machines[3].txFIFO.full ? 0x80 : 0) |
|
|
849
|
+
(!this.machines[2].txFIFO.full ? 0x40 : 0) |
|
|
850
|
+
(!this.machines[1].txFIFO.full ? 0x20 : 0) |
|
|
851
|
+
(!this.machines[0].txFIFO.full ? 0x10 : 0) |
|
|
852
|
+
(!this.machines[3].rxFIFO.empty ? 0x08 : 0) |
|
|
853
|
+
(!this.machines[2].rxFIFO.empty ? 0x04 : 0) |
|
|
854
|
+
(!this.machines[1].rxFIFO.empty ? 0x02 : 0) |
|
|
855
|
+
(!this.machines[0].rxFIFO.empty ? 0x01 : 0));
|
|
856
|
+
}
|
|
857
|
+
get irq0IntStatus() {
|
|
858
|
+
return (this.intRaw & this.irq0IntEnable) | this.irq0IntForce;
|
|
859
|
+
}
|
|
860
|
+
get irq1IntStatus() {
|
|
861
|
+
return (this.intRaw & this.irq1IntEnable) | this.irq1IntForce;
|
|
862
|
+
}
|
|
863
|
+
readUint32(offset) {
|
|
864
|
+
if (offset >= SM0_CLKDIV && offset <= SM0_PINCTRL) {
|
|
865
|
+
return this.machines[0].readUint32(offset - SM0_CLKDIV);
|
|
866
|
+
}
|
|
867
|
+
if (offset >= SM1_CLKDIV && offset <= SM1_PINCTRL) {
|
|
868
|
+
return this.machines[1].readUint32(offset - SM1_CLKDIV);
|
|
869
|
+
}
|
|
870
|
+
if (offset >= SM2_CLKDIV && offset <= SM2_PINCTRL) {
|
|
871
|
+
return this.machines[2].readUint32(offset - SM2_CLKDIV);
|
|
872
|
+
}
|
|
873
|
+
if (offset >= SM3_CLKDIV && offset <= SM3_PINCTRL) {
|
|
874
|
+
return this.machines[3].readUint32(offset - SM3_CLKDIV);
|
|
875
|
+
}
|
|
876
|
+
switch (offset) {
|
|
877
|
+
case CTRL:
|
|
878
|
+
return ((this.machines[0].enabled ? 1 << 0 : 0) |
|
|
879
|
+
(this.machines[1].enabled ? 1 << 1 : 0) |
|
|
880
|
+
(this.machines[2].enabled ? 1 << 2 : 0) |
|
|
881
|
+
(this.machines[3].enabled ? 1 << 3 : 0));
|
|
882
|
+
case FSTAT:
|
|
883
|
+
return (this.machines[0].fifoStat |
|
|
884
|
+
this.machines[1].fifoStat |
|
|
885
|
+
this.machines[2].fifoStat |
|
|
886
|
+
this.machines[3].fifoStat);
|
|
887
|
+
case FDEBUG:
|
|
888
|
+
return this.fdebug;
|
|
889
|
+
case FLEVEL:
|
|
890
|
+
return ((this.machines[0].txFIFO.itemCount & 0xf) |
|
|
891
|
+
((this.machines[0].rxFIFO.itemCount & 0xf) << 4) |
|
|
892
|
+
((this.machines[1].txFIFO.itemCount & 0xf) << 8) |
|
|
893
|
+
((this.machines[1].rxFIFO.itemCount & 0xf) << 12) |
|
|
894
|
+
((this.machines[2].txFIFO.itemCount & 0xf) << 16) |
|
|
895
|
+
((this.machines[2].rxFIFO.itemCount & 0xf) << 20) |
|
|
896
|
+
((this.machines[3].txFIFO.itemCount & 0xf) << 24) |
|
|
897
|
+
((this.machines[3].rxFIFO.itemCount & 0xf) << 28));
|
|
898
|
+
case RXF0:
|
|
899
|
+
return this.machines[0].readFIFO();
|
|
900
|
+
case RXF1:
|
|
901
|
+
return this.machines[1].readFIFO();
|
|
902
|
+
case RXF2:
|
|
903
|
+
return this.machines[2].readFIFO();
|
|
904
|
+
case RXF3:
|
|
905
|
+
return this.machines[3].readFIFO();
|
|
906
|
+
case IRQ:
|
|
907
|
+
return this.irq;
|
|
908
|
+
case IRQ_FORCE:
|
|
909
|
+
return 0;
|
|
910
|
+
case INPUT_SYNC_BYPASS:
|
|
911
|
+
return this.inputSyncBypass;
|
|
912
|
+
case DBG_PADOUT:
|
|
913
|
+
return this.pinValues;
|
|
914
|
+
case DBG_PADOE:
|
|
915
|
+
return this.pinDirections;
|
|
916
|
+
case DBG_CFGINFO:
|
|
917
|
+
return 0x200404;
|
|
918
|
+
case INTR:
|
|
919
|
+
return this.intRaw;
|
|
920
|
+
case IRQ0_INTE:
|
|
921
|
+
return this.irq0IntEnable;
|
|
922
|
+
case IRQ0_INTF:
|
|
923
|
+
return this.irq0IntForce;
|
|
924
|
+
case IRQ0_INTS:
|
|
925
|
+
return this.irq0IntStatus;
|
|
926
|
+
case IRQ1_INTE:
|
|
927
|
+
return this.irq1IntEnable;
|
|
928
|
+
case IRQ1_INTF:
|
|
929
|
+
return this.irq1IntForce;
|
|
930
|
+
case IRQ1_INTS:
|
|
931
|
+
return this.irq1IntStatus;
|
|
932
|
+
}
|
|
933
|
+
return super.readUint32(offset);
|
|
934
|
+
}
|
|
935
|
+
writeUint32(offset, value) {
|
|
936
|
+
if (offset >= INSTR_MEM0 && offset <= INSTR_MEM31) {
|
|
937
|
+
const index = (offset - INSTR_MEM0) >> 2;
|
|
938
|
+
this.instructions[index] = value & 0xffff;
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
if (offset >= SM0_CLKDIV && offset <= SM0_PINCTRL) {
|
|
942
|
+
this.machines[0].writeUint32(offset - SM0_CLKDIV, value);
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
if (offset >= SM1_CLKDIV && offset <= SM1_PINCTRL) {
|
|
946
|
+
this.machines[1].writeUint32(offset - SM1_CLKDIV, value);
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
if (offset >= SM2_CLKDIV && offset <= SM2_PINCTRL) {
|
|
950
|
+
this.machines[2].writeUint32(offset - SM2_CLKDIV, value);
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
if (offset >= SM3_CLKDIV && offset <= SM3_PINCTRL) {
|
|
954
|
+
this.machines[3].writeUint32(offset - SM3_CLKDIV, value);
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
switch (offset) {
|
|
958
|
+
case CTRL: {
|
|
959
|
+
for (let index = 0; index < 4; index++) {
|
|
960
|
+
this.machines[index].enabled = value & (1 << index) ? true : false;
|
|
961
|
+
if (value & (1 << (4 + index))) {
|
|
962
|
+
this.machines[index].restart();
|
|
963
|
+
}
|
|
964
|
+
if (value & (1 << (8 + index))) {
|
|
965
|
+
this.machines[index].clkDivRestart();
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
const shouldRun = value & 0xf;
|
|
969
|
+
if (this.stopped && shouldRun) {
|
|
970
|
+
this.stopped = false;
|
|
971
|
+
this.run();
|
|
972
|
+
}
|
|
973
|
+
if (!shouldRun) {
|
|
974
|
+
this.stopped = true;
|
|
975
|
+
}
|
|
976
|
+
break;
|
|
977
|
+
}
|
|
978
|
+
case FDEBUG:
|
|
979
|
+
this.fdebug &= ~this.rawWriteValue;
|
|
980
|
+
break;
|
|
981
|
+
case TXF0:
|
|
982
|
+
this.machines[0].writeFIFO(value);
|
|
983
|
+
break;
|
|
984
|
+
case TXF1:
|
|
985
|
+
this.machines[1].writeFIFO(value);
|
|
986
|
+
break;
|
|
987
|
+
case TXF2:
|
|
988
|
+
this.machines[2].writeFIFO(value);
|
|
989
|
+
break;
|
|
990
|
+
case TXF3:
|
|
991
|
+
this.machines[3].writeFIFO(value);
|
|
992
|
+
break;
|
|
993
|
+
case IRQ:
|
|
994
|
+
this.irq &= ~this.rawWriteValue;
|
|
995
|
+
this.irqUpdated();
|
|
996
|
+
break;
|
|
997
|
+
case INPUT_SYNC_BYPASS:
|
|
998
|
+
this.inputSyncBypass = value;
|
|
999
|
+
break;
|
|
1000
|
+
case IRQ_FORCE:
|
|
1001
|
+
this.irq |= value;
|
|
1002
|
+
this.irqUpdated();
|
|
1003
|
+
break;
|
|
1004
|
+
case IRQ0_INTE:
|
|
1005
|
+
this.irq0IntEnable = value & 0xfff;
|
|
1006
|
+
this.checkInterrupts();
|
|
1007
|
+
break;
|
|
1008
|
+
case IRQ0_INTF:
|
|
1009
|
+
this.irq0IntForce = value & 0xfff;
|
|
1010
|
+
this.checkInterrupts();
|
|
1011
|
+
break;
|
|
1012
|
+
case IRQ1_INTE:
|
|
1013
|
+
this.irq1IntEnable = value & 0xfff;
|
|
1014
|
+
this.checkInterrupts();
|
|
1015
|
+
break;
|
|
1016
|
+
case IRQ1_INTF:
|
|
1017
|
+
this.irq1IntForce = value & 0xfff;
|
|
1018
|
+
this.checkInterrupts();
|
|
1019
|
+
break;
|
|
1020
|
+
default:
|
|
1021
|
+
super.writeUint32(offset, value);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
pinValuesChanged(value, firstPin, count) {
|
|
1025
|
+
// TODO: wrapping after pin 31
|
|
1026
|
+
const mask = count > 31 ? 0xffffffff : ((1 << count) - 1) << firstPin;
|
|
1027
|
+
const newValue = ((this.pinValues & ~mask) | ((value << firstPin) & mask)) & 0x3fffffff;
|
|
1028
|
+
this.pinValues = newValue;
|
|
1029
|
+
}
|
|
1030
|
+
pinDirectionsChanged(value, firstPin, count) {
|
|
1031
|
+
// TODO: wrapping after pin 31
|
|
1032
|
+
const mask = count > 31 ? 0xffffffff : ((1 << count) - 1) << firstPin;
|
|
1033
|
+
const newValue = ((this.pinDirections & ~mask) | ((value << firstPin) & mask)) & 0x3fffffff;
|
|
1034
|
+
this.pinDirections = newValue;
|
|
1035
|
+
}
|
|
1036
|
+
checkInterrupts() {
|
|
1037
|
+
const { firstIrq } = this;
|
|
1038
|
+
this.rp2040.setInterrupt(firstIrq, !!this.irq0IntStatus);
|
|
1039
|
+
this.rp2040.setInterrupt(firstIrq + 1, !!this.irq1IntStatus);
|
|
1040
|
+
}
|
|
1041
|
+
irqUpdated() {
|
|
1042
|
+
for (const machine of this.machines) {
|
|
1043
|
+
machine.checkWait();
|
|
1044
|
+
}
|
|
1045
|
+
this.checkInterrupts();
|
|
1046
|
+
}
|
|
1047
|
+
checkChangedPins() {
|
|
1048
|
+
const changedPins = (this.oldPinDirections ^ this.pinDirections) | (this.oldPinValues ^ this.pinValues);
|
|
1049
|
+
if (changedPins) {
|
|
1050
|
+
this.oldPinDirections = this.pinDirections;
|
|
1051
|
+
this.oldPinValues = this.pinValues;
|
|
1052
|
+
// Notify GPIO about the changed pins
|
|
1053
|
+
const { gpio } = this.rp2040;
|
|
1054
|
+
for (let gpioIndex = 0; gpioIndex < gpio.length; gpioIndex++) {
|
|
1055
|
+
if (changedPins & (1 << gpioIndex)) {
|
|
1056
|
+
gpio[gpioIndex].checkForUpdates();
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
step() {
|
|
1062
|
+
for (const machine of this.machines) {
|
|
1063
|
+
machine.step();
|
|
1064
|
+
}
|
|
1065
|
+
this.checkChangedPins();
|
|
1066
|
+
}
|
|
1067
|
+
run() {
|
|
1068
|
+
for (let i = 0; i < 1000 && !this.stopped; i++) {
|
|
1069
|
+
this.step();
|
|
1070
|
+
}
|
|
1071
|
+
if (!this.stopped) {
|
|
1072
|
+
this.runTimer = setTimeout(() => this.run(), 0);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
stop() {
|
|
1076
|
+
for (const machine of this.machines) {
|
|
1077
|
+
machine.enabled = false;
|
|
1078
|
+
}
|
|
1079
|
+
this.stopped = true;
|
|
1080
|
+
if (this.runTimer) {
|
|
1081
|
+
clearTimeout(this.runTimer);
|
|
1082
|
+
this.runTimer = null;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
exports.RPPIO = RPPIO;
|