Skip to content

Commit d9206f2

Browse files
committed
refactor Encode* functions to rcv 8 bit args; begin adding spi3w
1 parent 8bb1d77 commit d9206f2

File tree

11 files changed

+295
-89
lines changed

11 files changed

+295
-89
lines changed

rp2-pio/instr.go

Lines changed: 102 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,39 @@ import (
55
"math"
66
)
77

8+
// InstrKind is a enum for the PIO instruction type. It only represents the kind of
9+
// instruction. It cannot store the arguments.
10+
type InstrKind uint8
11+
12+
const (
13+
InstrJMP InstrKind = iota
14+
InstrWAIT
15+
InstrIN
16+
InstrOUT
17+
InstrPUSH
18+
InstrPULL
19+
InstrMOV
20+
InstrIRQ
21+
InstrSET
22+
)
23+
824
// This file contains the primitives for creating instructions dynamically
925
const (
10-
INSTR_BITS_JMP = 0x0000
11-
INSTR_BITS_WAIT = 0x2000
12-
INSTR_BITS_IN = 0x4000
13-
INSTR_BITS_OUT = 0x6000
14-
INSTR_BITS_PUSH = 0x8000
15-
INSTR_BITS_PULL = 0x8080
16-
INSTR_BITS_MOV = 0xa000
17-
INSTR_BITS_IRQ = 0xc000
18-
INSTR_BITS_SET = 0xe000
26+
_INSTR_BITS_JMP = 0x0000
27+
_INSTR_BITS_WAIT = 0x2000
28+
_INSTR_BITS_IN = 0x4000
29+
_INSTR_BITS_OUT = 0x6000
30+
_INSTR_BITS_PUSH = 0x8000
31+
_INSTR_BITS_PULL = 0x8080
32+
_INSTR_BITS_MOV = 0xa000
33+
_INSTR_BITS_IRQ = 0xc000
34+
_INSTR_BITS_SET = 0xe000
1935

2036
// Bit mask for instruction code
21-
INSTR_BITS_Msk = 0xe000
37+
_INSTR_BITS_Msk = 0xe000
2238
)
2339

24-
type SrcDest uint16
40+
type SrcDest uint8
2541

