17 KiB
CPLD Firmware Architecture Reference
Project: NewCalBoard DIG
Toolchain: Lattice Diamond (CPLD1/2/3), Xilinx Vivado 2023.2 (NewExtInst_Debug)
Note: This firmware is NOT fully complete — several features are stubbed out or incomplete.
1. System Overview
The system uses a Zynq SoC (ARM + FPGA) architecture with 3 external Lattice CPLDs communicating via SPI:
┌─────────────────────────────────────────────────────────────────┐
│ Zynq SoC (ARM + FPGA) │
│ ┌──────────┐ AXI ┌──────────────┐ SPI ┌─────────┐ │
│ │ ARM │◄────────►│NewExtInst_TOP│◄────────►│ CPLDs │ │
│ │ (Linux) │ GP0 │ (Vivado BD) │ SPI_Con │ (3x) │ │
│ └──────────┘ └──────────────┘ └─────────┘ │
│ ▲ │ │
│ │ ▼ │
│ │ ┌─────────────────┐ │
│ │ │ clk_wiz (PLL) │ → 100MHz CPLD clk │
│ │ │ proc_sys_reset │ │
│ │ └─────────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────────┐ │
│ │ │ ps7_axi_periph │ (1→3 split) │
│ │ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Key Components
| Component | Tool | Purpose |
|---|---|---|
NewExtInst_TOP |
Vivado 2023.2 | Top-level block design (Zynq PS + AXI peripherals) |
CPLD1/2/3 |
Lattice Diamond | CPLD firmware (Verilog) |
Release/*.jed |
— | Programming files for CPLDs |
2. CPLD Architecture (CPLD1/2/3)
Each CPLD has the same 3-module internal structure:
RelayConTop (Top)
├── BUS_Con — SPI master interface (Mode 0)
├── Reg_file — Register file + FSM
└── CPLD_Con — Relay control logic
2.1 Module: BUS_Con (SPI Interface)
Purpose: Implements a SPI Mode 0 (CPOL=0, CPHA=0) master interface.
SPI Protocol:
- CS active LOW
- MOSI sampled on rising edge of SCLK
- MISO shifted on falling edge of SCLK
- 32-bit transaction:
[Bit31: WR] [Bit30:24: Addr(7bit)] [Bit23:0: Data(24bit)]
FSM States:
IDLE → CMD_SENT → DONE → IDLE
↑ ↓
WAIT_BUSY (waits for reg_busy to clear)
Key Signals:
| Signal | Direction | Description |
|---|---|---|
i_sclk |
input | SPI clock |
i_mosi |
input | SPI data in |
i_cs |
input | Chip select (active LOW) |
o_miso |
output | SPI data out (tri-state) |
o_cmd_valid |
output | Command valid pulse |
o_addr[6:0] |
output | Register address |
o_data[23:0] |
output | Write data |
o_wr |
output | 1=write, 0=read |
o_wready |
output | Ready to accept new command |
o_err |
output | Bit count error flag |
Important Notes:
o_rvalidis hardcoded to1'b0(not implemented)- Typo in original:
o_rvaildvso_rvalidin LPF - MISO is tri-stated when CS is HIGH:
assign o_miso = cs_active ? miso_shift[31] : 1'bz;
2.2 Module: Reg_file (Register File)
Purpose: 16-register file (0-15) with read/write FSM.
Register Map:
| Addr | Name | R/W | Description |
|---|---|---|---|
| 0 | IDENT | R/W | Identity: CPLD3=0, CPLD2=0, CPLD1=1, Major=1, Minor=0, Rev=0 |
| 1 | STATE | R/W | State/Execution control. Bit 0 = EXEC trigger, Bit 23 = RDY, Bits 22:1 = Reserved |
| 2 | Freq_Slot1 | R/W | Frequency slot 1 relay control |
| 3 | Freq_Slot2 | R/W | Frequency slot 2 relay control |
| 4 | Freq_Slot3 | R/W | Frequency slot 3 relay control |
| 5 | Freq_Slot4 | R/W | Frequency slot 4 relay control |
| 6 | DC_Slot1 | R/W | DC slot 1 control |
| 7 | DC_Slot2 | W | DC slot 2 control (write-only per Excel) |
| 8 | DC_Slot3 | W | DC slot 3 control (write-only per Excel) |
| 9 | DC_Slot4 | W | DC slot 4 control (write-only per Excel) |
| 10-15 | — | — | Reserved/Unused |
Register Bit Layout (24 bits):
Freq_Slot N (Addr 2-5):
Bit 23:10: Per Relay_Control (1=Switch, 0=Not Switch) — 14 bits, one per relay
Bit 9:1: Channel_Number (1-256) — 9 bits
Bit 0: Slot_EN (1=Enable)
RC_Tx Mapping (Slot 4 only, part of Per Relay_Control bits 17:12):
| RC_Tx Bit | Output Pin |
|---|---|
| [5] | o_RC_T27 |
| [4] | o_RC_T28 |
| [3] | o_RC_T29 |
| [2] | o_RC_T30 |
| [1] | o_RC_T31 |
| [0] | o_RC_T32 |
Source: i_freq_relay4[17:12] → RC_Tx[5:0] (part of Per Relay_Control field)
Relay Control Bits per Slot (from Excel Freq_CPLD sheet):
| Slot | RC_F | RC_S | RC_T |
|---|---|---|---|
| 1 | RC_F1, RC_F2 | RC_S1-RC_S4 | RC_T1-RC_T8 |
| 2 | RC_F3, RC_F4 | RC_S5-RC_S8 | RC_T9-RC_T16 |
| 3 | RC_F5, RC_F6 | RC_S9-RC_S12 | RC_T17-RC_T24 |
| 4 | RC_F7, RC_F8 | RC_S13-RC_S16 | RC_T25-RC_T32 |
DC_Slot N (Addr 6-9):
Bit 23: PMU(0)/DPS(1) — PMU or DPS mode select
Bit 22: V(0)/I(1) — Voltage or Current select
Bit 21:17: Rload_Sel (0-31) — Resistor selection (5-bit, 0-31 range)
Bit 16:10: Reserved (7 bits)
Bit 9:1: Channel_Number (1-256) — 9 bits
Bit 0: Slot_EN (1=Enable)
FSM States:
IDLE → BUSY → EXEC_ACK → EXEC_WAIT → IDLE
↑
(crash recovery: if exec_bit==1 at reset)
Execution Protocol:
- Write
STATEregister with bit 0 = 1 - Register FSM enters EXEC_ACK, waits for
con_doneto go LOW (controller busy) - Enters EXEC_WAIT, waits for
con_doneto go HIGH (controller done) - Auto-clears exec bit, sets ready bit
- Cannot write if controller is already running (exec_bit==1 → error)
2.3 Module: CPLD_Con (Control Logic)
Purpose: Decodes register values and generates relay control outputs.
Key Logic:
- Sanity check: Only ONE enable bit should be active (
en_t > 1→ error) - Freq mode: Routes channel numbers to OC_x01/OC_x17/DMM_EN based on channel range
- DC mode: Selects resistor, PMU/DPS, V/I mode
Freq Slot Decoding (per slot, from CPLD_Con.v code):
| Channel Range | OC_x01 | OC_x17 | DMM_EN |
|---|---|---|---|
| 1-8 | Set | 0 | DMM1 |
| 9-72 | 0 | 0 | DMM2/DMM3/DMM4 |
| 73-136 | 0 | Set | DMM3/DMM4 |
| 137-200 | 0 | 0 | DMM4 |
Note: Code uses < 9, < 72, < 137, < 201 for ranges. Excel Freq_CPLD sheet shows actual channel groupings are more complex (e.g., "1-4&65-68||5-8&69-72").
ARM_CPLD Pin Assignments (from Excel ARM_CPLD sheet):
| Signal | CPLD1 Pin | CPLD2 Pin | CPLD3 Pin | Notes |
|---|---|---|---|---|
| SCLK | AA16 | AA10 | AA16 | LPF discrepancy: CPLD1 LPF says AA10 |
| CS | AB11 | Y15 | AB11 | |
| MOSI | AB12 | AB12 | AB12 | Shared across all CPLDs |
| MISO | AA14 | AA14 | AA14 | Shared across all CPLDs |
| RST_N | Y14 | Y14 | Y14 | |
| ERR | AB16 | AB16 | AB16 | |
| WVAILD | AA15 | AA15 | AA15 | |
| RREADY | AB15 | AA10 | AB15 | CPLD2: AA10 same as SCLK? |
| WREADY | Y15 | Y15 | Y15 | |
| CLK | AA10 | AA16 | AA10 | CPLD1/3: AA10, CPLD2: AA16 |
| RVAILD | AA16 | AB15 | AA16 | CPLD2: AB15 same as RREADY? |
⚠ Critical Note: CPLD1 and CPLD3 share identical SPI pins (SCLK=AA16, CS=AB11, MOSI=AB12, MISO=AA14). This requires external multiplexing or the LPF is incorrect. The LPF file may need review.
DC Slot Decoding (per slot):
- Bit 22: V(0)/I(1) select →
RC_VSel/RC_ISel - Bit 21:17: Resistor selection →
RC_RLSel(18-bit one-hot) - Bit 23: PMU(0)/DPS(1) — DPS path is STUBBED OUT (empty branch)
Output Signals:
| Signal | Width | Description |
|---|---|---|
o_OC_x01 |
4:0 | OC relay selector (CPLD1: 4-bit, CPLD2: 4-bit) |
o_OC_x17 |
4:0 | OC relay selector (CPLD1: 4-bit, CPLD2: 4-bit) |
o_RC_F[7:0] |
8 | RC_F relays (CPLD2 only) |
o_RC_S[15:0] |
16 | RC_S relays (CPLD2 only) |
o_RC_T[5:0] |
6 | RC_T relays (CPLD1: 6 bits T27-T32, CPLD2: 26 bits) |
o_RC_T27-T32 |
6 | RC_T relays (CPLD1 only, expanded from 5 bits) |
o_RC_RLSel[17:0] |
18 | Resistor load select (CPLD1 only) |
o_RC_VSel |
1 | Voltage select (CPLD1 only) |
o_RC_ISel |
1 | Current select (CPLD1 only) |
o_RC_LOF[1:0] |
2 | DMM_N port relay LOF (CPLD1 only) |
o_RC_LOS[1:0] |
2 | DMM_N port relay LOS (CPLD1 only) |
o_PMU_OC_[1-4][31:0] |
32 | PMU output channel (CPLD1 only) |
o_PMU_RC[3:0] |
4 | PMU relay control (CPLD3 only) |
o_DMM_EN[18:0] |
19 | DMM enable signals (CPLD1 only) |
o_IO_RC1 |
1 | IO relay control (CPLD1 only) |
o_con_done |
1 | Execution done flag |
o_err |
1 | Error flag |
3. CPLD Differences
CPLD1 (Most Complete)
- Role: Main relay control + PMU output + DMM enable
- Outputs: Full set including PMU_OC, DMM_EN, RC_RLSel, RC_V/I Sel, RC_LOF/LOS, IO_RC1
- RC_Tx: Expanded from 5 bits to 6 bits (T27-T32), source
[17:12] - RC_LOF/LOS: 2-bit outputs for DMM_N port relays —
o_RC_LOF = (RC_VSel==1)? 2'b01 : 2'b10 - SPI Pins: SCLK=AA16, CS=AB11, MOSI=AB12, MISO=AA14 (per ARM_CPLD sheet)
- Clock: B9, Reset: Y14
- Note: LPF file has SCLK=AA10 (discrepancy with ARM_CPLD sheet which says AA16)
CPLD2 (Partial)
- Role: RC_F/RC_S/RC_T relay control + OC channels
- Outputs: RC_F[7:0], RC_S[15:0], RC_T[25:0], OC_[1-4][31:0]
- Missing: No DC control, no DMM_EN, no RC_RLSel
- SPI Pins: SCLK=AA10, CS=Y15, MOSI=AB12, MISO=AA14 (per ARM_CPLD sheet)
- Note:
i_wvaildtypo (should bei_wvalid) - Note: No
CPLD_ConDC handling — only Freq relay logic
CPLD3 (Minimal)
- Role: PMU relay control only
- Outputs: PMU_RC[3:0] only
- SPI Pins: SCLK=AA16, CS=AB11, MOSI=AB12, MISO=AA14 (per ARM_CPLD sheet)
- Note: No DC control, no Freq relay logic
- Note:
i_rvalidtypo (should bei_rvalid— consistent with CPLD1)
4. System Interconnect (Vivado Block Design)
NewExtInst_TOP Architecture
Zynq PS (M_AXI_GP0)
│
▼
ps7_0_axi_periph (1→3 split)
├── M00 → SPI_Con_0 → CPLD1
├── M01 → SPI_Con_1 → CPLD2
└── M02 → SPI_Con_2 → CPLD3
Clock Tree
Zynq FCLK_CLK0 → clk_wiz_0 → clk_out1 (100MHz) → CPLD SPI_Con IP
↓
rst_clk_wiz_0_100M → peripheral reset
SPI_Con IP (Custom AXI Peripheral)
- 3 instances (one per CPLD)
- AXI4-Lite slave interface
- 7-bit address space (matches CPLD register count)
- Maps AXI writes to CPLD SPI commands
5. Known Issues & Incomplete Features
Critical Incomplete Features
- DPS Path Not Implemented —
CPLD_Con.vlines 266-268, 288-290, 310-312, 332-334: DPS selection branch is empty (all 4 DC slots). Wheni_DC_Con[N][23] == 1'b1, no output is driven. - CPLD_Con Slot 4 Bug —
CPLD_Con.vline 328:i_DC_Con1[23]should bei_DC_Con4[23]for slot 4 PMU/DPS selection - CPLD2 Missing DC Control — No
i_DC_Coninputs, no DC handling inCPLD_Con - CPLD3 Minimal — Only PMU_RC output, no relay logic
- o_rvalid Hardcoded —
BUS_Con.vline 211:assign o_rvalid = 1'b0;(but commented out in CPLD1 top module) - IDENT Constant Bug —
Reg_file.vline 38: uses||(logical OR) instead of|(bitwise OR):24'h200000 || 12'b0001_0000_0000evaluates to1'b1, not the intended bit pattern
Typos Found
| File | Typo | Should Be |
|---|---|---|
BUS_Con.v:92 |
o_cmd_vaild |
o_cmd_valid |
CPLD1/RelayConTop.v:105 |
cmd_vaild |
cmd_valid |
CPLD2/RelayConTop.v:11 |
i_wvaild |
i_wvalid |
CPLD2/RelayConTop.v:56 |
i_rvaild |
i_rvalid |
CPLD3/RelayConTop.v:25 |
cmd_vaild |
cmd_valid |
LPF files |
o_rvaild |
o_rvalid |
Design Concerns
- No timeout on execution FSM — If controller hangs, FSM can hang forever (line 139 in Reg_file.v: "Optional: Timeout counter here")
- No concurrent execution — Only one slot can execute at a time (
en_t > 1→ error) - Channel range validation incomplete — DC slot checks 1-18 for resistor but 1-256 for channel
- CPLD1/3 share same SPI pins — Need external multiplexing or different pin assignment (see ARM_CPLD sheet)
- LPF vs ARM_CPLD sheet discrepancy — CPLD1 SCLK: LPF=AA10, ARM_CPLD=AA16. LPF may be outdated.
- CPLD_Con channel range mismatch — Code uses
< 9, < 72, < 137, < 201but Excel Freq_CPLD shows complex groupings like "1-4&65-68||5-8&69-72"
6. File Inventory
Source Files (Verilog)
| File | Location | Lines | Purpose |
|---|---|---|---|
RelayConTop.v |
CPLD1/ | 194 | Top module (CPLD1) |
RelayConTop.v |
CPLD2/ | 118 | Top module (CPLD2) |
RelayConTop.v |
CPLD3/ | 98 | Top module (CPLD3) |
BUS_Con.v |
CPLD1/ | 213 | SPI interface (shared) |
BUS_Con.v |
CPLD2/ | — | Same as CPLD1 |
BUS_Con.v |
CPLD3/ | — | Same as CPLD1 |
Reg_file.v |
CPLD1/ | 179 | Register file (shared) |
Reg_file.v |
CPLD2/ | — | Same as CPLD1 |
Reg_file.v |
CPLD3/ | — | Same as CPLD1 |
CPLD_Con.v |
CPLD1/ | 376 | Control logic (CPLD1 only) |
RelayConTop_tf.v |
CPLD1/ | 93 | Test fixture template |
Constraints (LPF)
| File | Location | Lines | Purpose |
|---|---|---|---|
NewExtIns_CPLD1.lpf |
CPLD1/ | 283 | Pin assignments (CPLD1) |
NewExtIns_CPLD2.lpf |
CPLD2/ | 322 | Pin assignments (CPLD2) |
NewExtIns_CPLD3.lpf |
CPLD3/ | 29 | Pin assignments (CPLD3) |
Programming Files
| File | Size | Date |
|---|---|---|
Release/NewExtIns_CPLD1.jed |
1.4 MB | Jan 19 |
Release/NewExtIns_CPLD2.jed |
1.4 MB | Jan 19 |
Release/NewExtIns_CPLD3.jed |
1.4 MB | Jan 19 |
Vivado Block Design
| File | Location | Purpose |
|---|---|---|
NewExtInst_TOP.v |
NewExtInst_Debug/.../sim/ | Top-level netlist |
SPI_Con_v1_0.v |
.../ipshared/8878/hdl/ | Custom SPI AXI IP |
processing_system7_v5_5.v |
.../ipshared/8fd3/ | Zynq PS IP |
7. Register Protocol Summary
Write Sequence (ARM → CPLD)
- ARM writes to AXI address via
M_AXI_GP0 SPI_ConIP converts to SPI transactionBUS_Conreceives 32-bit SPI frameReg_filestores data in register table- If bit 0 of STATE register set → triggers execution
Read Sequence (CPLD → ARM)
- ARM reads AXI address
SPI_Coninitiates SPI transactionBUS_Conshifts out 32-bit response:[8'h00][24-bit rdata]- Note:
o_rvalidis hardcoded to 0 — read acknowledgment not implemented
Execution Sequence
- ARM writes
STATEregister with bit 0 = 1 Reg_fileFSM → EXEC_ACK (waits forcon_doneLOW)CPLD_Condecodes register values, drives outputsCPLD_Consetscon_doneHIGH when completeReg_fileFSM → EXEC_WAIT (waits forcon_doneHIGH)- Auto-clears exec bit, returns to IDLE
8. Key Bit Fields Reference
IDENT Register (Addr 0)
23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
CPLD3 CPLD2 CPLD1 Reserved Major Version Minor Version Reversion
- CPLD3, CPLD2, CPLD1: Board identity flags (CPLD1=1 means the CPLD communicating to IDENTIFY itself as CPLD1)
- Major Version: 1
- Minor Version: 0
- Reversion: 0
Freq_Slot Register (Addr 2-5)
23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Per Relay_Control (1=Switch, 0=Not Switch) Channel_Number Slot_EN
- Bits 23:10: Per Relay_Control (14 bits, one per relay per slot)
- Bits 9:1: Channel_Number (9 bits)
- Bit 0: Slot_EN (1=Enable)
DC_Slot Register (Addr 6-9)
23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
DPS V/I Rload_Sel (0-31) Reserved Channel_Number Slot_EN
- Bit 23: DPS (0=PMU, 1=DPS)
- Bit 22: V/I (0=Voltage, 1=Current)
- Bits 21:17: Rload_Sel (0-31, 5-bit resistor selection)
- Bits 16:10: Reserved (7 bits)
- Bits 9:1: Channel_Number (9 bits)
- Bit 0: Slot_EN (1=Enable)
STATE Register (Addr 1)
23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
RDY Reserved EXEC
- Bit 23: RDY (ready flag)
- Bits 22:1: Reserved (22 bits)
- Bit 0: EXEC (1=start execution)
Document generated from source code analysis. Last updated: May 2026