diff --git a/eda/board.go b/eda/board.go new file mode 100644 index 0000000..8ece1f4 --- /dev/null +++ b/eda/board.go @@ -0,0 +1,1525 @@ +// Copyright 2021 The go-lpc Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package eda + +import ( + "bufio" + "encoding/binary" + "fmt" + "io" + "log" + "os" + "strconv" + "strings" + "time" + + "github.com/go-lpc/mim/eda/internal/regs" +) + +type board struct { + mem [szCfgHR]byte + sli []byte + regs pins + + msg *log.Logger + err error + xbuf [4]byte +} + +type pins struct { + pio struct { + state reg32 + ctrl reg32 + pulser reg32 + + chkSC [nRFM]reg32 + + cntHit0 [nRFM]reg32 + cntHit1 [nRFM]reg32 + cntTrig reg32 + cnt48MSB reg32 + cnt48LSB reg32 + cnt24 reg32 + } + ramSC [nRFM]hrCfg + + fifo struct { + daq [nRFM]reg32 + daqCSR [nRFM]daqFIFO + } +} + +func newBoard(msg *log.Logger) board { + var b board + b.msg = msg + b.sli = b.mem[4:] + return b +} + +func (brd *board) readU32(r io.ReaderAt, off int64) uint32 { + if brd.err != nil { + return 0 + } + _, brd.err = r.ReadAt(brd.xbuf[:4], off) + if brd.err != nil { + brd.err = fmt.Errorf("eda: could not read register 0x%x: %w", off, brd.err) + return 0 + } + return binary.LittleEndian.Uint32(brd.xbuf[:4]) +} + +func (brd *board) writeU32(w io.WriterAt, off int64, v uint32) { + if brd.err != nil { + return + } + binary.LittleEndian.PutUint32(brd.xbuf[:4], v) + _, brd.err = w.WriteAt(brd.xbuf[:4], off) + if brd.err != nil { + brd.err = fmt.Errorf("eda: could not write register 0x%x: %w", off, brd.err) + return + } +} + +func (brd *board) bindH2F(h2f rwer) error { + brd.regs.fifo.daq[0] = newReg32(brd, h2f, regs.H2F_FIFO_DAQ_RFM0) + brd.regs.fifo.daq[1] = newReg32(brd, h2f, regs.H2F_FIFO_DAQ_RFM1) + brd.regs.fifo.daq[2] = newReg32(brd, h2f, regs.H2F_FIFO_DAQ_RFM2) + brd.regs.fifo.daq[3] = newReg32(brd, h2f, regs.H2F_FIFO_DAQ_RFM3) + + brd.regs.fifo.daqCSR[0] = newDAQFIFO(brd, h2f, regs.H2F_FIFO_DAQ_CSR_RFM0) + brd.regs.fifo.daqCSR[1] = newDAQFIFO(brd, h2f, regs.H2F_FIFO_DAQ_CSR_RFM1) + brd.regs.fifo.daqCSR[2] = newDAQFIFO(brd, h2f, regs.H2F_FIFO_DAQ_CSR_RFM2) + brd.regs.fifo.daqCSR[3] = newDAQFIFO(brd, h2f, regs.H2F_FIFO_DAQ_CSR_RFM3) + return nil +} + +func (brd *board) bindLwH2F(lw rwer) error { + brd.regs.pio.state = newReg32(brd, lw, regs.LW_H2F_PIO_STATE_IN) + brd.regs.pio.ctrl = newReg32(brd, lw, regs.LW_H2F_PIO_CTRL_OUT) + brd.regs.pio.pulser = newReg32(brd, lw, regs.LW_H2F_PIO_PULSER) + + brd.regs.ramSC[0] = newHRCfg(lw, regs.LW_H2F_RAM_SC_RFM0) + brd.regs.ramSC[1] = newHRCfg(lw, regs.LW_H2F_RAM_SC_RFM1) + brd.regs.ramSC[2] = newHRCfg(lw, regs.LW_H2F_RAM_SC_RFM2) + brd.regs.ramSC[3] = newHRCfg(lw, regs.LW_H2F_RAM_SC_RFM3) + + brd.regs.pio.chkSC[0] = newReg32(brd, lw, regs.LW_H2F_PIO_SC_CHECK_RFM0) + brd.regs.pio.chkSC[1] = newReg32(brd, lw, regs.LW_H2F_PIO_SC_CHECK_RFM1) + brd.regs.pio.chkSC[2] = newReg32(brd, lw, regs.LW_H2F_PIO_SC_CHECK_RFM2) + brd.regs.pio.chkSC[3] = newReg32(brd, lw, regs.LW_H2F_PIO_SC_CHECK_RFM3) + + brd.regs.pio.cntHit0[0] = newReg32(brd, lw, regs.LW_H2F_PIO_CNT_HIT0_RFM0) + brd.regs.pio.cntHit0[1] = newReg32(brd, lw, regs.LW_H2F_PIO_CNT_HIT0_RFM1) + brd.regs.pio.cntHit0[2] = newReg32(brd, lw, regs.LW_H2F_PIO_CNT_HIT0_RFM2) + brd.regs.pio.cntHit0[3] = newReg32(brd, lw, regs.LW_H2F_PIO_CNT_HIT0_RFM3) + + brd.regs.pio.cntHit1[0] = newReg32(brd, lw, regs.LW_H2F_PIO_CNT_HIT1_RFM0) + brd.regs.pio.cntHit1[1] = newReg32(brd, lw, regs.LW_H2F_PIO_CNT_HIT1_RFM1) + brd.regs.pio.cntHit1[2] = newReg32(brd, lw, regs.LW_H2F_PIO_CNT_HIT1_RFM2) + brd.regs.pio.cntHit1[3] = newReg32(brd, lw, regs.LW_H2F_PIO_CNT_HIT1_RFM3) + + brd.regs.pio.cntTrig = newReg32(brd, lw, regs.LW_H2F_PIO_CNT_TRIG) + brd.regs.pio.cnt48MSB = newReg32(brd, lw, regs.LW_H2F_PIO_CNT48_MSB) + brd.regs.pio.cnt48LSB = newReg32(brd, lw, regs.LW_H2F_PIO_CNT48_LSB) + brd.regs.pio.cnt24 = newReg32(brd, lw, regs.LW_H2F_PIO_CNT24) + + return nil +} + +func (brd *board) rfmOn(rfm int) error { + var mask uint32 + switch rfm { + case 0: + mask = regs.O_ON_OFF_RFM0 + case 1: + mask = regs.O_ON_OFF_RFM1 + case 2: + mask = regs.O_ON_OFF_RFM2 + case 3: + mask = regs.O_ON_OFF_RFM3 + default: + panic(fmt.Errorf("eda: invalid RFM id=%d", rfm)) + } + ctrl := brd.regs.pio.ctrl.r() + ctrl |= mask + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not switch ON RFM=%d: %w", rfm, brd.err) + } + return nil +} + +// func (brd *board) rfmOff(rfm int) error { +// var mask uint32 +// switch rfm { +// case 0: +// mask = regs.O_ON_OFF_RFM0 +// case 1: +// mask = regs.O_ON_OFF_RFM1 +// case 2: +// mask = regs.O_ON_OFF_RFM2 +// case 3: +// mask = regs.O_ON_OFF_RFM3 +// default: +// panic(fmt.Errorf("eda: invalid RFM id=%d", rfm)) +// } +// ctrl := brd.regs.pio.ctrl.r() +// ctrl &= ^mask +// brd.regs.pio.ctrl.w(ctrl) +// +// if brd.err != nil { +// return fmt.Errorf("eda: could not switch OFF RFM=%d: %w", rfm, brd.err) +// } +// return nil +// } + +func (brd *board) rfmEnable(rfm int) error { + var mask uint32 + switch rfm { + case 0: + mask = regs.O_ENA_RFM0 + case 1: + mask = regs.O_ENA_RFM1 + case 2: + mask = regs.O_ENA_RFM2 + case 3: + mask = regs.O_ENA_RFM3 + default: + panic(fmt.Errorf("eda: invalid RFM id=%d", rfm)) + } + ctrl := brd.regs.pio.ctrl.r() + ctrl |= mask + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not enable RFM=%d: %w", rfm, brd.err) + } + return nil +} + +// func (brd *board) rfmDisable(rfm int) error { +// var mask uint32 +// switch rfm { +// case 0: +// mask = regs.O_ENA_RFM0 +// case 1: +// mask = regs.O_ENA_RFM1 +// case 2: +// mask = regs.O_ENA_RFM2 +// case 3: +// mask = regs.O_ENA_RFM3 +// default: +// panic(fmt.Errorf("eda: invalid RFM id=%d", rfm)) +// } +// ctrl := brd.regs.pio.ctrl.r() +// ctrl &= ^mask +// brd.regs.pio.ctrl.w(ctrl) +// +// if brd.err != nil { +// return fmt.Errorf("eda: could not disable RFM=%d: %w", rfm, brd.err) +// } +// return nil +// } + +func (brd *board) syncResetFPGA() error { + brd.regs.pio.ctrl.w(regs.O_RESET) + brd.msg.Printf("reset FPGA") + time.Sleep(1 * time.Microsecond) + brd.regs.pio.ctrl.w(0x00000000) + time.Sleep(1 * time.Microsecond) + + if brd.err != nil { + return fmt.Errorf("eda: could not reset FPGA: %w", brd.err) + } + return nil +} + +func (brd *board) syncResetHR() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl |= regs.O_RESET_HR + brd.regs.pio.ctrl.w(ctrl) + time.Sleep(1 * time.Microsecond) + + ctrl = brd.regs.pio.ctrl.r() + ctrl &= ^uint32(regs.O_RESET_HR) + brd.regs.pio.ctrl.w(ctrl) + time.Sleep(1 * time.Microsecond) + + if brd.err != nil { + return fmt.Errorf("eda: could not reset HR: %w", brd.err) + } + return nil +} + +func (brd *board) syncPLLLock() bool { + state := brd.regs.pio.state.r() + return state®s.O_PLL_LCK == regs.O_PLL_LCK +} + +func (brd *board) syncState() uint32 { + state := brd.regs.pio.state.r() + return (state >> regs.SHIFT_SYNCHRO_STATE) & 0xF +} + +func (brd *board) syncSelectCmdSoft() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl |= regs.O_SEL_CMD_SOURCE + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not synchronize cmd-soft: %w", brd.err) + } + return nil +} + +func (brd *board) syncSelectCmdDCC() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl &= ^uint32(regs.O_SEL_CMD_SOURCE) + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not synchronize cmd-dcc: %w", brd.err) + } + return nil +} + +func (brd *board) syncSetCmd(cmd uint32) error { + ctrl := brd.regs.pio.ctrl.r() + ctrl &= ^uint32(0xf << regs.SHIFT_CMD_CODE) // reset 4 bits + ctrl |= (0xf & cmd) << regs.SHIFT_CMD_CODE // set command + + brd.regs.pio.ctrl.w(ctrl) + time.Sleep(2 * time.Microsecond) + + ctrl &= ^uint32(0xf << regs.SHIFT_CMD_CODE) // reset 4 bits + ctrl |= regs.CMD_IDLE << regs.SHIFT_CMD_CODE // set idle command + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not set command 0x%x: %w", cmd, brd.err) + } + return nil +} + +func (brd *board) syncResetBCID() error { + return brd.syncSetCmd(regs.CMD_RESET_BCID) +} + +func (brd *board) syncStart() error { + return brd.syncSetCmd(regs.CMD_START_ACQ) +} + +func (brd *board) syncStop() error { + return brd.syncSetCmd(regs.CMD_STOP_ACQ) +} + +func (brd *board) syncRAMFullExt() error { + return brd.syncSetCmd(regs.CMD_RAMFULL_EXT) +} + +// func (brd *board) syncDigitalRO() error { +// return brd.syncSetCmd(regs.CMD_DIGITAL_RO) +// } + +func (brd *board) syncArmFIFO() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl |= regs.O_HPS_BUSY + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not arm FIFO: %w", brd.err) + } + return nil +} + +func (brd *board) syncAckFIFO() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl &= ^uint32(regs.O_HPS_BUSY) + brd.regs.pio.ctrl.w(ctrl) // falling edge on hps busy + for brd.syncState() != regs.S_IDLE { + // when FPGA ready for new acquisition + } + ctrl = brd.regs.pio.ctrl.r() + brd.regs.pio.ctrl.w(ctrl | regs.O_HPS_BUSY) // re-arming + + if brd.err != nil { + return fmt.Errorf("eda: could not ACK FIFO: %w", brd.err) + } + return nil +} + +func (brd *board) syncDCCCmdMem() uint32 { + cnt := brd.regs.pio.cnt24.r() + return (cnt >> regs.SHIFT_CMD_CODE_MEM) & 0xf +} + +// func (brd *board) syncDCCCmdNow() uint32 { +// cnt := brd.regs.pio.cnt24.r() +// return (cnt >> regs.SHIFT_CMD_CODE_NOW) & 0xf +// } +// +// func (brd *board) syncRAMFull() bool { +// state := brd.syncState() +// return state == regs.S_RAMFULL +// } +// +// func (brd *board) syncFPGARO() bool { +// state := brd.syncState() +// return state == regs.S_START_RO || state == regs.S_WAIT_END_RO +// } +// +// func (brd *board) syncFIFOReady() bool { +// state := brd.syncState() +// return state == regs.S_FIFO_READY +// } +// +// func (brd *board) syncRunStopped() bool { +// state := brd.syncState() +// return state == regs.S_STOP_RUN +// } + +// func (brd *board) syncHRTransmitOn(rfm int) bool { +// state := brd.regs.pio.state.r() +// switch rfm { +// case 0: +// return (state & regs.O_HR_TRANSMITON_0) == regs.O_HR_TRANSMITON_0 +// case 1: +// return (state & regs.O_HR_TRANSMITON_1) == regs.O_HR_TRANSMITON_1 +// case 2: +// return (state & regs.O_HR_TRANSMITON_2) == regs.O_HR_TRANSMITON_2 +// case 3: +// return (state & regs.O_HR_TRANSMITON_3) == regs.O_HR_TRANSMITON_3 +// } +// panic(fmt.Errorf("eda: invalid RFM id %d", rfm)) +// } +// +// func (brd *board) syncChipsAt(rfm int) bool { +// state := brd.regs.pio.state.r() +// switch rfm { +// case 0: +// return (state & regs.O_CHIPSAT_0) == regs.O_CHIPSAT_0 +// case 1: +// return (state & regs.O_CHIPSAT_1) == regs.O_CHIPSAT_1 +// case 2: +// return (state & regs.O_CHIPSAT_2) == regs.O_CHIPSAT_2 +// case 3: +// return (state & regs.O_CHIPSAT_3) == regs.O_CHIPSAT_3 +// } +// panic(fmt.Errorf("eda: invalid RFM id %d", rfm)) +// } +// +// func (brd *board) syncHREndRO(rfm int) bool { +// state := brd.regs.pio.state.r() +// switch rfm { +// case 0: +// return (state & regs.O_HR_END_RO_0) == regs.O_HR_END_RO_0 +// case 1: +// return (state & regs.O_HR_END_RO_1) == regs.O_HR_END_RO_1 +// case 2: +// return (state & regs.O_HR_END_RO_2) == regs.O_HR_END_RO_2 +// case 3: +// return (state & regs.O_HR_END_RO_3) == regs.O_HR_END_RO_3 +// } +// panic(fmt.Errorf("eda: invalid RFM id %d", rfm)) +// } + +func (brd *board) syncEnableDCCBusy() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl |= regs.O_ENA_DCC_BUSY + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not enable DCC-BUSY: %w", brd.err) + } + return nil +} + +func (brd *board) syncEnableDCCRAMFull() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl |= regs.O_ENA_DCC_RAMFULL + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not enable DCC-RAMFULL: %w", brd.err) + } + return nil +} + +// func (brd *board) trigSelectThreshold0() error { +// ctrl := brd.regs.pio.ctrl.r() +// ctrl &= ^uint32(regs.O_SEL_TRIG_THRESH) +// brd.regs.pio.ctrl.w(ctrl) +// +// if brd.err != nil { +// return fmt.Errorf("eda: could not select threshold-0: %w", brd.err) +// } +// return nil +// } +// +// func (brd *board) trigSelectThreshold1() error { +// ctrl := brd.regs.pio.ctrl.r() +// ctrl |= regs.O_SEL_TRIG_THRESH +// brd.regs.pio.ctrl.w(ctrl) +// +// if brd.err != nil { +// return fmt.Errorf("eda: could not select threshold-1: %w", brd.err) +// } +// return nil +// } +// +// func (brd *board) trigEnable() error { +// ctrl := brd.regs.pio.ctrl.r() +// ctrl |= regs.O_ENA_TRIG +// brd.regs.pio.ctrl.w(ctrl) +// +// if brd.err != nil { +// return fmt.Errorf("eda: could not enable trigger: %w", brd.err) +// } +// return nil +// } +// +// func (brd *board) trigDisable() error { +// ctrl := brd.regs.pio.ctrl.r() +// ctrl &= ^uint32(regs.O_ENA_TRIG) +// brd.regs.pio.ctrl.w(ctrl) +// +// if brd.err != nil { +// return fmt.Errorf("eda: could not disable trigger: %w", brd.err) +// } +// return nil +// } + +func (brd *board) cntReset() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl |= regs.O_RST_SCALERS + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not reset scalers: %w", brd.err) + } + + time.Sleep(1 * time.Microsecond) + + ctrl &= ^uint32(regs.O_RST_SCALERS) + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not clear scalers: %w", brd.err) + } + return nil +} + +func (brd *board) cntStart() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl |= regs.O_ENA_SCALERS + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not start scalers: %w", brd.err) + } + return nil +} + +func (brd *board) cntStop() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl &= ^uint32(regs.O_ENA_SCALERS) + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not stop scalers: %w", brd.err) + } + return nil +} + +func (brd *board) cntHit0(rfm int) uint32 { + return brd.regs.pio.cntHit0[rfm].r() +} + +func (brd *board) cntHit1(rfm int) uint32 { + return brd.regs.pio.cntHit1[rfm].r() +} + +func (brd *board) cntTrig() uint32 { + return brd.regs.pio.cntTrig.r() +} + +func (brd *board) cntBCID24() uint32 { + v := brd.regs.pio.cnt24.r() + return v & 0xffffff +} + +func (brd *board) cntBCID48MSB() uint32 { + v := brd.regs.pio.cnt48MSB.r() + return v & 0xffff +} + +func (brd *board) cntBCID48LSB() uint32 { + return brd.regs.pio.cnt48LSB.r() +} + +// func (brd *board) cntSave(w io.Writer, rfm int) error { +// var ( +// i = 0 +// buf = make([]byte, 7*4) +// dif = difIDOffset + ((brd.id & 7) << 3) + (uint32(rfm) & 3) +// u32 = (dif << 24) | (brd.daq.cycleID[rfm] & 0x00ffffff) +// ) +// +// binary.BigEndian.PutUint32(buf[i:], u32) +// i += 4 +// binary.BigEndian.PutUint32(buf[i:], brd.cntBCID48MSB()) +// i += 4 +// binary.BigEndian.PutUint32(buf[i:], brd.cntBCID48LSB()) +// i += 4 +// binary.BigEndian.PutUint32(buf[i:], brd.cntBCID24()) +// i += 4 +// binary.BigEndian.PutUint32(buf[i:], brd.cntHit0(rfm)) +// i += 4 +// binary.BigEndian.PutUint32(buf[i:], brd.cntHit1(rfm)) +// i += 4 +// binary.BigEndian.PutUint32(buf[i:], brd.cntTrig()) +// if brd.err != nil { +// return fmt.Errorf("eda: could not read counters: %w", brd.err) +// } +// +// n, err := w.Write(buf) +// if err != nil { +// return fmt.Errorf("eda: could not save counters: %w", err) +// } +// +// if n != len(buf) { +// return fmt.Errorf("eda: could not save counters: %w", io.ErrShortWrite) +// } +// return nil +// } + +// hardroc slow control + +func (brd *board) hrscSelectSlowControl() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl &= ^uint32(regs.O_SELECT_SC_RR) + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not select slow-control: %w", brd.err) + } + return nil +} + +func (brd *board) hrscSelectReadRegister() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl |= regs.O_SELECT_SC_RR + brd.regs.pio.ctrl.w(ctrl) + + if brd.err != nil { + return fmt.Errorf("eda: could not select read-register: %w", brd.err) + } + return nil +} + +func div(num, den uint32) (quo, rem uint32) { + quo = num / den + rem = num % den + return quo, rem +} + +func (brd *board) hrscSetBit(hr, addr, bit uint32) { + // byte address 0 corresponds to the last register (addr 864 to 871) + // of the last Hardroc (pos=nHR-1) + var ( + quo, rem = div(addr, nHR) + + i = (nHR-1-hr)*nBytesCfgHR + nBytesCfgHR - 1 - quo + v = brd.sli[i] + off = rem + + // bit address increases from LSB to MSB + mask1 = uint8(0x01 << off) + mask2 = uint8((0x1 & bit) << off) + ) + v &= ^mask1 // reset target bit + v |= mask2 // set target bit = "bit" argument + brd.sli[i] = v +} + +func (brd *board) hrscGetBit(hr, addr uint32) uint32 { + // byte address 0 corresponds to the last register (addr 864 to 871) + // of the last Hardroc (pos=nHR-1) + var ( + quo, rem = div(addr, nHR) + + i = (nHR-1-hr)*nBytesCfgHR + nBytesCfgHR - 1 - quo + v = brd.sli[i] + off = rem + ) + return uint32((v >> off) & 0x01) +} + +func (brd *board) hrscSetWord(hr, addr, nbits, v uint32) { + for i := uint32(0); i < nbits; i++ { + // scan LSB to MSB + bit := (v >> i) & 0x01 + brd.hrscSetBit(hr, addr+i, bit) + } +} + +func (brd *board) hrscSetWordMSB2LSB(hr, addr, nbits, v uint32) { + for i := uint32(0); i < nbits; i++ { + // scan MSB to LSB + bit := (v >> i) & 0x01 + brd.hrscSetBit(hr, addr+nbits-1-i, bit) + } +} + +func (brd *board) hrscReadConf(fname string, hr uint32) error { + f, err := os.Open(fname) + if err != nil { + return fmt.Errorf("eda: could not open config file %q: %w", fname, err) + } + defer f.Close() + + var ( + addr uint32 + bit uint32 + cnt = uint32(nBitsCfgHR - 1) + sc = bufio.NewScanner(f) + line int + ) + + for sc.Scan() { + line++ + txt := strings.TrimSpace(sc.Text()) + if strings.HasPrefix(txt, "#") { + continue + } + toks := strings.Split(txt, ";") + + if len(toks) != 5 { + return fmt.Errorf("eda: invalid config file:%d: line=%q", line, txt) + } + v, err := strconv.ParseUint(toks[0], 10, 32) + if err != nil { + return fmt.Errorf("eda: could not parse address %q in %q: %w", toks[0], txt, err) + } + addr = uint32(v) + + v, err = strconv.ParseUint(toks[4], 10, 32) + if err != nil { + return fmt.Errorf("eda: could not parse bit %q in %q: %w", toks[4], txt, err) + } + bit = uint32(v) + + if addr != cnt { + return fmt.Errorf( + "eda: invalid bit address line:%d: got=0x%x, want=0x%x", + line, addr, cnt, + ) + } + cnt-- + + brd.hrscSetBit(hr, addr, bit) + if addr == 0 { + return nil + } + } + err = sc.Err() + if err != nil && err != io.EOF { + return fmt.Errorf("eda: could not scan config file %q: %w", fname, err) + } + + return fmt.Errorf("eda: reached end of config file %q before last bit", fname) +} + +func (brd *board) hrscCopyConf(hrDst, hrSrc uint32) { + var ( + isrc = (nHR - 1 - hrSrc) * nBytesCfgHR + idst = (nHR - 1 - hrDst) * nBytesCfgHR + + dst = brd.sli[idst : idst+nBytesCfgHR] + src = brd.sli[isrc : isrc+nBytesCfgHR] + ) + copy(dst, src) +} + +func (brd *board) hrscReadConfHRs(fname string) error { + f, err := os.Open(fname) + if err != nil { + return fmt.Errorf("eda: could not open hr-sc %q: %w", fname, err) + } + defer f.Close() + + var ( + hr uint32 + addr uint32 + bit uint32 + cntBit = int64(nBitsCfgHR - 1) + cntHR = int64(nHR - 1) + sc = bufio.NewScanner(f) + line int + ) + + for sc.Scan() && cntBit >= 0 && cntHR >= 0 { + line++ + txt := strings.TrimSpace(sc.Text()) + if strings.HasPrefix(txt, "#") { + continue + } + toks := strings.Split(txt, ";") + if len(toks) != 3 { + return fmt.Errorf("eda: invalid HR config file:%d: line=%q", line, txt) + } + v, err := strconv.ParseUint(toks[0], 10, 32) + if err != nil { + return fmt.Errorf( + "eda: could not parse HR address %q in %q: %w", + toks[0], txt, err, + ) + } + hr = uint32(v) + + v, err = strconv.ParseUint(toks[1], 10, 32) + if err != nil { + return fmt.Errorf( + "eda: could not parse bit address %q in %q: %w", + toks[1], txt, err, + ) + } + addr = uint32(v) + + v, err = strconv.ParseUint(toks[2], 10, 32) + if err != nil { + return fmt.Errorf( + "eda: could not parse bit value %q in %q: %w", + toks[2], txt, err, + ) + } + bit = uint32(v) + + if int64(addr) != cntBit { + return fmt.Errorf( + "eda: invalid bit address line:%d: got=%d, want=%d", + line, addr, cntBit, + ) + } + + if int64(hr) != cntHR { + return fmt.Errorf( + "eda: invalid HR address line:%d: got=%d, want=%d", + line, hr, cntHR, + ) + } + + cntBit-- + if cntBit < 0 { + cntBit = nBitsCfgHR - 1 + cntHR-- + } + + brd.hrscSetBit(hr, addr, bit) + if addr == 0 && hr == 0 { + return nil + } + } + + err = sc.Err() + if err != nil && err != io.EOF { + return fmt.Errorf("eda: could not scan config file %q: %w", fname, err) + } + + return fmt.Errorf("eda: reached end of config file %q before last bit", fname) +} + +func (brd *board) hrscWriteConfHRs(fname string) error { + f, err := os.Create(fname) + if err != nil { + return fmt.Errorf("eda: could not create hr-sc file %q: %w", fname, err) + } + defer f.Close() + + w := bufio.NewWriter(f) + for i := 0; i < nHR; i++ { + for j := 0; j < nBitsCfgHR; j++ { + var ( + hr = uint32(nHR - 1 - i) + addr = uint32(nBitsCfgHR - 1 - j) + v = brd.hrscGetBit(hr, addr) + ) + fmt.Fprintf(w, "%d;%d;%d\n", hr, addr, v) + } + } + + err = w.Flush() + if err != nil { + return fmt.Errorf("eda: could not flush hr-sc file %q: %w", fname, err) + } + + err = f.Close() + if err != nil { + return fmt.Errorf("eda: could not close hr-sc file %q: %w", fname, err) + } + return nil +} + +// // hrscSetCtest switches the test capacitor (1=closed). +// func (brd *board) hrscSetCtest(hr, ch, v uint32) { +// brd.hrscSetBit(hr, ch, v&0x01) +// } +// +// func (brd *board) hrscSetAllCtestOff() { +// for hr := uint32(0); hr < nHR; hr++ { +// for ch := uint32(0); ch < nChans; ch++ { +// brd.hrscSetCtest(hr, ch, 0) +// } +// } +// } + +func (brd *board) hrscSetPreAmp(hr, ch, v uint32) { + addr := nChans + nHR*ch + brd.hrscSetWord(hr, addr, 8, v) +} + +// func (brd *board) hrscSetCmdFSB2(hr, ch, v uint32) { +// // fast shaper 2 gain +// addr := 587 + 4*ch +// brd.hrscSetWordMSB2LSB(hr, addr, 4, ^v) // "cmdb" register bits are active-low +// } +// +// func (brd *board) hrscSetCmdFSB1(hr, ch, v uint32) { +// // fast shaper 2 gain +// addr := 595 + 4*ch +// brd.hrscSetWordMSB2LSB(hr, addr, 4, ^v) // "cmdb" register bits are active-low +// } + +func (brd *board) hrscSetMask(hr, ch, v uint32) { + addr := 618 + 3*ch + brd.hrscSetWord(hr, addr, 3, v) +} + +func (brd *board) hrscSetChipID(hr, v uint32) { + brd.hrscSetWordMSB2LSB(hr, 810, 8, v) +} + +func (brd *board) hrscSetDAC0(hr, v uint32) { + brd.hrscSetWord(hr, 818, 10, v) +} + +func (brd *board) hrscSetDAC1(hr, v uint32) { + brd.hrscSetWord(hr, 828, 10, v) +} + +func (brd *board) hrscSetDAC2(hr, v uint32) { + brd.hrscSetWord(hr, 838, 10, v) +} + +// func (brd *board) hrscSetDACCoarse(hr uint32) { +// brd.hrscSetWord(hr, 848, 10, 0) +// } +// +// func (brd *board) hrscSetDACFine(hr uint32) { +// brd.hrscSetWord(hr, 848, 10, 1) +// } + +func (brd *board) hrscSetCShaper(hr, v uint32) { + brd.hrscSetBit(hr, 611, v&1) // sw_50f0 = b0 + brd.hrscSetBit(hr, 602, v&1) // sw_50f1 = b0 + brd.hrscSetBit(hr, 594, v&1) // sw_50f2 = b0 + brd.hrscSetBit(hr, 610, (v>>1)&1) // sw_100f0 = b1 + brd.hrscSetBit(hr, 601, (v>>1)&1) // sw_100f1 = b1 + brd.hrscSetBit(hr, 593, (v>>1)&1) // sw_100f2 = b1 +} + +func (brd *board) hrscSetRShaper(hr, v uint32) { + brd.hrscSetBit(hr, 609, v&1) // sw_100k0 = b0 + brd.hrscSetBit(hr, 600, v&1) // sw_100k1 = b0 + brd.hrscSetBit(hr, 592, v&1) // sw_100k2 = b0 + brd.hrscSetBit(hr, 608, (v>>1)&1) // sw_50k0 = b1 + brd.hrscSetBit(hr, 599, (v>>1)&1) // sw_50k1 = b1 + brd.hrscSetBit(hr, 591, (v>>1)&1) // sw_50k2 = b1 +} + +func (brd *board) hrscSetConfig(rfm int) error { + ctrl := brd.regs.pio.chkSC[rfm].r() + if brd.err != nil { + return fmt.Errorf( + "eda: could not read check-sc register (rfm=%d): %w", + rfm, brd.err, + ) + } + + switch ctrl { + case 0xcafefade: + ctrl = 0x36baffe5 + default: + ctrl = 0xcafefade + } + brd.mem[0] = byte((ctrl >> 24) & 0xff) + brd.mem[1] = byte((ctrl >> 16) & 0xff) + brd.mem[2] = byte((ctrl >> 8) & 0xff) + brd.mem[3] = byte(ctrl & 0xff) + + // reset sc + err := brd.hrscSelectSlowControl() + if err != nil { + return fmt.Errorf("eda: could not select slow-control (rfm=%d): %w", + rfm, err, + ) + } + + err = brd.hrscResetSC() + if err != nil { + return fmt.Errorf("eda: could not reset slow-control (rfm=%d): %w", + rfm, err, + ) + } + + if brd.hrscSCDone(rfm) { + return fmt.Errorf("eda: could not reset slow control (rfm=%d): sc-not-done", rfm) + } + + // copy to FPGA + _, err = brd.regs.ramSC[rfm].w(brd.mem[:szCfgHR]) + if err != nil { + return fmt.Errorf( + "eda: could not write slow-control cfg to FPGA (rfm=%d): %w", + rfm, err, + ) + } + + // trigger the slow control serializer + err = brd.hrscStartSC(rfm) + if err != nil { + return fmt.Errorf( + "eda: could not start slow-control serializer (rfm=%d): %w", + rfm, err, + ) + } + + // check loop-back header + time.Sleep(10 * time.Microsecond) + for !brd.hrscSCDone(rfm) { + time.Sleep(10 * time.Microsecond) + } + + chk := brd.regs.pio.chkSC[rfm].r() + if brd.err != nil { + return fmt.Errorf( + "eda: could not read slow-control loopback register (rfm=%d): %w", + rfm, brd.err, + ) + } + + if chk != ctrl { + return fmt.Errorf( + "eda: invalid loopback register (rfm=%d): got=0x%x, want=0x%x", + rfm, chk, ctrl, + ) + } + + return nil +} + +func (brd *board) hrscResetReadRegisters(rfm int) error { + ctrl := brd.regs.pio.chkSC[rfm].r() + if brd.err != nil { + return fmt.Errorf( + "eda: could not read check-sc register (rfm=%d): %w", + rfm, brd.err, + ) + } + + switch ctrl { + case 0xcafefade: + ctrl = 0x36baffe5 + default: + ctrl = 0xcafefade + } + var ( + buf [szCfgHR]byte + off = nHR*nBytesCfgHR - nChans + ) + buf[off+0] = byte((ctrl >> 24) & 0xff) + buf[off+1] = byte((ctrl >> 16) & 0xff) + buf[off+2] = byte((ctrl >> 8) & 0xff) + buf[off+3] = byte(ctrl & 0xff) + + // reset sc + err := brd.hrscSelectReadRegister() + if err != nil { + return fmt.Errorf( + "eda: could select read-register (rfm=%d): %w", + rfm, err, + ) + } + + err = brd.hrscResetSC() + if err != nil { + return fmt.Errorf("eda: could not reset slow-control (rfm=%d): %w", + rfm, err, + ) + } + + if brd.hrscSCDone(rfm) { + return fmt.Errorf("eda: could not reset slow control (rfm=%d)", rfm) + } + + // copy to FPGA + _, err = brd.regs.ramSC[rfm].w(buf[:szCfgHR]) + if err != nil { + return fmt.Errorf( + "eda: could not write slow-control cfg to FPGA (rfm=%d): %w", + rfm, err, + ) + } + + // trigger the slow control serializer + time.Sleep(10 * time.Microsecond) + err = brd.hrscStartSC(rfm) + if err != nil { + return fmt.Errorf( + "eda: could not start slow-control serializer (rfm=%d): %w", + rfm, err, + ) + } + + // check loop-back header + time.Sleep(10 * time.Microsecond) + for !brd.hrscSCDone(rfm) { + time.Sleep(10 * time.Microsecond) + } + + chk := brd.regs.pio.chkSC[rfm].r() + if brd.err != nil { + return fmt.Errorf( + "eda: could not read slow-control loopback register (rfm=%d): %w", + rfm, brd.err, + ) + } + + if chk != ctrl { + return fmt.Errorf( + "eda: invalid loopback register (rfm=%d): got=0x%x, want=0x%x", + rfm, chk, ctrl, + ) + } + + err = brd.hrscSelectSlowControl() + if err != nil { + return fmt.Errorf( + "eda: could not select slow-control (rfm=%d): %w", + rfm, err, + ) + } + + return nil +} + +// func (brd *board) hrscSetReadRegister(rfm, ch int) error { +// ctrl := brd.regs.pio.chkSC[rfm].r() +// if brd.err != nil { +// return fmt.Errorf( +// "eda: could not read check-sc register (rfm=%d): %w", +// rfm, brd.err, +// ) +// } +// +// switch ctrl { +// case 0xcafefade: +// ctrl = 0x36baffe5 +// default: +// ctrl = 0xcafefade +// } +// var ( +// buf [szCfgHR]byte +// off = nHR*nBytesCfgHR - nChans +// ) +// buf[off+0] = byte((ctrl >> 24) & 0xff) +// buf[off+1] = byte((ctrl >> 16) & 0xff) +// buf[off+2] = byte((ctrl >> 8) & 0xff) +// buf[off+3] = byte(ctrl & 0xff) +// +// // reset sc +// err := brd.hrscSelectReadRegister() +// if err != nil { +// return fmt.Errorf( +// "eda: could select read-register (rfm=%d): %w", +// rfm, err, +// ) +// } +// +// err = brd.hrscResetSC() +// if err != nil { +// return fmt.Errorf("eda: could not reset slow-control (rfm=%d): %w", +// rfm, err, +// ) +// } +// +// if !brd.hrscSCDone(rfm) { +// return fmt.Errorf("eda: could not reset slow control (rfm=%d)", rfm) +// } +// +// // select the same channel for all HR's +// var ( +// quo, rem = div(uint32(ch), nHR) // channels: 0->64*nHR-1 +// v = byte(0x1 << rem) +// ) +// for i := 0; i < nHR; i++ { +// off := nHR*nBytesCfgHR + 3 - i*nHR - int(quo) // last byte -> channels [0,8) +// buf[off] = v +// } +// +// // copy to FPGA +// _, err = brd.regs.ramSC[rfm].w(buf[:szCfgHR]) +// if err != nil { +// return fmt.Errorf( +// "eda: could not write slow-control cfg to FPGA (rfm=%d): %w", +// rfm, err, +// ) +// } +// +// // trigger the slow control serializer +// err = brd.hrscStartSC(rfm) +// if err != nil { +// return fmt.Errorf( +// "eda: could not start slow-control serializer (rfm=%d): %w", +// rfm, err, +// ) +// } +// +// // check loop-back header +// time.Sleep(10 * time.Microsecond) +// for !brd.hrscSCDone(rfm) { +// time.Sleep(10 * time.Microsecond) +// } +// +// chk := brd.regs.pio.chkSC[rfm].r() +// if brd.err != nil { +// return fmt.Errorf( +// "eda: could not read slow-control loopback register (rfm=%d): %w", +// rfm, brd.err, +// ) +// } +// +// if chk != ctrl { +// return fmt.Errorf( +// "eda: invalid loopback register (rfm=%d): got=0x%x, want=0x%x", +// rfm, chk, ctrl, +// ) +// } +// +// err = brd.hrscSelectSlowControl() +// if err != nil { +// return fmt.Errorf( +// "eda: could not select slow-control (rfm=%d): %w", +// rfm, err, +// ) +// } +// +// return nil +// } + +func (brd *board) hrscResetSC() error { + ctrl := brd.regs.pio.ctrl.r() + ctrl |= regs.O_RESET_SC + brd.regs.pio.ctrl.w(ctrl) + if brd.err != nil { + return fmt.Errorf("eda: could not reset slow-control: %w", brd.err) + } + + time.Sleep(1 * time.Microsecond) + + ctrl = brd.regs.pio.ctrl.r() + ctrl &= ^uint32(regs.O_RESET_SC) + brd.regs.pio.ctrl.w(ctrl) + if brd.err != nil { + return fmt.Errorf("eda: could not reset slow-control: %w", brd.err) + } + + time.Sleep(1 * time.Microsecond) + + return nil +} + +func (brd *board) hrscStartSC(rfm int) error { + var ( + mask uint32 + ) + + switch rfm { + case 0: + mask = regs.O_START_SC_0 + case 1: + mask = regs.O_START_SC_1 + case 2: + mask = regs.O_START_SC_2 + case 3: + mask = regs.O_START_SC_3 + default: + return fmt.Errorf("eda: start slow-control: invalid RFM id %d", rfm) + } + + ctrl := brd.regs.pio.ctrl.r() + ctrl |= mask + brd.regs.pio.ctrl.w(ctrl) + if brd.err != nil { + return fmt.Errorf( + "eda: could read/write pio ctrl mask=0x%x: %w", + mask, + brd.err, + ) + } + + time.Sleep(1 * time.Microsecond) + + ctrl = brd.regs.pio.ctrl.r() + ctrl &= ^mask + brd.regs.pio.ctrl.w(ctrl) + if brd.err != nil { + return fmt.Errorf( + "eda: could read/write pio ctrl ^mask=0x%x: %w", + mask, + brd.err, + ) + } + + return nil +} + +func (brd *board) hrscSCDone(rfm int) bool { + var mask uint32 + switch rfm { + case 0: + mask = regs.O_SC_DONE_0 + case 1: + mask = regs.O_SC_DONE_1 + case 2: + mask = regs.O_SC_DONE_2 + case 3: + mask = regs.O_SC_DONE_3 + default: + panic(fmt.Errorf("eda: invalid RFM ID=%d", rfm)) + } + + return (brd.regs.pio.state.r() & mask) == mask +} + +func bit32(word, digit uint32) uint32 { + return (word >> digit) & 0x1 +} + +func bitU64(v uint64, pos uint32) uint8 { + o := v & uint64(1<> 16)) +// wU16(uint16(bcid24 & 0xffff)) +// // unused "nb-lines" +// wU8(0xff) +// +// // HR DAQ chunk +// var ( +// lastHR = -1 +// hrID int +// ) +// for !brd.daqFIFOEmpty(rfm) { +// // read HR ID +// id := brd.regs.fifo.daq[rfm].r() +// hrID = int(id >> 24) +// // insert trailer and header if new hardroc ID +// if hrID != lastHR { +// if lastHR >= 0 { +// wU8(0xA3) // HR trailer +// } +// wU8(0xB4) // HR header +// } +// wU32(id) +// for i := 0; i < 4; i++ { +// wU32(brd.regs.fifo.daq[rfm].r()) +// n++ +// } +// lastHR = hrID +// } +// wU8(0xA3) // last HR trailer +// wU8(0xA0) // DIF DAQ trailer +// wU16(0xC0C0) // fake CRC +// +// // on-line monitoring +// nRAMUnits := n / 5 +// +// brd.daq.cycleID[rfm]++ +// return nRAMUnits +// } diff --git a/eda/cfg.go b/eda/cfg.go index 64f0c4d..63805c9 100644 --- a/eda/cfg.go +++ b/eda/cfg.go @@ -87,9 +87,6 @@ type config struct { cshaper uint32 // capacity shaper db dbConfig // configuration from tmv-db - - buf [szCfgHR]byte - data []byte } daq struct { @@ -126,7 +123,6 @@ func newConfig() config { cfg.hr.db = newDbConfig() cfg.hr.cshaper = 3 cfg.daq.mode = "dcc" - cfg.hr.data = cfg.hr.buf[4:] return cfg } @@ -161,7 +157,7 @@ func (dev *Device) configASICs(dif uint8) error { n = len(cfg) ) for i, v := range cfg { - dev.hrscSetBit(ihr, uint32(n-1-i), uint32(v)) + dev.brd.hrscSetBit(ihr, uint32(n-1-i), uint32(v)) } } return nil diff --git a/eda/cfg_test.go b/eda/cfg_test.go index e1b8386..35f03b1 100644 --- a/eda/cfg_test.go +++ b/eda/cfg_test.go @@ -68,8 +68,8 @@ func TestCompareConfig(t *testing.T) { for i := range asics { var ( ihr = (nHR - 1 - i) * nBytesCfgHR - buf1 = devDB.cfg.hr.data[ihr : ihr+nBytesCfgHR] - buf2 = devCSV.cfg.hr.data[ihr : ihr+nBytesCfgHR] + buf1 = devDB.brd.sli[ihr : ihr+nBytesCfgHR] + buf2 = devCSV.brd.sli[ihr : ihr+nBytesCfgHR] ) if !bytes.Equal(buf1, buf2) { t.Errorf("asic-%d: hr-data NOT OK", i) @@ -83,9 +83,9 @@ func TestCompareConfig(t *testing.T) { func testCfgWithDB(dev *Device, asics []conddb.ASIC, rshaper uint32, rfms []int) error { WithRShaper(rshaper)(&dev.cfg) dev.cfg.hr.cshaper = 3 - dev.cfg.hr.data = dev.cfg.hr.buf[4:] dev.cfg.hr.db = newDbConfig() dev.rfms = rfms + dev.brd = newBoard(dev.msg) { rfmID := asics[0].DIFID @@ -95,22 +95,22 @@ func testCfgWithDB(dev *Device, asics []conddb.ASIC, rshaper uint32, rfms []int) return fmt.Errorf("could not configure ASICs for rfm=%d: %w", rfmID, err) } } - dev.hrscSetBit(0, 854, 0) + dev.brd.hrscSetBit(0, 854, 0) - dev.hrscSetRShaper(0, dev.cfg.hr.rshaper) - dev.hrscSetCShaper(0, dev.cfg.hr.cshaper) + dev.brd.hrscSetRShaper(0, dev.cfg.hr.rshaper) + dev.brd.hrscSetCShaper(0, dev.cfg.hr.cshaper) - dev.hrscCopyConf(1, 0) - dev.hrscCopyConf(2, 0) - dev.hrscCopyConf(3, 0) - dev.hrscCopyConf(4, 0) - dev.hrscCopyConf(5, 0) - dev.hrscCopyConf(6, 0) - dev.hrscCopyConf(7, 0) + dev.brd.hrscCopyConf(1, 0) + dev.brd.hrscCopyConf(2, 0) + dev.brd.hrscCopyConf(3, 0) + dev.brd.hrscCopyConf(4, 0) + dev.brd.hrscCopyConf(5, 0) + dev.brd.hrscCopyConf(6, 0) + dev.brd.hrscCopyConf(7, 0) // set chip IDs for hr := uint32(0); hr < nHR; hr++ { - dev.hrscSetChipID(hr, hr+1) + dev.brd.hrscSetChipID(hr, hr+1) } for i := range dev.rfms { @@ -122,12 +122,12 @@ func testCfgWithDB(dev *Device, asics []conddb.ASIC, rshaper uint32, rfms []int) m2 := bitU64(asics[hr].Mask2, ch) mask := uint32(m0 | m1<<1 | m2<<2) - dev.hrscSetMask(hr, ch, mask) + dev.brd.hrscSetMask(hr, ch, mask) } - dev.hrscSetDAC0(hr, uint32(asics[hr].B0)) - dev.hrscSetDAC1(hr, uint32(asics[hr].B1)) - dev.hrscSetDAC2(hr, uint32(asics[hr].B2)) + dev.brd.hrscSetDAC0(hr, uint32(asics[hr].B0)) + dev.brd.hrscSetDAC1(hr, uint32(asics[hr].B1)) + dev.brd.hrscSetDAC2(hr, uint32(asics[hr].B2)) for ch := uint32(0); ch < nChans; ch++ { v, err := strconv.ParseUint(string(asics[hr].PreAmpGain[2*ch:2*ch+2]), 16, 8) @@ -136,7 +136,7 @@ func testCfgWithDB(dev *Device, asics []conddb.ASIC, rshaper uint32, rfms []int) } gain := uint32(v) dev.cfg.preamp.gains[nChans*(nHR*rfm+hr)+ch] = gain - dev.hrscSetPreAmp(hr, ch, gain) + dev.brd.hrscSetPreAmp(hr, ch, gain) } } } @@ -149,10 +149,10 @@ func testCfgWithCSV(dev *Device, thresh, rshaper uint32, rfms []int) error { WithRShaper(rshaper)(&dev.cfg) dev.cfg.hr.db = newDbConfig() dev.cfg.hr.cshaper = 3 - dev.cfg.hr.data = dev.cfg.hr.buf[4:] dev.rfms = rfms + dev.brd = newBoard(dev.msg) - err := dev.hrscReadConf(dev.cfg.hr.fname, 0) + err := dev.brd.hrscReadConf(dev.cfg.hr.fname, 0) if err != nil { return fmt.Errorf("eda: could load single-HR configuration file: %w", err) } @@ -173,22 +173,22 @@ func testCfgWithCSV(dev *Device, thresh, rshaper uint32, rfms []int) error { } // disable trig_out output pin (RFM v1 coupling problem) - dev.hrscSetBit(0, 854, 0) + dev.brd.hrscSetBit(0, 854, 0) - dev.hrscSetRShaper(0, dev.cfg.hr.rshaper) - dev.hrscSetCShaper(0, dev.cfg.hr.cshaper) + dev.brd.hrscSetRShaper(0, dev.cfg.hr.rshaper) + dev.brd.hrscSetCShaper(0, dev.cfg.hr.cshaper) - dev.hrscCopyConf(1, 0) - dev.hrscCopyConf(2, 0) - dev.hrscCopyConf(3, 0) - dev.hrscCopyConf(4, 0) - dev.hrscCopyConf(5, 0) - dev.hrscCopyConf(6, 0) - dev.hrscCopyConf(7, 0) + dev.brd.hrscCopyConf(1, 0) + dev.brd.hrscCopyConf(2, 0) + dev.brd.hrscCopyConf(3, 0) + dev.brd.hrscCopyConf(4, 0) + dev.brd.hrscCopyConf(5, 0) + dev.brd.hrscCopyConf(6, 0) + dev.brd.hrscCopyConf(7, 0) // set chip IDs for hr := uint32(0); hr < nHR; hr++ { - dev.hrscSetChipID(hr, hr+1) + dev.brd.hrscSetChipID(hr, hr+1) } // for each active RFM, tune the configuration and send it. @@ -197,7 +197,7 @@ func testCfgWithCSV(dev *Device, thresh, rshaper uint32, rfms []int) error { for hr := uint32(0); hr < nHR; hr++ { for ch := uint32(0); ch < nChans; ch++ { mask := dev.cfg.mask.table[nChans*(nHR*uint32(rfm)+hr)+ch] - dev.hrscSetMask(hr, ch, mask) + dev.brd.hrscSetMask(hr, ch, mask) } } @@ -210,15 +210,15 @@ func testCfgWithCSV(dev *Device, thresh, rshaper uint32, rfms []int) error { th0 := dev.cfg.daq.floor[3*(nHR*uint32(rfm)+hr)+0] th1 := dev.cfg.daq.floor[3*(nHR*uint32(rfm)+hr)+1] th2 := dev.cfg.daq.floor[3*(nHR*uint32(rfm)+hr)+2] - dev.hrscSetDAC0(hr, th0) - dev.hrscSetDAC1(hr, th1) - dev.hrscSetDAC2(hr, th2) + dev.brd.hrscSetDAC0(hr, th0) + dev.brd.hrscSetDAC1(hr, th1) + dev.brd.hrscSetDAC2(hr, th2) } for hr := uint32(0); hr < nHR; hr++ { for ch := uint32(0); ch < nChans; ch++ { gain := dev.cfg.preamp.gains[nChans*hr+ch] - dev.hrscSetPreAmp(hr, ch, gain) + dev.brd.hrscSetPreAmp(hr, ch, gain) } } diff --git a/eda/device.go b/eda/device.go index 7f7b43f..1de2737 100644 --- a/eda/device.go +++ b/eda/device.go @@ -66,31 +66,8 @@ type Device struct { dir string - err error - buf []byte - regs struct { - pio struct { - state reg32 - ctrl reg32 - pulser reg32 - - chkSC [nRFM]reg32 - - cntHit0 [nRFM]reg32 - cntHit1 [nRFM]reg32 - cntTrig reg32 - cnt48MSB reg32 - cnt48LSB reg32 - cnt24 reg32 - } - ramSC [nRFM]hrCfg - - fifo struct { - daq [nRFM]reg32 - daqCSR [nRFM]daqFIFO - } - } - + err error + brd board cfg config daq struct { @@ -125,11 +102,12 @@ func newDevice(devmem, odir, devshm string, opts ...Option) (*Device, error) { } }() + msg := log.New(os.Stdout, "eda: ", 0) dev := &Device{ - msg: log.New(os.Stdout, "eda: ", 0), + msg: msg, dir: odir, - buf: make([]byte, 4), cfg: newConfig(), + brd: newBoard(msg), } dev.mem.fd = mem @@ -185,11 +163,12 @@ func NewDevice(fname string, odir string, opts ...Option) (*Device, error) { } }() + msg := log.New(os.Stdout, "eda: ", 0) dev := &Device{ - msg: log.New(os.Stdout, "eda: ", 0), + msg: msg, dir: odir, - buf: make([]byte, 4), cfg: newConfig(), + brd: newBoard(msg), } dev.mem.fd = mem WithResetBCID(10 * time.Second)(&dev.cfg) @@ -278,7 +257,7 @@ func (dev *Device) Configure() error { } func (dev *Device) configureFromCSV() error { - err := dev.hrscReadConf(dev.cfg.hr.fname, 0) + err := dev.brd.hrscReadConf(dev.cfg.hr.fname, 0) if err != nil { return fmt.Errorf("eda: could load single-HR configuration file: %w", err) } @@ -328,14 +307,14 @@ func (dev *Device) Initialize() error { func (dev *Device) initFPGA() error { // reset FPGA and set clock. - err := dev.syncResetFPGA() + err := dev.brd.syncResetFPGA() if err != nil { return fmt.Errorf("eda: could not reset FPGA: %w", err) } time.Sleep(2 * time.Microsecond) cnt := 0 max := 100 - for !dev.syncPLLLock() && cnt < max { + for !dev.brd.syncPLLLock() && cnt < max { time.Sleep(10 * time.Millisecond) cnt++ } @@ -343,22 +322,22 @@ func (dev *Device) initFPGA() error { return fmt.Errorf("eda: could not lock PLL") } - dev.msg.Printf("pll lock=%v\n", dev.syncPLLLock()) + dev.msg.Printf("pll lock=%v\n", dev.brd.syncPLLLock()) // activate RFMs for _, rfm := range dev.rfms { - err = dev.rfmOn(rfm) + err = dev.brd.rfmOn(rfm) if err != nil { return fmt.Errorf("eda: could not activate RFM=%d: %w", rfm, err) } - err = dev.rfmEnable(rfm) + err = dev.brd.rfmEnable(rfm) if err != nil { return fmt.Errorf("eda: could not enable RFM=%d: %w", rfm, err) } } time.Sleep(1 * time.Millisecond) - ctrl := dev.regs.pio.ctrl.r() + ctrl := dev.brd.regs.pio.ctrl.r() if dev.err != nil { return fmt.Errorf("eda: could not read control pio: %w", dev.err) } @@ -367,20 +346,20 @@ func (dev *Device) initFPGA() error { dev.msg.Printf("trigger mode: %v", dev.cfg.daq.mode) switch dev.cfg.daq.mode { case "dcc": - err = dev.syncSelectCmdDCC() + err = dev.brd.syncSelectCmdDCC() if err != nil { return fmt.Errorf("eda: could not select DCC cmd: %w", err) } - err = dev.syncEnableDCCBusy() + err = dev.brd.syncEnableDCCBusy() if err != nil { return fmt.Errorf("eda: could not enable DCC busy: %w", err) } - err = dev.syncEnableDCCRAMFull() + err = dev.brd.syncEnableDCCRAMFull() if err != nil { return fmt.Errorf("eda: could not enable DCC RAM-full: %w", err) } case "noise": - err = dev.syncSelectCmdSoft() + err = dev.brd.syncSelectCmdSoft() if err != nil { return fmt.Errorf("eda: could not select SOFT cmd: %w", err) } @@ -401,14 +380,14 @@ func (dev *Device) initHR() error { func (dev *Device) initHRFromDB() error { // disable trig_out output pin (RFM v1 coupling problem) - dev.hrscSetBit(0, 854, 0) + dev.brd.hrscSetBit(0, 854, 0) - dev.hrscSetRShaper(0, dev.cfg.hr.rshaper) - dev.hrscSetCShaper(0, dev.cfg.hr.cshaper) + dev.brd.hrscSetRShaper(0, dev.cfg.hr.rshaper) + dev.brd.hrscSetCShaper(0, dev.cfg.hr.cshaper) // set chip IDs for hr := uint32(0); hr < nHR; hr++ { - dev.hrscSetChipID(hr, hr+1) + dev.brd.hrscSetChipID(hr, hr+1) } // for each active RFM, tune the configuration and send it. @@ -427,7 +406,7 @@ func (dev *Device) initHRFromDB() error { if verbose { dev.msg.Printf("%d %d %d\n", hr, ch, mask) } - dev.hrscSetMask(hr, ch, mask) + dev.brd.hrscSetMask(hr, ch, mask) } } @@ -443,9 +422,9 @@ func (dev *Device) initHRFromDB() error { if verbose { dev.msg.Printf("%d %d %d %d\n", hr, th0, th1, th2) } - dev.hrscSetDAC0(hr, th0) - dev.hrscSetDAC1(hr, th1) - dev.hrscSetDAC2(hr, th2) + dev.brd.hrscSetDAC0(hr, th0) + dev.brd.hrscSetDAC1(hr, th1) + dev.brd.hrscSetDAC2(hr, th2) } // set preamplifier gain @@ -462,12 +441,12 @@ func (dev *Device) initHRFromDB() error { if verbose { dev.msg.Printf("%d %d %d\n", hr, ch, gain) } - dev.hrscSetPreAmp(hr, ch, gain) + dev.brd.hrscSetPreAmp(hr, ch, gain) } } // send to HRs - err := dev.hrscSetConfig(int(rfm)) + err := dev.brd.hrscSetConfig(int(rfm)) if err != nil { return fmt.Errorf( "eda: could not send configuration to HR (dif=%d,slot=%d): %w", @@ -476,7 +455,7 @@ func (dev *Device) initHRFromDB() error { } dev.msg.Printf("Hardroc configuration (dif=%d, RFM=%d): [done]\n", dif, rfm) - err = dev.hrscResetReadRegisters(int(rfm)) + err = dev.brd.hrscResetReadRegisters(int(rfm)) if err != nil { return fmt.Errorf( "eda: could not reset read-registers for RFM=%d: %w", @@ -494,22 +473,22 @@ func (dev *Device) initHRFromDB() error { func (dev *Device) initHRFromCSV() error { // disable trig_out output pin (RFM v1 coupling problem) - dev.hrscSetBit(0, 854, 0) + dev.brd.hrscSetBit(0, 854, 0) - dev.hrscSetRShaper(0, dev.cfg.hr.rshaper) - dev.hrscSetCShaper(0, dev.cfg.hr.cshaper) + dev.brd.hrscSetRShaper(0, dev.cfg.hr.rshaper) + dev.brd.hrscSetCShaper(0, dev.cfg.hr.cshaper) - dev.hrscCopyConf(1, 0) - dev.hrscCopyConf(2, 0) - dev.hrscCopyConf(3, 0) - dev.hrscCopyConf(4, 0) - dev.hrscCopyConf(5, 0) - dev.hrscCopyConf(6, 0) - dev.hrscCopyConf(7, 0) + dev.brd.hrscCopyConf(1, 0) + dev.brd.hrscCopyConf(2, 0) + dev.brd.hrscCopyConf(3, 0) + dev.brd.hrscCopyConf(4, 0) + dev.brd.hrscCopyConf(5, 0) + dev.brd.hrscCopyConf(6, 0) + dev.brd.hrscCopyConf(7, 0) // set chip IDs for hr := uint32(0); hr < nHR; hr++ { - dev.hrscSetChipID(hr, hr+1) + dev.brd.hrscSetChipID(hr, hr+1) } // for each active RFM, tune the configuration and send it. @@ -521,7 +500,7 @@ func (dev *Device) initHRFromCSV() error { if verbose { dev.msg.Printf("%d %d %d\n", hr, ch, mask) } - dev.hrscSetMask(hr, ch, mask) + dev.brd.hrscSetMask(hr, ch, mask) } } @@ -536,9 +515,9 @@ func (dev *Device) initHRFromCSV() error { if verbose { dev.msg.Printf("%d %d %d %d\n", hr, th0, th1, th2) } - dev.hrscSetDAC0(hr, th0) - dev.hrscSetDAC1(hr, th1) - dev.hrscSetDAC2(hr, th2) + dev.brd.hrscSetDAC0(hr, th0) + dev.brd.hrscSetDAC1(hr, th1) + dev.brd.hrscSetDAC2(hr, th2) } // set preamplifier gain @@ -551,12 +530,12 @@ func (dev *Device) initHRFromCSV() error { if verbose { dev.msg.Printf("%d %d %d\n", hr, ch, gain) } - dev.hrscSetPreAmp(hr, ch, gain) + dev.brd.hrscSetPreAmp(hr, ch, gain) } } // send to HRs - err := dev.hrscSetConfig(rfm) + err := dev.brd.hrscSetConfig(rfm) if err != nil { return fmt.Errorf( "eda: could not send configuration to HR (RFM=%d): %w", @@ -565,7 +544,7 @@ func (dev *Device) initHRFromCSV() error { } dev.msg.Printf("Hardroc configuration (RFM=%d): [done]\n", rfm) - err = dev.hrscResetReadRegisters(rfm) + err = dev.brd.hrscResetReadRegisters(rfm) if err != nil { return fmt.Errorf( "eda: could not reset read-registers for RFM=%d: %w", @@ -606,7 +585,7 @@ func (dev *Device) startRunDCC(run uint32) error { var dccCmd uint32 = 0xe dev.msg.Printf("launching reset-BCID goroutine...") for dccCmd != regs.CMD_RESET_BCID { - dccCmd = dev.syncDCCCmdMem() + dccCmd = dev.brd.syncDCCCmdMem() } dev.msg.Printf("launching reset-BCID goroutine... [done: v=0x%x]", dccCmd) resetBCID <- dccCmd @@ -622,7 +601,7 @@ func (dev *Device) startRunDCC(run uint32) error { dev.msg.Printf("waiting for reset-BCID... [ok=0x%x]", v) } - dev.msg.Printf("sync-state: %[1]d 0x%[1]x\n", dev.syncState()) + dev.msg.Printf("sync-state: %[1]d 0x%[1]x\n", dev.brd.syncState()) for _, rfm := range dev.rfms { err = dev.DumpCounters(dev.msg.Writer(), rfm) if err != nil { @@ -630,24 +609,24 @@ func (dev *Device) startRunDCC(run uint32) error { } } - err = dev.cntReset() + err = dev.brd.cntReset() if err != nil { return fmt.Errorf("eda: could not reset counters: %w", err) } - err = dev.cntStart() + err = dev.brd.cntStart() if err != nil { return fmt.Errorf("eda: could not start counters: %w", err) } for _, rfm := range dev.rfms { - err = dev.daqFIFOInit(rfm) + err = dev.brd.daqFIFOInit(rfm) if err != nil { return fmt.Errorf("eda: could not initialize DAQ FIFO (RFM=%d): %w", rfm, err) } } - err = dev.syncArmFIFO() + err = dev.brd.syncArmFIFO() if err != nil { return fmt.Errorf("eda: could not arm FIFO: %w", err) } @@ -661,28 +640,28 @@ func (dev *Device) startRunDCC(run uint32) error { func (dev *Device) startRunNoise(run uint32) error { var err error for _, rfm := range dev.rfms { - err = dev.daqFIFOInit(rfm) + err = dev.brd.daqFIFOInit(rfm) if err != nil { return fmt.Errorf("eda: could not initialize DAQ FIFO (RFM=%d): %w", rfm, err) } } - err = dev.cntReset() + err = dev.brd.cntReset() if err != nil { return fmt.Errorf("eda: could not reset counters: %w", err) } - err = dev.syncResetBCID() + err = dev.brd.syncResetBCID() if err != nil { return fmt.Errorf("eda: could not reset BCID: %w", err) } - err = dev.syncStart() + err = dev.brd.syncStart() if err != nil { return fmt.Errorf("eda: could not start acquisition: %w", err) } - err = dev.syncArmFIFO() + err = dev.brd.syncArmFIFO() if err != nil { return fmt.Errorf("eda: could not arm FIFO: %w", err) } @@ -729,7 +708,7 @@ func (dev *Device) initRun(run uint32) error { dev.msg.Printf("-----------------RUN NB %d-----------------\n", run) fname = path.Join(dev.dir, fmt.Sprintf("hr_sc_%03d.csv", run)) - err = dev.hrscWriteConfHRs(fname) + err = dev.brd.hrscWriteConfHRs(fname) if err != nil { return fmt.Errorf( "eda: could not write HR config file %q: %w", @@ -737,7 +716,7 @@ func (dev *Device) initRun(run uint32) error { ) } - err = dev.syncResetHR() + err = dev.brd.syncResetHR() if err != nil { return fmt.Errorf("eda: could not reset hardroc: %w", err) } @@ -814,7 +793,7 @@ func (dev *Device) loopDCC() { // wait until readout is done readout: for { - state := dev.syncState() + state := dev.brd.syncState() switch state { case regs.S_START_RO: printf(w, "ro-") // readout of HR @@ -837,7 +816,7 @@ func (dev *Device) loopDCC() { for i, rfm := range dev.rfms { dev.daqWriteDIFData(dev.daq.rfm[i].w, rfm) } - err = dev.syncAckFIFO() + err = dev.brd.syncAckFIFO() if err != nil { errorf("eda: could not ACK FIFO: %w", err) return @@ -910,7 +889,7 @@ func (dev *Device) loopNoise() { // wait until readout is done readout: for { - state := dev.syncState() + state := dev.brd.syncState() switch { case state >= regs.S_RAMFULL: break readout @@ -924,7 +903,7 @@ func (dev *Device) loopNoise() { } } printf(w, "ramfull-") - err = dev.syncRAMFullExt() + err = dev.brd.syncRAMFullExt() if err != nil { errorf("could not set RAMFULL: %+v", err) return @@ -932,7 +911,7 @@ func (dev *Device) loopNoise() { dataReady: for { - state := dev.syncState() + state := dev.brd.syncState() switch { case state >= regs.S_FIFO_READY: break dataReady @@ -952,7 +931,7 @@ func (dev *Device) loopNoise() { for i, rfm := range dev.rfms { dev.daqWriteDIFData(dev.daq.rfm[i].w, rfm) } - err = dev.syncAckFIFO() + err = dev.brd.syncAckFIFO() if err != nil { errorf("eda: could not ACK FIFO: %w", err) return @@ -987,7 +966,7 @@ func (dev *Device) loopNoise() { dev.daq.done <- 1 return default: - err = dev.syncStart() + err = dev.brd.syncStart() if err != nil { errorf("eda: could not start acquisition: %w", err) return @@ -1015,30 +994,30 @@ func (dev *Device) Stop() error { var err error switch dev.cfg.daq.mode { case "dcc": - err = dev.cntStop() + err = dev.brd.cntStop() if err != nil { return fmt.Errorf("eda: could not stop counters: %w", err) } case "noise": - err = dev.syncStop() + err = dev.brd.syncStop() if err != nil { return fmt.Errorf("eda: could not stop acquisition: %w", err) } - err = dev.cntStop() + err = dev.brd.cntStop() if err != nil { return fmt.Errorf("eda: could not stop counters: %w", err) } } - err = dev.cntReset() + err = dev.brd.cntReset() if err != nil { return fmt.Errorf("eda: could not reset counters: %w", err) } - err = dev.syncResetFPGA() + err = dev.brd.syncResetFPGA() if err != nil { return fmt.Errorf("eda: could not reset FPGA: %w", err) } - err = dev.syncResetHR() + err = dev.brd.syncResetHR() if err != nil { return fmt.Errorf("eda: could not reset Hardroc: %w", err) } @@ -1078,7 +1057,7 @@ func (dev *Device) Close() error { func (dev *Device) DumpFIFOStatus(w io.Writer, rfm int) error { var ( - fifo = &dev.regs.fifo.daqCSR[rfm] + fifo = &dev.brd.regs.fifo.daqCSR[rfm] buf = bufio.NewWriter(w) err error printf = func(format string, args ...interface{}) { @@ -1154,12 +1133,12 @@ func (dev *Device) DumpCounters(w io.Writer, rfm int) error { printf("cnt48_msb;cnt48_lsb;cnt24\n") printf("%d;%d;%d;%d;", dev.daq.rfm[rfm].cycle, - dev.cntHit0(rfm), - dev.cntHit1(rfm), - dev.cntTrig(), + dev.brd.cntHit0(rfm), + dev.brd.cntHit1(rfm), + dev.brd.cntTrig(), ) printf("%d;%d;%d\n", - dev.cntBCID48MSB(), dev.cntBCID48LSB(), dev.cntBCID24(), + dev.brd.cntBCID48MSB(), dev.brd.cntBCID48LSB(), dev.brd.cntBCID24(), ) if err != nil { @@ -1177,7 +1156,7 @@ func (dev *Device) DumpConfig(w io.Writer, rfm int) error { buf := bufio.NewWriter(w) defer buf.Flush() - ram := &dev.regs.ramSC[rfm] + ram := &dev.brd.regs.ramSC[rfm] for i := 0; i < szCfgHR; i++ { j := 8 * (nHR*nBytesCfgHR - i - 1) v := ram.r(i) @@ -1193,7 +1172,7 @@ func (dev *Device) DumpRegisters(w io.Writer) error { const ( lvl = regs.ALTERA_AVALON_FIFO_LEVEL_REG ) - regs := &dev.regs + regs := &dev.brd.regs fmt.Fprintf(w, "pio.state= 0x%08x\n", regs.pio.state.r()) fmt.Fprintf(w, "pio.ctrl= 0x%08x\n", regs.pio.ctrl.r()) @@ -1229,7 +1208,7 @@ func (dev *Device) DumpRegisters(w io.Writer) error { 7: "fifo ready", 8: "stop run", } - state := dev.syncState() + state := dev.brd.syncState() fmt.Fprintf(w, "synchro FSM state= %d (%s)\n", state, names[state]) return dev.err } diff --git a/eda/device_test.go b/eda/device_test.go index 5099074..cb5492b 100644 --- a/eda/device_test.go +++ b/eda/device_test.go @@ -176,77 +176,77 @@ func TestDumpRegisters(t *testing.T) { defer dev.Close() var mu sync.RWMutex - wrap(dev, &mu, &dev.regs.pio.state, "pio.state", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.state, "pio.state", []uint32{ 0x1, 0x8 << regs.SHIFT_CMD_CODE_MEM, }, nil) - wrap(dev, &mu, &dev.regs.pio.ctrl, "pio.ctrl", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.ctrl, "pio.ctrl", []uint32{ 0x2, 0x2, }, nil) - wrap(dev, &mu, &dev.regs.pio.pulser, "pio.pulser", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.pulser, "pio.pulser", []uint32{ 0x3, }, nil) - wrap(dev, &mu, &dev.regs.pio.cntHit0[0], "pio.cntHit0[0]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.cntHit0[0], "pio.cntHit0[0]", []uint32{ 0x4, }, nil) - wrap(dev, &mu, &dev.regs.pio.cntHit0[1], "pio.cntHit0[1]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.cntHit0[1], "pio.cntHit0[1]", []uint32{ 0x5, }, nil) - wrap(dev, &mu, &dev.regs.pio.cntHit0[2], "pio.cntHit0[2]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.cntHit0[2], "pio.cntHit0[2]", []uint32{ 0x6, }, nil) - wrap(dev, &mu, &dev.regs.pio.cntHit0[3], "pio.cntHit0[3]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.cntHit0[3], "pio.cntHit0[3]", []uint32{ 0x7, }, nil) - wrap(dev, &mu, &dev.regs.pio.cntHit1[0], "pio.cntHit0[0]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.cntHit1[0], "pio.cntHit0[0]", []uint32{ 0x8, }, nil) - wrap(dev, &mu, &dev.regs.pio.cntHit1[1], "pio.cntHit1[1]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.cntHit1[1], "pio.cntHit1[1]", []uint32{ 0x9, }, nil) - wrap(dev, &mu, &dev.regs.pio.cntHit1[2], "pio.cntHit1[2]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.cntHit1[2], "pio.cntHit1[2]", []uint32{ 0x10, }, nil) - wrap(dev, &mu, &dev.regs.pio.cntHit1[3], "pio.cntHit1[3]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.cntHit1[3], "pio.cntHit1[3]", []uint32{ 0x11, }, nil) - wrap(dev, &mu, &dev.regs.pio.cntTrig, "pio.cntTrig", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.cntTrig, "pio.cntTrig", []uint32{ 0x12, }, nil) - wrap(dev, &mu, &dev.regs.pio.cnt48MSB, "pio.cnt48MSB", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.cnt48MSB, "pio.cnt48MSB", []uint32{ 0x13, }, nil) - wrap(dev, &mu, &dev.regs.pio.cnt48LSB, "pio.cnt48LSB", []uint32{ + wrap(dev, &mu, &dev.brd.regs.pio.cnt48LSB, "pio.cnt48LSB", []uint32{ 0x14, }, nil) - wrap(dev, &mu, &dev.regs.fifo.daqCSR[0].pins[0], "fifo.daqCSR[0]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.fifo.daqCSR[0].pins[0], "fifo.daqCSR[0]", []uint32{ 0x15, }, nil) - wrap(dev, &mu, &dev.regs.fifo.daqCSR[1].pins[0], "fifo.daqCSR[1]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.fifo.daqCSR[1].pins[0], "fifo.daqCSR[1]", []uint32{ 0x16, }, nil) - wrap(dev, &mu, &dev.regs.fifo.daqCSR[2].pins[0], "fifo.daqCSR[2]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.fifo.daqCSR[2].pins[0], "fifo.daqCSR[2]", []uint32{ 0x17, }, nil) - wrap(dev, &mu, &dev.regs.fifo.daqCSR[3].pins[0], "fifo.daqCSR[3]", []uint32{ + wrap(dev, &mu, &dev.brd.regs.fifo.daqCSR[3].pins[0], "fifo.daqCSR[3]", []uint32{ 0x18, }, nil) @@ -307,27 +307,27 @@ func TestDumpFIFOStatus(t *testing.T) { var mu sync.RWMutex - wrap(dev, &mu, &dev.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_LEVEL_REG], "fifo-level", []uint32{ + wrap(dev, &mu, &dev.brd.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_LEVEL_REG], "fifo-level", []uint32{ 0x1, }, nil) - wrap(dev, &mu, &dev.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_STATUS_REG], "fifo-status", []uint32{ + wrap(dev, &mu, &dev.brd.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_STATUS_REG], "fifo-status", []uint32{ 0xffffff, }, nil) - wrap(dev, &mu, &dev.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_EVENT_REG], "fifo-event", []uint32{ + wrap(dev, &mu, &dev.brd.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_EVENT_REG], "fifo-event", []uint32{ 0xffffff, }, nil) - wrap(dev, &mu, &dev.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_IENABLE_REG], "fifo-ienable", []uint32{ + wrap(dev, &mu, &dev.brd.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_IENABLE_REG], "fifo-ienable", []uint32{ 0xffffff, }, nil) - wrap(dev, &mu, &dev.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_ALMOSTFULL_REG], "fifo-almost-full", []uint32{ + wrap(dev, &mu, &dev.brd.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_ALMOSTFULL_REG], "fifo-almost-full", []uint32{ 128, }, nil) - wrap(dev, &mu, &dev.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_ALMOSTEMPTY_REG], "fifo-almost-empty", []uint32{ + wrap(dev, &mu, &dev.brd.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_ALMOSTEMPTY_REG], "fifo-almost-empty", []uint32{ 255, }, nil) @@ -387,7 +387,7 @@ func TestDumpConfig(t *testing.T) { j := 8 * (nHR*nBytesCfgHR - i - 1) fmt.Fprintf(want, "%d\t%x\n", j, buf[i]) } - _, err = dev.regs.ramSC[rfmID].w(buf) + _, err = dev.brd.regs.ramSC[rfmID].w(buf) if err != nil { t.Fatalf("could not write test buffer: %+v", err) } diff --git a/eda/driver.go b/eda/driver.go new file mode 100644 index 0000000..5b2db1c --- /dev/null +++ b/eda/driver.go @@ -0,0 +1,20 @@ +// Copyright 2021 The go-lpc Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package eda + +type driver interface { + hrscSetBit(hr, addr, bit uint32) + hrscGetBit(hr, addr uint32) uint32 + hrscCopyConf(hrDst, hrSrc uint32) + hrscResetReadRegisters(rfm int) error + hrscSetConfig(rfm int) error + hrscSelectSlowControl() error + hrscSelectReadRegister() error + hrscResetSC() error + hrscStartSC(rfm int) error + hrscSCDone(rfm int) bool +} + +var _ driver = (*board)(nil) diff --git a/eda/fake_device_test.go b/eda/fake_device_test.go index a893e7d..62889fd 100644 --- a/eda/fake_device_test.go +++ b/eda/fake_device_test.go @@ -173,14 +173,14 @@ func (*fakeDev) fpga(dev *Device, rfmID int, rfmDone uint32, exhaust func()) { }...) var mu sync.RWMutex - wrap(dev, &mu, &dev.regs.pio.ctrl, "pio.ctrl", fakeCtrl, exhaust) - wrap(dev, &mu, &dev.regs.pio.state, "pio.state", fakeState, exhaust) - wrap(dev, &mu, &dev.regs.pio.chkSC[rfmID], "pio.chk-sc", fakeChkSC, exhaust) - wrap(dev, &mu, &dev.regs.pio.cnt24, "pio.cnt24", fakeCnt24, exhaust) + wrap(dev, &mu, &dev.brd.regs.pio.ctrl, "pio.ctrl", fakeCtrl, exhaust) + wrap(dev, &mu, &dev.brd.regs.pio.state, "pio.state", fakeState, exhaust) + wrap(dev, &mu, &dev.brd.regs.pio.chkSC[rfmID], "pio.chk-sc", fakeChkSC, exhaust) + wrap(dev, &mu, &dev.brd.regs.pio.cnt24, "pio.cnt24", fakeCnt24, exhaust) wrap( dev, &mu, - &dev.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_STATUS_REG], + &dev.brd.regs.fifo.daqCSR[rfmID].pins[regs.ALTERA_AVALON_FIFO_STATUS_REG], "fifo.daq-csr[rfm]", fakeDaqCSR, exhaust, diff --git a/eda/pio.go b/eda/pio.go index e9ea8f5..eba09ee 100644 --- a/eda/pio.go +++ b/eda/pio.go @@ -13,7 +13,6 @@ import ( "os" "strconv" "strings" - "time" "github.com/go-lpc/mim/eda/internal/regs" "github.com/go-lpc/mim/internal/eformat" @@ -359,1476 +358,17 @@ func (dev *Device) readMask(fname string) error { } func (dev *Device) bindLwH2F() error { - dev.regs.pio.state = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_STATE_IN) - dev.regs.pio.ctrl = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CTRL_OUT) - dev.regs.pio.pulser = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_PULSER) - - dev.regs.ramSC[0] = newHRCfg(dev, dev.mem.lw, regs.LW_H2F_RAM_SC_RFM0) - dev.regs.ramSC[1] = newHRCfg(dev, dev.mem.lw, regs.LW_H2F_RAM_SC_RFM1) - dev.regs.ramSC[2] = newHRCfg(dev, dev.mem.lw, regs.LW_H2F_RAM_SC_RFM2) - dev.regs.ramSC[3] = newHRCfg(dev, dev.mem.lw, regs.LW_H2F_RAM_SC_RFM3) - - dev.regs.pio.chkSC[0] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_SC_CHECK_RFM0) - dev.regs.pio.chkSC[1] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_SC_CHECK_RFM1) - dev.regs.pio.chkSC[2] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_SC_CHECK_RFM2) - dev.regs.pio.chkSC[3] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_SC_CHECK_RFM3) - - dev.regs.pio.cntHit0[0] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT_HIT0_RFM0) - dev.regs.pio.cntHit0[1] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT_HIT0_RFM1) - dev.regs.pio.cntHit0[2] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT_HIT0_RFM2) - dev.regs.pio.cntHit0[3] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT_HIT0_RFM3) - - dev.regs.pio.cntHit1[0] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT_HIT1_RFM0) - dev.regs.pio.cntHit1[1] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT_HIT1_RFM1) - dev.regs.pio.cntHit1[2] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT_HIT1_RFM2) - dev.regs.pio.cntHit1[3] = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT_HIT1_RFM3) - - dev.regs.pio.cntTrig = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT_TRIG) - dev.regs.pio.cnt48MSB = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT48_MSB) - dev.regs.pio.cnt48LSB = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT48_LSB) - dev.regs.pio.cnt24 = newReg32(dev, dev.mem.lw, regs.LW_H2F_PIO_CNT24) - - return dev.err + return dev.brd.bindLwH2F(dev.mem.lw) } func (dev *Device) bindH2F() error { - dev.regs.fifo.daq[0] = newReg32(dev, dev.mem.h2f, regs.H2F_FIFO_DAQ_RFM0) - dev.regs.fifo.daq[1] = newReg32(dev, dev.mem.h2f, regs.H2F_FIFO_DAQ_RFM1) - dev.regs.fifo.daq[2] = newReg32(dev, dev.mem.h2f, regs.H2F_FIFO_DAQ_RFM2) - dev.regs.fifo.daq[3] = newReg32(dev, dev.mem.h2f, regs.H2F_FIFO_DAQ_RFM3) - - dev.regs.fifo.daqCSR[0] = newDAQFIFO(dev, dev.mem.h2f, regs.H2F_FIFO_DAQ_CSR_RFM0) - dev.regs.fifo.daqCSR[1] = newDAQFIFO(dev, dev.mem.h2f, regs.H2F_FIFO_DAQ_CSR_RFM1) - dev.regs.fifo.daqCSR[2] = newDAQFIFO(dev, dev.mem.h2f, regs.H2F_FIFO_DAQ_CSR_RFM2) - dev.regs.fifo.daqCSR[3] = newDAQFIFO(dev, dev.mem.h2f, regs.H2F_FIFO_DAQ_CSR_RFM3) - - return dev.err -} - -func (dev *Device) readU32(r io.ReaderAt, off int64) uint32 { - if dev.err != nil { - return 0 - } - _, dev.err = r.ReadAt(dev.buf[:4], off) - if dev.err != nil { - dev.err = fmt.Errorf("eda: could not read register 0x%x: %w", off, dev.err) - return 0 - } - return binary.LittleEndian.Uint32(dev.buf[:4]) -} - -func (dev *Device) writeU32(w io.WriterAt, off int64, v uint32) { - if dev.err != nil { - return - } - binary.LittleEndian.PutUint32(dev.buf[:4], v) - _, dev.err = w.WriteAt(dev.buf[:4], off) - if dev.err != nil { - dev.err = fmt.Errorf("eda: could not write register 0x%x: %w", off, dev.err) - return - } -} - -func (dev *Device) rfmOn(rfm int) error { - var mask uint32 - switch rfm { - case 0: - mask = regs.O_ON_OFF_RFM0 - case 1: - mask = regs.O_ON_OFF_RFM1 - case 2: - mask = regs.O_ON_OFF_RFM2 - case 3: - mask = regs.O_ON_OFF_RFM3 - default: - panic(fmt.Errorf("eda: invalid RFM id=%d", rfm)) - } - ctrl := dev.regs.pio.ctrl.r() - ctrl |= mask - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not switch ON RFM=%d: %w", rfm, dev.err) - } - return nil -} - -// func (dev *Device) rfmOff(rfm int) error { -// var mask uint32 -// switch rfm { -// case 0: -// mask = regs.O_ON_OFF_RFM0 -// case 1: -// mask = regs.O_ON_OFF_RFM1 -// case 2: -// mask = regs.O_ON_OFF_RFM2 -// case 3: -// mask = regs.O_ON_OFF_RFM3 -// default: -// panic(fmt.Errorf("eda: invalid RFM id=%d", rfm)) -// } -// ctrl := dev.regs.pio.ctrl.r() -// ctrl &= ^mask -// dev.regs.pio.ctrl.w(ctrl) -// -// if dev.err != nil { -// return fmt.Errorf("eda: could not switch OFF RFM=%d: %w", rfm, dev.err) -// } -// return nil -// } - -func (dev *Device) rfmEnable(rfm int) error { - var mask uint32 - switch rfm { - case 0: - mask = regs.O_ENA_RFM0 - case 1: - mask = regs.O_ENA_RFM1 - case 2: - mask = regs.O_ENA_RFM2 - case 3: - mask = regs.O_ENA_RFM3 - default: - panic(fmt.Errorf("eda: invalid RFM id=%d", rfm)) - } - ctrl := dev.regs.pio.ctrl.r() - ctrl |= mask - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not enable RFM=%d: %w", rfm, dev.err) - } - return nil -} - -// func (dev *Device) rfmDisable(rfm int) error { -// var mask uint32 -// switch rfm { -// case 0: -// mask = regs.O_ENA_RFM0 -// case 1: -// mask = regs.O_ENA_RFM1 -// case 2: -// mask = regs.O_ENA_RFM2 -// case 3: -// mask = regs.O_ENA_RFM3 -// default: -// panic(fmt.Errorf("eda: invalid RFM id=%d", rfm)) -// } -// ctrl := dev.regs.pio.ctrl.r() -// ctrl &= ^mask -// dev.regs.pio.ctrl.w(ctrl) -// -// if dev.err != nil { -// return fmt.Errorf("eda: could not disable RFM=%d: %w", rfm, dev.err) -// } -// return nil -// } - -func (dev *Device) syncResetFPGA() error { - dev.regs.pio.ctrl.w(regs.O_RESET) - dev.msg.Printf("reset FPGA") - time.Sleep(1 * time.Microsecond) - dev.regs.pio.ctrl.w(0x00000000) - time.Sleep(1 * time.Microsecond) - - if dev.err != nil { - return fmt.Errorf("eda: could not reset FPGA: %w", dev.err) - } - return nil -} - -func (dev *Device) syncResetHR() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl |= regs.O_RESET_HR - dev.regs.pio.ctrl.w(ctrl) - time.Sleep(1 * time.Microsecond) - - ctrl = dev.regs.pio.ctrl.r() - ctrl &= ^uint32(regs.O_RESET_HR) - dev.regs.pio.ctrl.w(ctrl) - time.Sleep(1 * time.Microsecond) - - if dev.err != nil { - return fmt.Errorf("eda: could not reset HR: %w", dev.err) - } - return nil -} - -func (dev *Device) syncPLLLock() bool { - state := dev.regs.pio.state.r() - return state®s.O_PLL_LCK == regs.O_PLL_LCK -} - -func (dev *Device) syncState() uint32 { - state := dev.regs.pio.state.r() - return (state >> regs.SHIFT_SYNCHRO_STATE) & 0xF -} - -func (dev *Device) syncSelectCmdSoft() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl |= regs.O_SEL_CMD_SOURCE - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not synchronize cmd-soft: %w", dev.err) - } - return nil -} - -func (dev *Device) syncSelectCmdDCC() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl &= ^uint32(regs.O_SEL_CMD_SOURCE) - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not synchronize cmd-dcc: %w", dev.err) - } - return nil -} - -func (dev *Device) syncSetCmd(cmd uint32) error { - ctrl := dev.regs.pio.ctrl.r() - ctrl &= ^uint32(0xf << regs.SHIFT_CMD_CODE) // reset 4 bits - ctrl |= (0xf & cmd) << regs.SHIFT_CMD_CODE // set command - - dev.regs.pio.ctrl.w(ctrl) - time.Sleep(2 * time.Microsecond) - - ctrl &= ^uint32(0xf << regs.SHIFT_CMD_CODE) // reset 4 bits - ctrl |= regs.CMD_IDLE << regs.SHIFT_CMD_CODE // set idle command - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not set command 0x%x: %w", cmd, dev.err) - } - return nil -} - -func (dev *Device) syncResetBCID() error { - return dev.syncSetCmd(regs.CMD_RESET_BCID) -} - -func (dev *Device) syncStart() error { - return dev.syncSetCmd(regs.CMD_START_ACQ) -} - -func (dev *Device) syncStop() error { - return dev.syncSetCmd(regs.CMD_STOP_ACQ) -} - -func (dev *Device) syncRAMFullExt() error { - return dev.syncSetCmd(regs.CMD_RAMFULL_EXT) -} - -// func (dev *Device) syncDigitalRO() error { -// return dev.syncSetCmd(regs.CMD_DIGITAL_RO) -// } - -func (dev *Device) syncArmFIFO() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl |= regs.O_HPS_BUSY - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not arm FIFO: %w", dev.err) - } - return nil -} - -func (dev *Device) syncAckFIFO() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl &= ^uint32(regs.O_HPS_BUSY) - dev.regs.pio.ctrl.w(ctrl) // falling edge on hps busy - for dev.syncState() != regs.S_IDLE { - // when FPGA ready for new acquisition - } - ctrl = dev.regs.pio.ctrl.r() - dev.regs.pio.ctrl.w(ctrl | regs.O_HPS_BUSY) // re-arming - - if dev.err != nil { - return fmt.Errorf("eda: could not ACK FIFO: %w", dev.err) - } - return nil -} - -func (dev *Device) syncDCCCmdMem() uint32 { - cnt := dev.regs.pio.cnt24.r() - return (cnt >> regs.SHIFT_CMD_CODE_MEM) & 0xf -} - -// func (dev *Device) syncDCCCmdNow() uint32 { -// cnt := dev.regs.pio.cnt24.r() -// return (cnt >> regs.SHIFT_CMD_CODE_NOW) & 0xf -// } -// -// func (dev *Device) syncRAMFull() bool { -// state := dev.syncState() -// return state == regs.S_RAMFULL -// } -// -// func (dev *Device) syncFPGARO() bool { -// state := dev.syncState() -// return state == regs.S_START_RO || state == regs.S_WAIT_END_RO -// } -// -// func (dev *Device) syncFIFOReady() bool { -// state := dev.syncState() -// return state == regs.S_FIFO_READY -// } -// -// func (dev *Device) syncRunStopped() bool { -// state := dev.syncState() -// return state == regs.S_STOP_RUN -// } - -// func (dev *Device) syncHRTransmitOn(rfm int) bool { -// state := dev.regs.pio.state.r() -// switch rfm { -// case 0: -// return (state & regs.O_HR_TRANSMITON_0) == regs.O_HR_TRANSMITON_0 -// case 1: -// return (state & regs.O_HR_TRANSMITON_1) == regs.O_HR_TRANSMITON_1 -// case 2: -// return (state & regs.O_HR_TRANSMITON_2) == regs.O_HR_TRANSMITON_2 -// case 3: -// return (state & regs.O_HR_TRANSMITON_3) == regs.O_HR_TRANSMITON_3 -// } -// panic(fmt.Errorf("eda: invalid RFM id %d", rfm)) -// } -// -// func (dev *Device) syncChipsAt(rfm int) bool { -// state := dev.regs.pio.state.r() -// switch rfm { -// case 0: -// return (state & regs.O_CHIPSAT_0) == regs.O_CHIPSAT_0 -// case 1: -// return (state & regs.O_CHIPSAT_1) == regs.O_CHIPSAT_1 -// case 2: -// return (state & regs.O_CHIPSAT_2) == regs.O_CHIPSAT_2 -// case 3: -// return (state & regs.O_CHIPSAT_3) == regs.O_CHIPSAT_3 -// } -// panic(fmt.Errorf("eda: invalid RFM id %d", rfm)) -// } -// -// func (dev *Device) syncHREndRO(rfm int) bool { -// state := dev.regs.pio.state.r() -// switch rfm { -// case 0: -// return (state & regs.O_HR_END_RO_0) == regs.O_HR_END_RO_0 -// case 1: -// return (state & regs.O_HR_END_RO_1) == regs.O_HR_END_RO_1 -// case 2: -// return (state & regs.O_HR_END_RO_2) == regs.O_HR_END_RO_2 -// case 3: -// return (state & regs.O_HR_END_RO_3) == regs.O_HR_END_RO_3 -// } -// panic(fmt.Errorf("eda: invalid RFM id %d", rfm)) -// } - -func (dev *Device) syncEnableDCCBusy() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl |= regs.O_ENA_DCC_BUSY - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not enable DCC-BUSY: %w", dev.err) - } - return nil -} - -func (dev *Device) syncEnableDCCRAMFull() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl |= regs.O_ENA_DCC_RAMFULL - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not enable DCC-RAMFULL: %w", dev.err) - } - return nil -} - -// func (dev *Device) trigSelectThreshold0() error { -// ctrl := dev.regs.pio.ctrl.r() -// ctrl &= ^uint32(regs.O_SEL_TRIG_THRESH) -// dev.regs.pio.ctrl.w(ctrl) -// -// if dev.err != nil { -// return fmt.Errorf("eda: could not select threshold-0: %w", dev.err) -// } -// return nil -// } -// -// func (dev *Device) trigSelectThreshold1() error { -// ctrl := dev.regs.pio.ctrl.r() -// ctrl |= regs.O_SEL_TRIG_THRESH -// dev.regs.pio.ctrl.w(ctrl) -// -// if dev.err != nil { -// return fmt.Errorf("eda: could not select threshold-1: %w", dev.err) -// } -// return nil -// } -// -// func (dev *Device) trigEnable() error { -// ctrl := dev.regs.pio.ctrl.r() -// ctrl |= regs.O_ENA_TRIG -// dev.regs.pio.ctrl.w(ctrl) -// -// if dev.err != nil { -// return fmt.Errorf("eda: could not enable trigger: %w", dev.err) -// } -// return nil -// } -// -// func (dev *Device) trigDisable() error { -// ctrl := dev.regs.pio.ctrl.r() -// ctrl &= ^uint32(regs.O_ENA_TRIG) -// dev.regs.pio.ctrl.w(ctrl) -// -// if dev.err != nil { -// return fmt.Errorf("eda: could not disable trigger: %w", dev.err) -// } -// return nil -// } - -func (dev *Device) cntReset() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl |= regs.O_RST_SCALERS - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not reset scalers: %w", dev.err) - } - - time.Sleep(1 * time.Microsecond) - - ctrl &= ^uint32(regs.O_RST_SCALERS) - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not clear scalers: %w", dev.err) - } - return nil -} - -func (dev *Device) cntStart() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl |= regs.O_ENA_SCALERS - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not start scalers: %w", dev.err) - } - return nil -} - -func (dev *Device) cntStop() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl &= ^uint32(regs.O_ENA_SCALERS) - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not stop scalers: %w", dev.err) - } - return nil -} - -func (dev *Device) cntHit0(rfm int) uint32 { - return dev.regs.pio.cntHit0[rfm].r() + return dev.brd.bindH2F(dev.mem.h2f) } -func (dev *Device) cntHit1(rfm int) uint32 { - return dev.regs.pio.cntHit1[rfm].r() -} - -func (dev *Device) cntTrig() uint32 { - return dev.regs.pio.cntTrig.r() -} - -func (dev *Device) cntBCID24() uint32 { - v := dev.regs.pio.cnt24.r() - return v & 0xffffff -} - -func (dev *Device) cntBCID48MSB() uint32 { - v := dev.regs.pio.cnt48MSB.r() - return v & 0xffff -} - -func (dev *Device) cntBCID48LSB() uint32 { - return dev.regs.pio.cnt48LSB.r() -} - -// func (dev *Device) cntSave(w io.Writer, rfm int) error { -// var ( -// i = 0 -// buf = make([]byte, 7*4) -// dif = difIDOffset + ((dev.id & 7) << 3) + (uint32(rfm) & 3) -// u32 = (dif << 24) | (dev.daq.cycleID[rfm] & 0x00ffffff) -// ) -// -// binary.BigEndian.PutUint32(buf[i:], u32) -// i += 4 -// binary.BigEndian.PutUint32(buf[i:], dev.cntBCID48MSB()) -// i += 4 -// binary.BigEndian.PutUint32(buf[i:], dev.cntBCID48LSB()) -// i += 4 -// binary.BigEndian.PutUint32(buf[i:], dev.cntBCID24()) -// i += 4 -// binary.BigEndian.PutUint32(buf[i:], dev.cntHit0(rfm)) -// i += 4 -// binary.BigEndian.PutUint32(buf[i:], dev.cntHit1(rfm)) -// i += 4 -// binary.BigEndian.PutUint32(buf[i:], dev.cntTrig()) -// if dev.err != nil { -// return fmt.Errorf("eda: could not read counters: %w", dev.err) -// } -// -// n, err := w.Write(buf) -// if err != nil { -// return fmt.Errorf("eda: could not save counters: %w", err) -// } -// -// if n != len(buf) { -// return fmt.Errorf("eda: could not save counters: %w", io.ErrShortWrite) -// } -// return nil -// } - -// hardroc slow control - -func (dev *Device) hrscSelectSlowControl() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl &= ^uint32(regs.O_SELECT_SC_RR) - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not select slow-control: %w", dev.err) - } - return nil -} - -func (dev *Device) hrscSelectReadRegister() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl |= regs.O_SELECT_SC_RR - dev.regs.pio.ctrl.w(ctrl) - - if dev.err != nil { - return fmt.Errorf("eda: could not select read-register: %w", dev.err) - } - return nil -} - -func div(num, den uint32) (quo, rem uint32) { - quo = num / den - rem = num % den - return quo, rem -} - -func (dev *Device) hrscSetBit(hr, addr, bit uint32) { - // byte address 0 corresponds to the last register (addr 864 to 871) - // of the last Hardroc (pos=nHR-1) - var ( - quo, rem = div(addr, nHR) - - i = (nHR-1-hr)*nBytesCfgHR + nBytesCfgHR - 1 - quo - v = dev.cfg.hr.data[i] - off = rem - - // bit address increases from LSB to MSB - mask1 = uint8(0x01 << off) - mask2 = uint8((0x1 & bit) << off) - ) - v &= ^mask1 // reset target bit - v |= mask2 // set target bit = "bit" argument - dev.cfg.hr.data[i] = v -} - -func (dev *Device) hrscGetBit(hr, addr uint32) uint32 { - // byte address 0 corresponds to the last register (addr 864 to 871) - // of the last Hardroc (pos=nHR-1) - var ( - quo, rem = div(addr, nHR) - - i = (nHR-1-hr)*nBytesCfgHR + nBytesCfgHR - 1 - quo - v = dev.cfg.hr.data[i] - off = rem - ) - return uint32((v >> off) & 0x01) -} - -func (dev *Device) hrscSetWord(hr, addr, nbits, v uint32) { - for i := uint32(0); i < nbits; i++ { - // scan LSB to MSB - bit := (v >> i) & 0x01 - dev.hrscSetBit(hr, addr+i, bit) - } -} - -func (dev *Device) hrscSetWordMSB2LSB(hr, addr, nbits, v uint32) { - for i := uint32(0); i < nbits; i++ { - // scan MSB to LSB - bit := (v >> i) & 0x01 - dev.hrscSetBit(hr, addr+nbits-1-i, bit) - } -} - -func (dev *Device) hrscReadConf(fname string, hr uint32) error { - f, err := os.Open(fname) - if err != nil { - return fmt.Errorf("eda: could not open config file %q: %w", fname, err) - } - defer f.Close() - - var ( - addr uint32 - bit uint32 - cnt = uint32(nBitsCfgHR - 1) - sc = bufio.NewScanner(f) - line int - ) - - for sc.Scan() { - line++ - txt := strings.TrimSpace(sc.Text()) - if strings.HasPrefix(txt, "#") { - continue - } - toks := strings.Split(txt, ";") - - if len(toks) != 5 { - return fmt.Errorf("eda: invalid config file:%d: line=%q", line, txt) - } - v, err := strconv.ParseUint(toks[0], 10, 32) - if err != nil { - return fmt.Errorf("eda: could not parse address %q in %q: %w", toks[0], txt, err) - } - addr = uint32(v) - - v, err = strconv.ParseUint(toks[4], 10, 32) - if err != nil { - return fmt.Errorf("eda: could not parse bit %q in %q: %w", toks[4], txt, err) - } - bit = uint32(v) - - if addr != cnt { - return fmt.Errorf( - "eda: invalid bit address line:%d: got=0x%x, want=0x%x", - line, addr, cnt, - ) - } - cnt-- - - dev.hrscSetBit(hr, addr, bit) - if addr == 0 { - return nil - } - } - err = sc.Err() - if err != nil && err != io.EOF { - return fmt.Errorf("eda: could not scan config file %q: %w", fname, err) - } - - return fmt.Errorf("eda: reached end of config file %q before last bit", fname) -} - -func (dev *Device) hrscCopyConf(hrDst, hrSrc uint32) { - var ( - isrc = (nHR - 1 - hrSrc) * nBytesCfgHR - idst = (nHR - 1 - hrDst) * nBytesCfgHR - - dst = dev.cfg.hr.data[idst : idst+nBytesCfgHR] - src = dev.cfg.hr.data[isrc : isrc+nBytesCfgHR] - ) - copy(dst, src) -} - -func (dev *Device) hrscReadConfHRs(fname string) error { - f, err := os.Open(fname) - if err != nil { - return fmt.Errorf("eda: could not open hr-sc %q: %w", fname, err) - } - defer f.Close() - - var ( - hr uint32 - addr uint32 - bit uint32 - cntBit = int64(nBitsCfgHR - 1) - cntHR = int64(nHR - 1) - sc = bufio.NewScanner(f) - line int - ) - - for sc.Scan() && cntBit >= 0 && cntHR >= 0 { - line++ - txt := strings.TrimSpace(sc.Text()) - if strings.HasPrefix(txt, "#") { - continue - } - toks := strings.Split(txt, ";") - if len(toks) != 3 { - return fmt.Errorf("eda: invalid HR config file:%d: line=%q", line, txt) - } - v, err := strconv.ParseUint(toks[0], 10, 32) - if err != nil { - return fmt.Errorf( - "eda: could not parse HR address %q in %q: %w", - toks[0], txt, err, - ) - } - hr = uint32(v) - - v, err = strconv.ParseUint(toks[1], 10, 32) - if err != nil { - return fmt.Errorf( - "eda: could not parse bit address %q in %q: %w", - toks[1], txt, err, - ) - } - addr = uint32(v) - - v, err = strconv.ParseUint(toks[2], 10, 32) - if err != nil { - return fmt.Errorf( - "eda: could not parse bit value %q in %q: %w", - toks[2], txt, err, - ) - } - bit = uint32(v) - - if int64(addr) != cntBit { - return fmt.Errorf( - "eda: invalid bit address line:%d: got=%d, want=%d", - line, addr, cntBit, - ) - } - - if int64(hr) != cntHR { - return fmt.Errorf( - "eda: invalid HR address line:%d: got=%d, want=%d", - line, hr, cntHR, - ) - } - - cntBit-- - if cntBit < 0 { - cntBit = nBitsCfgHR - 1 - cntHR-- - } - - dev.hrscSetBit(hr, addr, bit) - if addr == 0 && hr == 0 { - return nil - } - } - - err = sc.Err() - if err != nil && err != io.EOF { - return fmt.Errorf("eda: could not scan config file %q: %w", fname, err) - } - - return fmt.Errorf("eda: reached end of config file %q before last bit", fname) -} - -func (dev *Device) hrscWriteConfHRs(fname string) error { - f, err := os.Create(fname) - if err != nil { - return fmt.Errorf("eda: could not create hr-sc file %q: %w", fname, err) - } - defer f.Close() - - w := bufio.NewWriter(f) - for i := 0; i < nHR; i++ { - for j := 0; j < nBitsCfgHR; j++ { - var ( - hr = uint32(nHR - 1 - i) - addr = uint32(nBitsCfgHR - 1 - j) - v = dev.hrscGetBit(hr, addr) - ) - fmt.Fprintf(w, "%d;%d;%d\n", hr, addr, v) - } - } - - err = w.Flush() - if err != nil { - return fmt.Errorf("eda: could not flush hr-sc file %q: %w", fname, err) - } - - err = f.Close() - if err != nil { - return fmt.Errorf("eda: could not close hr-sc file %q: %w", fname, err) - } - return nil -} - -// // hrscSetCtest switches the test capacitor (1=closed). -// func (dev *Device) hrscSetCtest(hr, ch, v uint32) { -// dev.hrscSetBit(hr, ch, v&0x01) -// } -// -// func (dev *Device) hrscSetAllCtestOff() { -// for hr := uint32(0); hr < nHR; hr++ { -// for ch := uint32(0); ch < nChans; ch++ { -// dev.hrscSetCtest(hr, ch, 0) -// } -// } -// } - -func (dev *Device) hrscSetPreAmp(hr, ch, v uint32) { - addr := nChans + nHR*ch - dev.hrscSetWord(hr, addr, 8, v) -} - -// func (dev *Device) hrscSetCmdFSB2(hr, ch, v uint32) { -// // fast shaper 2 gain -// addr := 587 + 4*ch -// dev.hrscSetWordMSB2LSB(hr, addr, 4, ^v) // "cmdb" register bits are active-low -// } -// -// func (dev *Device) hrscSetCmdFSB1(hr, ch, v uint32) { -// // fast shaper 2 gain -// addr := 595 + 4*ch -// dev.hrscSetWordMSB2LSB(hr, addr, 4, ^v) // "cmdb" register bits are active-low -// } - -func (dev *Device) hrscSetMask(hr, ch, v uint32) { - addr := 618 + 3*ch - dev.hrscSetWord(hr, addr, 3, v) -} - -func (dev *Device) hrscSetChipID(hr, v uint32) { - dev.hrscSetWordMSB2LSB(hr, 810, 8, v) -} - -func (dev *Device) hrscSetDAC0(hr, v uint32) { - dev.hrscSetWord(hr, 818, 10, v) -} - -func (dev *Device) hrscSetDAC1(hr, v uint32) { - dev.hrscSetWord(hr, 828, 10, v) -} - -func (dev *Device) hrscSetDAC2(hr, v uint32) { - dev.hrscSetWord(hr, 838, 10, v) -} - -// func (dev *Device) hrscSetDACCoarse(hr uint32) { -// dev.hrscSetWord(hr, 848, 10, 0) -// } -// -// func (dev *Device) hrscSetDACFine(hr uint32) { -// dev.hrscSetWord(hr, 848, 10, 1) -// } - -func (dev *Device) hrscSetCShaper(hr, v uint32) { - dev.hrscSetBit(hr, 611, v&1) // sw_50f0 = b0 - dev.hrscSetBit(hr, 602, v&1) // sw_50f1 = b0 - dev.hrscSetBit(hr, 594, v&1) // sw_50f2 = b0 - dev.hrscSetBit(hr, 610, (v>>1)&1) // sw_100f0 = b1 - dev.hrscSetBit(hr, 601, (v>>1)&1) // sw_100f1 = b1 - dev.hrscSetBit(hr, 593, (v>>1)&1) // sw_100f2 = b1 -} - -func (dev *Device) hrscSetRShaper(hr, v uint32) { - dev.hrscSetBit(hr, 609, v&1) // sw_100k0 = b0 - dev.hrscSetBit(hr, 600, v&1) // sw_100k1 = b0 - dev.hrscSetBit(hr, 592, v&1) // sw_100k2 = b0 - dev.hrscSetBit(hr, 608, (v>>1)&1) // sw_50k0 = b1 - dev.hrscSetBit(hr, 599, (v>>1)&1) // sw_50k1 = b1 - dev.hrscSetBit(hr, 591, (v>>1)&1) // sw_50k2 = b1 -} - -func (dev *Device) hrscSetConfig(rfm int) error { - ctrl := dev.regs.pio.chkSC[rfm].r() - if dev.err != nil { - return fmt.Errorf( - "eda: could not read check-sc register (rfm=%d): %w", - rfm, dev.err, - ) - } - - switch ctrl { - case 0xcafefade: - ctrl = 0x36baffe5 - default: - ctrl = 0xcafefade - } - dev.cfg.hr.buf[0] = byte((ctrl >> 24) & 0xff) - dev.cfg.hr.buf[1] = byte((ctrl >> 16) & 0xff) - dev.cfg.hr.buf[2] = byte((ctrl >> 8) & 0xff) - dev.cfg.hr.buf[3] = byte(ctrl & 0xff) - - // reset sc - err := dev.hrscSelectSlowControl() - if err != nil { - return fmt.Errorf("eda: could not select slow-control (rfm=%d): %w", - rfm, err, - ) - } - - err = dev.hrscResetSC() - if err != nil { - return fmt.Errorf("eda: could not reset slow-control (rfm=%d): %w", - rfm, err, - ) - } - - if dev.hrscSCDone(rfm) { - return fmt.Errorf("eda: could not reset slow control (rfm=%d): sc-not-done", rfm) - } - - // copy to FPGA - _, err = dev.regs.ramSC[rfm].w(dev.cfg.hr.buf[:szCfgHR]) - if err != nil { - return fmt.Errorf( - "eda: could not write slow-control cfg to FPGA (rfm=%d): %w", - rfm, err, - ) - } - - // trigger the slow control serializer - err = dev.hrscStartSC(rfm) - if err != nil { - return fmt.Errorf( - "eda: could not start slow-control serializer (rfm=%d): %w", - rfm, err, - ) - } - - // check loop-back header - time.Sleep(10 * time.Microsecond) - for !dev.hrscSCDone(rfm) { - time.Sleep(10 * time.Microsecond) - } - - chk := dev.regs.pio.chkSC[rfm].r() - if dev.err != nil { - return fmt.Errorf( - "eda: could not read slow-control loopback register (rfm=%d): %w", - rfm, dev.err, - ) - } - - if chk != ctrl { - return fmt.Errorf( - "eda: invalid loopback register (rfm=%d): got=0x%x, want=0x%x", - rfm, chk, ctrl, - ) - } - - return nil -} - -func (dev *Device) hrscResetReadRegisters(rfm int) error { - ctrl := dev.regs.pio.chkSC[rfm].r() - if dev.err != nil { - return fmt.Errorf( - "eda: could not read check-sc register (rfm=%d): %w", - rfm, dev.err, - ) - } - - switch ctrl { - case 0xcafefade: - ctrl = 0x36baffe5 - default: - ctrl = 0xcafefade - } - var ( - buf [szCfgHR]byte - off = nHR*nBytesCfgHR - nChans - ) - buf[off+0] = byte((ctrl >> 24) & 0xff) - buf[off+1] = byte((ctrl >> 16) & 0xff) - buf[off+2] = byte((ctrl >> 8) & 0xff) - buf[off+3] = byte(ctrl & 0xff) - - // reset sc - err := dev.hrscSelectReadRegister() - if err != nil { - return fmt.Errorf( - "eda: could select read-register (rfm=%d): %w", - rfm, err, - ) - } - - err = dev.hrscResetSC() - if err != nil { - return fmt.Errorf("eda: could not reset slow-control (rfm=%d): %w", - rfm, err, - ) - } - - if dev.hrscSCDone(rfm) { - return fmt.Errorf("eda: could not reset slow control (rfm=%d)", rfm) - } - - // copy to FPGA - _, err = dev.regs.ramSC[rfm].w(buf[:szCfgHR]) - if err != nil { - return fmt.Errorf( - "eda: could not write slow-control cfg to FPGA (rfm=%d): %w", - rfm, err, - ) - } - - // trigger the slow control serializer - time.Sleep(10 * time.Microsecond) - err = dev.hrscStartSC(rfm) - if err != nil { - return fmt.Errorf( - "eda: could not start slow-control serializer (rfm=%d): %w", - rfm, err, - ) - } - - // check loop-back header - time.Sleep(10 * time.Microsecond) - for !dev.hrscSCDone(rfm) { - time.Sleep(10 * time.Microsecond) - } - - chk := dev.regs.pio.chkSC[rfm].r() - if dev.err != nil { - return fmt.Errorf( - "eda: could not read slow-control loopback register (rfm=%d): %w", - rfm, dev.err, - ) - } - - if chk != ctrl { - return fmt.Errorf( - "eda: invalid loopback register (rfm=%d): got=0x%x, want=0x%x", - rfm, chk, ctrl, - ) - } - - err = dev.hrscSelectSlowControl() - if err != nil { - return fmt.Errorf( - "eda: could not select slow-control (rfm=%d): %w", - rfm, err, - ) - } - - return nil -} - -// func (dev *Device) hrscSetReadRegister(rfm, ch int) error { -// ctrl := dev.regs.pio.chkSC[rfm].r() -// if dev.err != nil { -// return fmt.Errorf( -// "eda: could not read check-sc register (rfm=%d): %w", -// rfm, dev.err, -// ) -// } -// -// switch ctrl { -// case 0xcafefade: -// ctrl = 0x36baffe5 -// default: -// ctrl = 0xcafefade -// } -// var ( -// buf [szCfgHR]byte -// off = nHR*nBytesCfgHR - nChans -// ) -// buf[off+0] = byte((ctrl >> 24) & 0xff) -// buf[off+1] = byte((ctrl >> 16) & 0xff) -// buf[off+2] = byte((ctrl >> 8) & 0xff) -// buf[off+3] = byte(ctrl & 0xff) -// -// // reset sc -// err := dev.hrscSelectReadRegister() -// if err != nil { -// return fmt.Errorf( -// "eda: could select read-register (rfm=%d): %w", -// rfm, err, -// ) -// } -// -// err = dev.hrscResetSC() -// if err != nil { -// return fmt.Errorf("eda: could not reset slow-control (rfm=%d): %w", -// rfm, err, -// ) -// } -// -// if !dev.hrscSCDone(rfm) { -// return fmt.Errorf("eda: could not reset slow control (rfm=%d)", rfm) -// } -// -// // select the same channel for all HR's -// var ( -// quo, rem = div(uint32(ch), nHR) // channels: 0->64*nHR-1 -// v = byte(0x1 << rem) -// ) -// for i := 0; i < nHR; i++ { -// off := nHR*nBytesCfgHR + 3 - i*nHR - int(quo) // last byte -> channels [0,8) -// buf[off] = v -// } -// -// // copy to FPGA -// _, err = dev.regs.ramSC[rfm].w(buf[:szCfgHR]) -// if err != nil { -// return fmt.Errorf( -// "eda: could not write slow-control cfg to FPGA (rfm=%d): %w", -// rfm, err, -// ) -// } -// -// // trigger the slow control serializer -// err = dev.hrscStartSC(rfm) -// if err != nil { -// return fmt.Errorf( -// "eda: could not start slow-control serializer (rfm=%d): %w", -// rfm, err, -// ) -// } -// -// // check loop-back header -// time.Sleep(10 * time.Microsecond) -// for !dev.hrscSCDone(rfm) { -// time.Sleep(10 * time.Microsecond) -// } -// -// chk := dev.regs.pio.chkSC[rfm].r() -// if dev.err != nil { -// return fmt.Errorf( -// "eda: could not read slow-control loopback register (rfm=%d): %w", -// rfm, dev.err, -// ) -// } -// -// if chk != ctrl { -// return fmt.Errorf( -// "eda: invalid loopback register (rfm=%d): got=0x%x, want=0x%x", -// rfm, chk, ctrl, -// ) -// } -// -// err = dev.hrscSelectSlowControl() -// if err != nil { -// return fmt.Errorf( -// "eda: could not select slow-control (rfm=%d): %w", -// rfm, err, -// ) -// } -// -// return nil -// } - -func (dev *Device) hrscResetSC() error { - ctrl := dev.regs.pio.ctrl.r() - ctrl |= regs.O_RESET_SC - dev.regs.pio.ctrl.w(ctrl) - if dev.err != nil { - return fmt.Errorf("eda: could not reset slow-control: %w", dev.err) - } - - time.Sleep(1 * time.Microsecond) - - ctrl = dev.regs.pio.ctrl.r() - ctrl &= ^uint32(regs.O_RESET_SC) - dev.regs.pio.ctrl.w(ctrl) - if dev.err != nil { - return fmt.Errorf("eda: could not reset slow-control: %w", dev.err) - } - - time.Sleep(1 * time.Microsecond) - - return nil -} - -func (dev *Device) hrscStartSC(rfm int) error { - var ( - mask uint32 - ) - - switch rfm { - case 0: - mask = regs.O_START_SC_0 - case 1: - mask = regs.O_START_SC_1 - case 2: - mask = regs.O_START_SC_2 - case 3: - mask = regs.O_START_SC_3 - default: - return fmt.Errorf("eda: start slow-control: invalid RFM id %d", rfm) - } - - ctrl := dev.regs.pio.ctrl.r() - ctrl |= mask - dev.regs.pio.ctrl.w(ctrl) - if dev.err != nil { - return fmt.Errorf( - "eda: could read/write pio ctrl mask=0x%x: %w", - mask, - dev.err, - ) - } - - time.Sleep(1 * time.Microsecond) - - ctrl = dev.regs.pio.ctrl.r() - ctrl &= ^mask - dev.regs.pio.ctrl.w(ctrl) - if dev.err != nil { - return fmt.Errorf( - "eda: could read/write pio ctrl ^mask=0x%x: %w", - mask, - dev.err, - ) - } - - return nil -} - -func (dev *Device) hrscSCDone(rfm int) bool { - var mask uint32 - switch rfm { - case 0: - mask = regs.O_SC_DONE_0 - case 1: - mask = regs.O_SC_DONE_1 - case 2: - mask = regs.O_SC_DONE_2 - case 3: - mask = regs.O_SC_DONE_3 - default: - panic(fmt.Errorf("eda: invalid RFM ID=%d", rfm)) - } - - return (dev.regs.pio.state.r() & mask) == mask -} - -func bit32(word, digit uint32) uint32 { - return (word >> digit) & 0x1 -} - -func bitU64(v uint64, pos uint32) uint8 { - o := v & uint64(1<> 16)) -// wU16(uint16(bcid24 & 0xffff)) -// // unused "nb-lines" -// wU8(0xff) -// -// // HR DAQ chunk -// var ( -// lastHR = -1 -// hrID int -// ) -// for !dev.daqFIFOEmpty(rfm) { -// // read HR ID -// id := dev.regs.fifo.daq[rfm].r() -// hrID = int(id >> 24) -// // insert trailer and header if new hardroc ID -// if hrID != lastHR { -// if lastHR >= 0 { -// wU8(0xA3) // HR trailer -// } -// wU8(0xB4) // HR header -// } -// wU32(id) -// for i := 0; i < 4; i++ { -// wU32(dev.regs.fifo.daq[rfm].r()) -// n++ -// } -// lastHR = hrID -// } -// wU8(0xA3) // last HR trailer -// wU8(0xA0) // DIF DAQ trailer -// wU16(0xC0C0) // fake CRC -// -// // on-line monitoring -// nRAMUnits := n / 5 -// -// dev.daq.cycleID[rfm]++ -// return nRAMUnits -// } - func (dev *Device) daqWriteDIFData(w io.Writer, slot int) { var ( rfm = &dev.daq.rfm[slot] - fifo = &dev.regs.fifo.daq[slot] + fifo = &dev.brd.regs.fifo.daq[slot] wU8 = func(v uint8) { rfm.buf[0] = v _, _ = w.Write(rfm.buf[:1]) @@ -1845,7 +385,7 @@ func (dev *Device) daqWriteDIFData(w io.Writer, slot int) { // offset if rfm.cycle == 0 { - rfm.bcid = dev.cntBCID48LSB() - dev.cntBCID24() + rfm.bcid = dev.brd.cntBCID48LSB() - dev.brd.cntBCID24() } bcid48Offset := rfm.bcid @@ -1854,18 +394,18 @@ func (dev *Device) daqWriteDIFData(w io.Writer, slot int) { wU8(dev.daq.rfm[slot].id) // counters wU32(rfm.cycle + 1) // FIXME(sbinet): off-by-one ? - wU32(dev.cntHit0(slot)) + wU32(dev.brd.cntHit0(slot)) //wU32(dev.cntHit1(rfm)) // FIXME(sbinet): hack wU32(rfm.cycle + 1) // FIXME(sbinet): hack (and off-by-one?) // assemble and correct absolute BCID - bcid48 := uint64(dev.cntBCID48MSB()) + bcid48 := uint64(dev.brd.cntBCID48MSB()) bcid48 <<= 32 - bcid48 |= uint64(dev.cntBCID48LSB()) + bcid48 |= uint64(dev.brd.cntBCID48LSB()) bcid48 -= uint64(bcid48Offset) // copy frame wU16(uint16(bcid48>>32) & 0xffff) wU32(uint32(bcid48)) - bcid24 := dev.cntBCID24() + bcid24 := dev.brd.cntBCID24() wU8(uint8(bcid24 >> 16)) wU16(uint16(bcid24 & 0xffff)) // unused "nb-lines" @@ -1879,7 +419,7 @@ func (dev *Device) daqWriteDIFData(w io.Writer, slot int) { wU8(0xB4) // HR header const nWordsPerHR = 5 - n := int(dev.daqFIFOFillLevel(slot) / nWordsPerHR) + n := int(dev.brd.daqFIFOFillLevel(slot) / nWordsPerHR) for i := 0; i < n; i++ { // read HR ID diff --git a/eda/pio_test.go b/eda/pio_test.go index 8169743..18a9be7 100644 --- a/eda/pio_test.go +++ b/eda/pio_test.go @@ -22,9 +22,9 @@ func TestReadConf(t *testing.T) { hrID uint32 ) dev.cfg.hr.db = newDbConfig() - dev.cfg.hr.data = dev.cfg.hr.buf[4:] + dev.brd = newBoard(dev.msg) - err := dev.hrscReadConf("testdata/conf_base.csv", hrID) + err := dev.brd.hrscReadConf("testdata/conf_base.csv", hrID) if err != nil { t.Fatalf("could not read config file: %+v", err) } @@ -40,7 +40,7 @@ func TestReadConf(t *testing.T) { {addr: 871, want: 1}, } { t.Run(fmt.Sprintf("addr=%d", tc.addr), func(t *testing.T) { - got := dev.hrscGetBit(hrID, tc.addr) + got := dev.brd.hrscGetBit(hrID, tc.addr) if got != tc.want { t.Fatalf("invalid value: got=0x%x, want=0x%x", got, tc.want) } @@ -102,14 +102,14 @@ func TestReadConf(t *testing.T) { fname = filepath.Join(tmp, tc.name+".txt") ) dev.cfg.hr.db = newDbConfig() - dev.cfg.hr.data = dev.cfg.hr.buf[4:] + dev.brd = newBoard(dev.msg) err := os.WriteFile(fname, []byte(tc.data), 0644) if err != nil { t.Fatalf("could not create tmp file: %+v", err) } - err = dev.hrscReadConf(fname, hrID) + err = dev.brd.hrscReadConf(fname, hrID) if err == nil { t.Fatalf("expected an error") } @@ -125,9 +125,9 @@ func TestReadConfHR(t *testing.T) { t.Run("valid-hr", func(t *testing.T) { var dev Device dev.cfg.hr.db = newDbConfig() - dev.cfg.hr.data = dev.cfg.hr.buf[4:] + dev.brd = newBoard(dev.msg) - err := dev.hrscReadConfHRs("testdata/hr_sc_385.csv") + err := dev.brd.hrscReadConfHRs("testdata/hr_sc_385.csv") if err != nil { t.Fatalf("could not read hr-sc cfg: %+v", err) } @@ -150,7 +150,7 @@ func TestReadConfHR(t *testing.T) { {hr: 7, addr: 871, want: 1}, } { t.Run(fmt.Sprintf("hr=%d-addr=%d", tc.hr, tc.addr), func(t *testing.T) { - got := dev.hrscGetBit(tc.hr, tc.addr) + got := dev.brd.hrscGetBit(tc.hr, tc.addr) if got != tc.want { t.Fatalf("invalid value: got=0x%x, want=0x%x", got, tc.want) } @@ -225,14 +225,14 @@ func TestReadConfHR(t *testing.T) { fname = filepath.Join(tmp, tc.name+".txt") ) dev.cfg.hr.db = newDbConfig() - dev.cfg.hr.data = dev.cfg.hr.buf[4:] + dev.brd = newBoard(dev.msg) err := os.WriteFile(fname, []byte(tc.data), 0644) if err != nil { t.Fatalf("could not create tmp file: %+v", err) } - err = dev.hrscReadConfHRs(fname) + err = dev.brd.hrscReadConfHRs(fname) if err == nil { t.Fatalf("expected an error") } @@ -248,9 +248,9 @@ func TestReadWriteConfHR(t *testing.T) { var dev Device dev.cfg.hr.db = newDbConfig() - dev.cfg.hr.data = dev.cfg.hr.buf[4:] + dev.brd = newBoard(dev.msg) - err := dev.hrscReadConfHRs("testdata/hr_sc_385.csv") + err := dev.brd.hrscReadConfHRs("testdata/hr_sc_385.csv") if err != nil { t.Fatalf("could not read hr-sc cfg: %+v", err) } @@ -261,7 +261,7 @@ func TestReadWriteConfHR(t *testing.T) { } _ = tmp.Close() - err = dev.hrscWriteConfHRs(tmp.Name()) + err = dev.brd.hrscWriteConfHRs(tmp.Name()) if err != nil { t.Fatalf("could not write hr-sc cfg: %+v", err) } diff --git a/eda/register.go b/eda/register.go index c1b21a5..b7cf8d0 100644 --- a/eda/register.go +++ b/eda/register.go @@ -16,12 +16,17 @@ type rwer interface { io.WriterAt } +type rw32 interface { + readU32(r io.ReaderAt, offset int64) uint32 + writeU32(w io.WriterAt, offset int64, v uint32) +} + type reg32 struct { r func() uint32 w func(v uint32) } -func newReg32(dev *Device, rw rwer, offset int64) reg32 { +func newReg32(dev rw32, rw rwer, offset int64) reg32 { return reg32{ r: func() uint32 { return dev.readU32(rw, offset) @@ -35,14 +40,12 @@ func newReg32(dev *Device, rw rwer, offset int64) reg32 { type hrCfg struct { rw rwer addr int64 - size int64 } -func newHRCfg(dev *Device, rw rwer, offset int64) hrCfg { +func newHRCfg(rw rwer, offset int64) hrCfg { return hrCfg{ rw: rw, addr: offset, - size: 4 + nHR*nBytesCfgHR, } } @@ -56,6 +59,9 @@ func (hr *hrCfg) r(i int) byte { } func (hr *hrCfg) w(p []byte) (int, error) { + if len(p) > szCfgHR { + return 0, io.ErrShortBuffer + } n, err := hr.rw.WriteAt(p, hr.addr) return int(n), err } @@ -64,7 +70,7 @@ type daqFIFO struct { pins [6]reg32 } -func newDAQFIFO(dev *Device, rw rwer, offset int64) daqFIFO { +func newDAQFIFO(dev rw32, rw rwer, offset int64) daqFIFO { const sz = 4 // sizeof(uint32) return daqFIFO{ pins: [6]reg32{ diff --git a/eda/standalone.go b/eda/standalone.go index 052d1ae..7381835 100644 --- a/eda/standalone.go +++ b/eda/standalone.go @@ -70,14 +70,14 @@ func (srv *standalone) runDAQ() error { // --- init FPGA --- // reset FPGA and set clock. - err = dev.syncResetFPGA() + err = dev.brd.syncResetFPGA() if err != nil { return fmt.Errorf("eda: could not reset FPGA: %w", err) } time.Sleep(2 * time.Microsecond) cnt := 0 max := 100 - for !dev.syncPLLLock() && cnt < max { + for !dev.brd.syncPLLLock() && cnt < max { time.Sleep(10 * time.Millisecond) cnt++ } @@ -85,28 +85,28 @@ func (srv *standalone) runDAQ() error { return fmt.Errorf("eda: could not lock PLL") } - dev.msg.Printf("pll lock=%v\n", dev.syncPLLLock()) + dev.msg.Printf("pll lock=%v\n", dev.brd.syncPLLLock()) // activate RFMs for _, rfm := range dev.rfms { - err = dev.rfmOn(rfm) + err = dev.brd.rfmOn(rfm) if err != nil { return fmt.Errorf("eda: could not activate RFM=%d: %w", rfm, err) } - err = dev.rfmEnable(rfm) + err = dev.brd.rfmEnable(rfm) if err != nil { return fmt.Errorf("eda: could not enable RFM=%d: %w", rfm, err) } } time.Sleep(1 * time.Millisecond) - ctrl := dev.regs.pio.ctrl.r() + ctrl := dev.brd.regs.pio.ctrl.r() if dev.err != nil { return fmt.Errorf("eda: could not read control pio: %w", dev.err) } dev.msg.Printf("control pio=0x%x\n", ctrl) - err = dev.syncSelectCmdSoft() + err = dev.brd.syncSelectCmdSoft() if err != nil { return fmt.Errorf("eda: could select cmd-soft mode: %w", err) } @@ -129,29 +129,29 @@ func (srv *standalone) runDAQ() error { cycleID := 0 for _, rfm := range dev.rfms { - err = dev.daqFIFOInit(rfm) + err = dev.brd.daqFIFOInit(rfm) if err != nil { return fmt.Errorf("eda: could not initialize DAQ FIFO (RFM=%d): %w", rfm, err) } } - err = dev.cntReset() + err = dev.brd.cntReset() if err != nil { return fmt.Errorf("eda: could not reset counters: %w", err) } - err = dev.syncResetBCID() + err = dev.brd.syncResetBCID() if err != nil { return fmt.Errorf("eda: could not reset BCID: %w", err) } - err = dev.syncStart() + err = dev.brd.syncStart() if err != nil { return fmt.Errorf("eda: could not start acquisition: %w", err) } - dev.msg.Printf("sync-state: %[1]d 0x%[1]x\n", dev.syncState()) + dev.msg.Printf("sync-state: %[1]d 0x%[1]x\n", dev.brd.syncState()) - err = dev.syncArmFIFO() + err = dev.brd.syncArmFIFO() if err != nil { return fmt.Errorf("eda: could not arm FIFO: %w", err) } @@ -168,7 +168,7 @@ readout: // ramloop: // for { - // switch state := dev.syncState(); { + // switch state := dev.brd.syncState(); { // case state == regs.S_RAMFULL: // // ok. // dev.msg.Printf("ramfull") @@ -179,7 +179,7 @@ readout: // } // } - err = dev.syncRAMFullExt() + err = dev.brd.syncRAMFullExt() if err != nil { return fmt.Errorf("eda: could not sync for RAMFULL-EXT: %w", err) } @@ -187,7 +187,7 @@ readout: // wait until data is ready. fifo: for { - switch state := dev.syncState(); state { + switch state := dev.brd.syncState(); state { case regs.S_FIFO_READY: break fifo default: @@ -204,12 +204,12 @@ readout: for _, rfm := range dev.rfms { dev.daqWriteDIFData(out, rfm) } - err = dev.syncAckFIFO() + err = dev.brd.syncAckFIFO() if err != nil { return fmt.Errorf("eda: could not ACK FIFO: %w", err) } - err = dev.syncStart() + err = dev.brd.syncStart() if err != nil { return fmt.Errorf("eda: could not start ACQ (cycle=%d): %w", cycleID, err) } @@ -217,7 +217,7 @@ readout: cycleID++ } - err = dev.syncStop() + err = dev.brd.syncStop() if err != nil { return fmt.Errorf("eda: could not stop ACQ: %w", err) }