2642
const (
2743
SrcDestPins SrcDest = 0
@@ -37,125 +53,122 @@ const (
3753
SrcExecOut SrcDest = 7
3854
)
3955

40-
func MajorInstrBits(instr uint16) uint16 {
41-
return instr & INSTR_BITS_Msk
42-
}
56+
type JmpCond uint8
4357

44-
func EncodeInstrAndArgs(instr uint16, arg1 uint16, arg2 uint16) uint16 {
45-
return instr | (arg1 << 5) | (arg2 & 0x1f)
46-
}
58+
const (
59+
// No condition, always jumps.
60+
JmpAlways JmpCond = iota
61+
// Jump if X is zero.
62+
JmpXZero
63+
// Jump if X is not zero, prior to decrement of X.
64+
JmpXNZeroDec
65+
// Jump if Y is zero.
66+
JmpYZero
67+
// Jump if Y is not zero, prior to decrement of Y.
68+
JmpYNZeroDec
69+
// Jump if X is not equal to Y.
70+
JmpXNotEqualY
71+
// Jump if EXECCTRL_JMP_PIN (state machine configured) is high.
72+
JmpPinInput
73+
// Compares the bits shifted out since last pull with the shift count theshold
74+
// (configured by SHIFTCTRL_PULL_THRESH) and jumps if there are remaining bits to shift.
75+
JmpOSRNotEmpty
76+
)
4777

48-
func EncodeInstrAndSrcDest(instr uint16, dest SrcDest, value uint16) uint16 {
49-
return EncodeInstrAndArgs(instr, uint16(dest)&7, value)
78+
// EncodeInstr encodes an arbitrary PIO instruction with the given arguments.
79+
func EncodeInstr(instr InstrKind, delaySideset, arg1_3b, arg2_5b uint8) uint16 {
80+
return uint16(instr&0b111)<<13 | uint16(delaySideset&0x1f)<<8 | uint16(arg1_3b&0b111)<<5 | uint16(arg2_5b&0x1f)
5081
}
5182

52-
func EncodeDelay(cycles uint16) uint16 {
53-
return cycles << 8
83+
func majorInstrBits(instr uint16) uint16 {
84+
return instr & _INSTR_BITS_Msk
5485
}
5586

56-
func EncodeSideSet(bitCount uint16, value uint16) uint16 {
57-
return value << (13 - bitCount)
87+
func encodeInstrAndArgs(instr uint16, arg1 uint8, arg2 uint8) uint16 {
88+
return instr | (uint16(arg1) << 5) | uint16(arg2&0x1f)
5889
}
5990

60-
func EncodeSetSetOpt(bitCount uint16, value uint16) uint16 {
61-
return 0x1000 | value<<(12-bitCount)
91+
func encodeInstrAndSrcDest(instr uint16, dest SrcDest, value uint8) uint16 {
92+
return encodeInstrAndArgs(instr, uint8(dest)&7, value)
6293
}
6394

64-
func EncodeJmp(addr uint16) uint16 {
65-
return EncodeInstrAndArgs(INSTR_BITS_JMP, 0, addr)
95+
func EncodeDelay(cycles uint8) uint16 {
96+
return 0b11111 & (uint16(cycles) << 8)
6697
}
6798

68-
func EncodeIRQ(relative bool, irq uint16) uint16 {
69-
instr := irq
99+
func EncodeSideSet(bitCount, value uint8) uint16 {
100+
return uint16(value) << (13 - bitCount)
101+
}
70102

71-
if relative {
72-
instr |= 0x10
73-
}
103+
func EncodeSetSetOpt(bitCount uint8, value uint8) uint16 {
104+
return 0x1000 | uint16(value)<<(12-bitCount)
105+
}
74106

75-
return instr
107+
func EncodeJmp(addr uint8, condition JmpCond) uint16 {
108+
return encodeInstrAndArgs(_INSTR_BITS_JMP, uint8(condition&0b111), addr)
76109
}
77110

78-
func EncodeWaitGPIO(polarity bool, pin uint16) uint16 {
79-
flag := uint16(0)
80-
if polarity {
81-
flag = 0x4
82-
}
111+
func encodeIRQ(relative bool, irq uint8) uint8 {
112+
return boolAsU8(relative) << 4
113+
}
83114

84-
return EncodeInstrAndArgs(INSTR_BITS_WAIT, 0|flag, pin)
115+
func EncodeWaitGPIO(polarity bool, pin uint8) uint16 {
116+
flag := boolAsU8(polarity) << 2
117+
return encodeInstrAndArgs(_INSTR_BITS_WAIT, 0|flag, pin)
85118
}
86119

87-
func EncodeWaitPin(polarity bool, pin uint16) uint16 {
88-
flag := uint16(0)
89-
if polarity {
90-
flag = 0x4
91-
}
120+
func EncodeWaitPin(polarity bool, pin uint8) uint16 {
121+
flag := boolAsU8(polarity) << 2
92122

93-
return EncodeInstrAndArgs(INSTR_BITS_WAIT, 1|flag, pin)
123+
return encodeInstrAndArgs(_INSTR_BITS_WAIT, 1|flag, pin)
94124
}
95125

96-
func EncodeWaitIRQ(polarity bool, relative bool, irq uint16) uint16 {
97-
flag := uint16(0)
98-
if polarity {
99-
flag = 0x4
100-
}
126+
func EncodeWaitIRQ(polarity bool, relative bool, irq uint8) uint16 {
127+
flag := boolAsU8(polarity) << 2
101128

102-
return EncodeInstrAndArgs(INSTR_BITS_WAIT, 2|flag, EncodeIRQ(relative, irq))
129+
return encodeInstrAndArgs(_INSTR_BITS_WAIT, 2|flag, encodeIRQ(relative, irq))
103130
}
104131

105-
func EncodeIn(src SrcDest, value uint16) uint16 {
106-
return EncodeInstrAndSrcDest(INSTR_BITS_IN, src, value)
132+
func EncodeIn(src SrcDest, value uint8) uint16 {
133+
return encodeInstrAndSrcDest(_INSTR_BITS_IN, src, value)
107134
}
108135

109-
func EncodeOut(dest SrcDest, value uint16) uint16 {
110-
return EncodeInstrAndSrcDest(INSTR_BITS_OUT, dest, value)
136+
func EncodeOut(dest SrcDest, value uint8) uint16 {
137+
return encodeInstrAndSrcDest(_INSTR_BITS_OUT, dest, value)
111138
}
112139

113140
func EncodePush(ifFull bool, block bool) uint16 {
114-
arg := uint16(0)
115-
if ifFull {
116-
arg |= 2
117-
}
118-
if block {
119-
arg |= 1
120-
}
121-
122-
return EncodeInstrAndArgs(INSTR_BITS_PUSH, arg, 0)
141+
arg := boolAsU8(ifFull)<<1 | boolAsU8(block)
142+
return encodeInstrAndArgs(_INSTR_BITS_PUSH, arg, 0)
123143
}
124144

125145
func EncodePull(ifEmpty bool, block bool) uint16 {
126-
arg := uint16(0)
127-
if ifEmpty {
128-
arg |= 2
129-
}
130-
if block {
131-
arg |= 1
132-
}
133-
134-
return EncodeInstrAndArgs(INSTR_BITS_PULL, arg, 0)
146+
arg := boolAsU8(ifEmpty)<<1 | boolAsU8(block)
147+
return encodeInstrAndArgs(_INSTR_BITS_PULL, arg, 0)
135148
}
136149

137150
func EncodeMov(dest SrcDest, src SrcDest) uint16 {
138-
return EncodeInstrAndSrcDest(INSTR_BITS_MOV, dest, uint16(src)&7)
151+
return encodeInstrAndSrcDest(_INSTR_BITS_MOV, dest, uint8(src)&7)
139152
}
140153

141154
func EncodeMovNot(dest SrcDest, src SrcDest) uint16 {
142-
return EncodeInstrAndSrcDest(INSTR_BITS_MOV, dest, (1<<3)|(uint16(src)&7))
155+
return encodeInstrAndSrcDest(_INSTR_BITS_MOV, dest, (1<<3)|(uint8(src)&7))
143156
}
144157

145158
func EncodeMovReverse(dest SrcDest, src SrcDest) uint16 {
146-
return EncodeInstrAndSrcDest(INSTR_BITS_MOV, dest, (2<<3)|(uint16(src)&7))
159+
return encodeInstrAndSrcDest(_INSTR_BITS_MOV, dest, (2<<3)|(uint8(src)&7))
147160
}
148161

149-
func EncodeIRQSet(relative bool, irq uint16) uint16 {
150-
return EncodeInstrAndArgs(INSTR_BITS_IRQ, 0, EncodeIRQ(relative, irq))
162+
func EncodeIRQSet(relative bool, irq uint8) uint16 {
163+
return encodeInstrAndArgs(_INSTR_BITS_IRQ, 0, encodeIRQ(relative, irq))
151164
}
152165

153-
func EncodeIRQClear(relative bool, irq uint16) uint16 {
154-
return EncodeInstrAndArgs(INSTR_BITS_IRQ, 2, EncodeIRQ(relative, irq))
166+
func EncodeIRQClear(relative bool, irq uint8) uint16 {
167+
return encodeInstrAndArgs(_INSTR_BITS_IRQ, 2, encodeIRQ(relative, irq))
155168
}
156169

157-
func EncodeSet(dest SrcDest, value uint16) uint16 {
158-
return EncodeInstrAndSrcDest(INSTR_BITS_SET, dest, value)
170+
func EncodeSet(dest SrcDest, value uint8) uint16 {
171+
return encodeInstrAndSrcDest(_INSTR_BITS_SET, dest, value)
159172
}
160173

161174
func EncodeNOP() uint16 {
@@ -196,3 +209,10 @@ func splitClkdiv(clkdiv uint64) (whole uint16, frac uint8, err error) {
196209
frac = uint8(clkdiv % 256)
197210
return whole, frac, nil
198211
}
212+
213+
func boolAsU8(b bool) uint8 {
214+
if b {
215+
return 1
216+
}
217+
return 0
218+
}

rp2-pio/pio.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (pio *PIO) AddProgramAtOffset(instructions []uint16, origin int8, offset ui
104104
instr := instructions[i]
105105

106106
// Patch jump instructions with relative offset
107-
if INSTR_BITS_JMP == instr&INSTR_BITS_Msk {
107+
if _INSTR_BITS_JMP == instr&_INSTR_BITS_Msk {
108108
pio.writeInstructionMemory(offset+i, instr+uint16(offset))
109109
} else {
110110
pio.writeInstructionMemory(offset+i, instr)

rp2-pio/piolib/all_generate.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var (
1515
//go:generate pioasm -o go spi.pio spi_pio.go
1616
//go:generate pioasm -o go ws2812.pio ws2812_pio.go
1717
//go:generate pioasm -o go i2s.pio i2s_pio.go
18+
//go:generate pioasm -o go spi3w.pio spi3w_pio.go
1819
func gosched() {
1920
runtime.Gosched()
2021
}

rp2-pio/piolib/i2s.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func NewI2S(sm pio.StateMachine, data, clockAndNext machine.Pin) (*I2S, error) {
4141
sm.SetPindirsMasked(pinMask, pinMask)
4242
sm.SetPinsMasked(0, pinMask)
4343

44-
sm.Exec(pio.EncodeJmp(uint16(offset) + i2soffset_entry_point))
44+
sm.Exec(pio.EncodeJmp(offset+i2soffset_entry_point, pio.JmpAlways))
4545

4646
i2s := &I2S{
4747
sm: sm,

rp2-pio/piolib/pulsar.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func (p *Pulsar) Stop() {
8585
p.sm.ClearFIFOs()
8686
p.sm.Restart()
8787
p.sm.ClkDivRestart()
88-
p.sm.Exec(pio.EncodeJmp(uint16(p.offsetPlusOne - 1)))
88+
p.sm.Exec(pio.EncodeJmp(p.offsetPlusOne-1, pio.JmpAlways))
8989
p.sm.SetEnabled(true)
9090
}
9191

rp2-pio/piolib/spi3w.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//go:build rp2040
2+
3+
package piolib
4+
5+
import (
6+
"machine"
7+
8+
pio "github.com/tinygo-org/pio/rp2-pio"
9+
)
10+
11+
// SPI3 is a 3-wire SPI implementation for specialized use cases, such as
12+
// the Pico W's on-board CYW43439 WiFi module. It uses a shared data input/output pin.
13+
type SPI3w struct {
14+
sm pio.StateMachine
15+
offset uint8
16+
}
17+
18+
func NewSPI3(sm pio.StateMachine, dio, clk machine.Pin, baud uint32) (*SPI3w, error) {
19+
sm.Claim() // SM should be claimed beforehand, we just guarantee it's claimed.
20+
21+
Pio := sm.PIO()
22+
offset, err := Pio.AddProgram(spi3wInstructions, spi3wOrigin)
23+
if err != nil {
24+
return nil, err
25+
}
26+
27+
// Configure state machine.
28+
cfg := spi3wProgramDefaultConfig(offset)
29+
cfg.SetOutPins(dio, 1)
30+
cfg.SetSetPins(dio, 1)
31+
cfg.SetInPins(dio)
32+
cfg.SetSidesetPins(clk)
33+
cfg.SetOutShift(false, true, 32)
34+
cfg.SetInShift(false, true, 32)
35+
36+
whole, frac, err := pio.ClkDivFromFrequency(baud, machine.CPUFrequency())
37+
if err != nil {
38+
return nil, err
39+
}
40+
cfg.SetClkDivIntFrac(whole, frac)
41+
42+
// Configure pins
43+
pinCfg := machine.PinConfig{Mode: Pio.PinMode()}
44+
dio.Configure(pinCfg)
45+
clk.Configure(pinCfg)
46+
Pio.HW().INPUT_SYNC_BYPASS.SetBits(1 << dio)
47+
48+
// Initialize state machine.
49+
sm.Init(offset, cfg)
50+
pinMask := uint32(1<<dio | 1<<clk)
51+
sm.SetPindirsMasked(0, pinMask)
52+
sm.SetPinsMasked(0, pinMask)
53+
54+
sm.SetEnabled(true)
55+
56+
spiw := &SPI3w{
57+
sm: sm,
58+
offset: offset,
59+
}
60+
return spiw, nil
61+
}
62+
63+
func (spi *SPI3w) CmdRead(cmd uint32, r []uint32) error {
64+
spi.sm.SetEnabled(false)
65+
// writeBits := 31
66+
// readBits := len(r)*32 + 32 - 1
67+
68+
return nil
69+
}

rp2-pio/piolib/spi3w.pio

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; Pico W SPI interface with CY43439 support.
2+
3+
.program spi3w
4+
.side_set 1
5+
6+
.wrap_target
7+
8+
; write out x-1 bits
9+
lp:
10+
out pins, 1 side 0
11+
jmp x-- lp side 1
12+
13+
; Switch directions
14+
15+
set pindirs, 0 side 0
16+
nop side 0
17+
18+
; read in y-1 bits
19+
lp2:
20+
in pins, 1 side 1
21+
jmp y-- lp2 side 0
22+
23+
; wait for event and irq host
24+
25+
wait 1 pin 0 side 0
26+
irq 0 side 0
27+
28+
.wrap
29+
30+
% go {
31+
//go:build rp2040
32+
package piolib
33+
34+
import (
35+
pio "github.com/tinygo-org/pio/rp2-pio"
36+
)
37+
%}

0 commit comments

Comments
 (0)