;############################################################################## ;# ;# Rudimentary Readout Program for TRAP3 chip ;# ;# Marcus Gutfleisch, Venelin Angelov ;# Universitaet Heidelberg, Kirchhoff-Institut fuer Physik ;# ;# $Id$: ;# ;############################################################################## #inc ;#def test_peLUT = 1; replace the calculated address with c10 of the corresponding CPU ; put in C10CPUn the value, 0x100 + byte_offset #ifdef cpu0 #INF Start the assembler program compilation for CPU0 #endif #ifdef cpu1 #INF Start the assembler program compilation for CPU1 #endif #ifdef cpu2 #INF Start the assembler program compilation for CPU2 #endif #ifdef cpu3 #INF Start the assembler program compilation for CPU3 #endif ;#def debug_par = 1; store temporary the calculated pad_row_n, yoffs, scale_y, scale_d to C11CPUn ; #def delay_hcm = 350 ; #def Q2Tracklet = 1; put the scaled Q1/N in the tracklet, otherwise use the LUT ; #def trckl_delay = 7; ; #def AVOID_DTR = 1; ; define at which event (full readout) to send the configuration => moved to the run_parameters.tcs! ;#def ConfigEvent = 1; ;#def testmode_t = 1 ; for tracklets - not up to date, please do not use it! ; major version bits ; - 1 bit as ZS flag ; - 1 bit as tracklet disable flag ; - 1 bit for ADC data/test pattern ; if ZS then ; - 1 bit: suppress sending of empty header/mask ; - 2 bits: 01/10/11: send every 128/256/1024 events complete ADC data ; else ; if Testpattern Mode then ; - 3 bits to define the pattern ; else ; - send full data, 1 bit: accumulate sum(ADC) and sum(ADC**2) ; ... ; ; Numeric constants ; tracklet calculation: ; #def nachkommast = 5 ; #def nachkommast_s= 2 ; #def ndrift_dp = 5 ; this must be so initialised by SCSN! ; #def rounding_add = 17; 2**(nachkommast-1)+1 ; #def pad_ext = 13; 8 + nachkommast. #def MSK_SLOPE = 0x0FF ; slope is 8-bit signed in the tracklet #def LEN_SLOPE = 8 ; slope is 8-bit signed in the tracklet ; #def POS_MAX_ABS= 1023 ; position is 11-bit signed in the tracklet and will be limit to +/- 1023 #ifneq DYN_FP_Q, 1 ; scale the charges by multiplying with a fixed number #def MSK_Q0Q1 = 0x07F ; Q0 and Q1 are 7-bit unsigned in the tracklet #def LEN_Q0Q1 = 7 ; Q0 and Q1 are 7-bit unsigned in the tracklet #def MSK_Q2 = 0x03F ; Q2 is 6-bit unsigned in the tracklet #def MAX_Q2 = 0x03E ; Q2 is 6-bit unsigned in the tracklet limited to 0x6E! #def LEN_Q2 = 6 ; Q2 is 6-bit unsigned in the tracklet #endif ; Q-word is 20-bit, independently on the art of compression #def MSK_LPID = 0xFFF ; 12-bit from the Q-word are in the tracklet, this is the mask #def LEN_LPID = 12 ; 12-bit from the Q-word are in the tracklet, this is the length #def CH_NR_NO_TRCK = 23 ; channel nr used to mark no tracklet, in hardware is 31, but it will be ; replaced in software with 23 for practical reasons ; the constants here are used to move the corresponding bit to carry ; the flags should be used as conditional compile options! ; #def TPATTflag = 7; test pattern flag (raw data) in bit 6 ; #def ZSflag = 6; zero suppression flag in bit 5 ; #def TDISflag = 5; disable tracklets flag in bit 4 ; #def COSMflag = 4; cosmic trigger flag, bit 3 ; #def TR_no_empty = 3; suppress sending of empty header in tracklet mode ; #def ZS_no_empty = 1; suppress sending of empty header/mask, OPTs[0] ; if so finally, some instructions can be optimized #def OPTs = 0; options, 0..15 in bits 3..0, now used 2..0 only #ifdef cpu0 #def EBR_CH_INI = 0 ; cpu0 reads channels 0 to 4 #def EBR_CH_MSK = b011111 ; cpu0 reads 5 channels #def COS_BEG_CH = 1 ; start channel in cosmic mode, may be from 0? #def COS_END_CH = 4 ; end channel in cosmic mode #def RAW_END_BITS = b11 ; the two LSBits in raw data readout of the first channel sent by this CPU #endif #ifdef cpu1 #def EBR_CH_INI = 5 ; cpu1 reads channels 5 to 9 #def EBR_CH_MSK = b011111 ; cpu1 reads 5 channels #def COS_BEG_CH = 5 ; start channel in cosmic mode #def COS_END_CH = 8 ; end channel in cosmic mode #def RAW_END_BITS = b10 ; the two LSBits in raw data readout of the first channel sent by this CPU #endif #ifdef cpu2 #def EBR_CH_INI = 10 ; cpu2 reads channels 10 to 14 #def EBR_CH_MSK = b011111 ; cpu2 reads 5 channels #def COS_BEG_CH = 9 ; start channel in cosmic mode #def COS_END_CH = 13 ; end channel in cosmic mode #def RAW_END_BITS = b11 ; the two LSBits in raw data readout of the first channel sent by this CPU #endif #ifdef cpu3 #def EBR_CH_INI = 15 ; cpu3 reads channels 15 to 20 #def EBR_CH_MSK = b111111 ; cpu3 reads 6 channels #def COS_BEG_CH = 14 ; start channel in cosmic mode #def COS_END_CH = 18 ; end channel in cosmic mode #def RAW_END_BITS = b10 ; the two LSBits in raw data readout of the first channel sent by this CPU #endif ; precise later, may be not needed? #def DELAY_NO_TR_MASK = 160; #def DELAY_NO_TR_FUNC = 160; ; #def EvnCntL0 = 1 ; ????? #def FIT_SVN_REV = $Rev$; ; ASM_SVN_REV is internally defined in the assembler, its own revision ; all run control parameters and configuration register values ; Tom: only load run_parameters.asm if they have not been set yet #ifdef RUNPAR_ASM_FILE #inc RUNPAR_ASM_FILE #else #inc "run_parameters.asm" #endif ; all defined addresses : in DMEM, DBANK and configuration space #inc "fit_addresses.asm" ; CPU registers and constants #def rstack = r8 ; program counter stack (depth=1) #def rstack2 = r10 ; program counter stack (depth=2) #def rio = r14 ; local I/O auto incrementer register #def charge_0 = g0 ; intermediate charge prepared for tracklet #def charge_1 = g1 ; intermediate charge prepared for tracklet #def charge_2 = g2 ; intermediate charge prepared for tracklet #def charge_3 = g3 ; used only in cosmic mode ; #def mask_1FFF = g3 ; mask for the offset #def adc_ch_msk_0 = g4 ; used as channel mask or channel nr. #def adc_ch_msk_1 = g5 #def adc_ch_msk_2 = g6 #def adc_ch_msk_3 = g7 ; used as global adc mask #def trackl_0 = g8 ; the prepared tracklet word by CPU0 #def trackl_1 = g9 ; ... 1 #def trackl_2 = g10 ; ... 2 #def scale_y = g11 ; 0.162354 = 0x29900000 / 2^32 0xC023 0x08C #def offs_y = g12 ; functional code (copied from DMEM), better not to use! #def scale_d = g13 ; 0.185547 = 0x2F800000 / 2^32 0xC024 0x090 #def scale_q = g14 ; in case of simple charge scaling ; #def func_code = g14 ; functional code (copied from DMEM), better not to use! ; TEMP !!! ; #def nwords = g15 ; number of 32-bit words when nsamples > 32 ; #def yoffs = g9; y-coord offset 0xC021 0x084 ; #def defl_cor = g10; deflection corr 0xC022 0x088 ; #def nsamples = c13 ; number of ADC samples per pad ; better not to used the CPU cosntants as constants, but to refresh them each time before usage! #def EventCounter = c12 ; event counter #def ChipPOS = c14 ; Chip Position for Header as a CPU constant #def h_0 = c15 ; half-chamber header 0 #ifdef cpu0 #def trackl_i = trackl_0 ; final tracklet #def charge_i = charge_0 ; intermediate charge prepared for tracklet #def adc_ch_msk = adc_ch_msk_0 ; used as channel mask or channel nr. #endif #ifdef cpu1 #def trackl_i = trackl_1 ; final tracklet #def charge_i = charge_1 ; intermediate charge prepared for tracklet #def adc_ch_msk = adc_ch_msk_1 ; used as channel mask or channel nr. #endif #ifdef cpu2 #def trackl_i = trackl_2 ; final tracklet #def charge_i = charge_2 ; intermediate charge prepared for tracklet #def adc_ch_msk = adc_ch_msk_2 ; used as channel mask or channel nr. #endif #ifdef cpu3 #def adc_ch_msk = adc_ch_msk_3 ; used in the ZS part #def charge_i = charge_3 ; used only in cosmic mode #endif ;############################################################################## ;# ;# 0x000: Infinite Loop at Instruction Memory Reset Address ;# The CPUs should never come here, as they are started with some high-level interrupt ;# normally to run a specific task! ;# ;############################################################################## ORG 0x0; lpw: nop nop nop lgio 0, lpcount0 jmpr cc_busy, 0 lpio GBUSR0, r1 add r1, 1, r1 iext lpcount0 sgio r1, lpcount0 jmpr cc_uncond, 0 nop lpw2: nop nop lgio 0, lpcount1 jmpr cc_busy, 0 lpio GBUSR0, r1 add r1, 1, r1 iext lpcount1 sgio r1, lpcount1 jmpr cc_uncond, 0 nop ;############################################################################## ;# ;# 0x10: Interrupt Clear Jump Address ;# ;############################################################################## ; In IRQ CLR some data are copied from DMEM to GRF ; 1) read pad_row_n (pad row number) from 0xC020 and put in g8 ; 2) read yoffset (y-coordinate offset) from 0xC021 and put in g9 ; 3) read defl_cor (deflection correction constant) from 0xC022 and put in g10 ; 4) read scale_y : 0.162354 = 0x29900000 / 2^32 from 0xC023 and put in g11 ; 5) read scale_d : 0.185547 = 0x2F800000 / 2^32 from 0xC024 and put in g12 ORG 0x20; clr: #ifdef cpu0 mov ARBTIM_VAL, r1 sgio r1, ARBTIM nop #endif #ifdef cpu1 mov DMDELA_VAL, r1 iext DMDELA sgio r1, DMDELA #endif #ifdef cpu2 mov DMDELS_VAL, r1 iext DMDELS sgio r1, DMDELS #endif #ifdef cpu3 mov CMD_EXT_CLR, r0 ; finish the clear state sgio r0, SMCMD ; as soon as possible nop #endif clr_endloop: sem 0xFFFF ; use sync command to save power syn nop jmp cc_uncond, clr_endloop nop ;############################################################################## ;# ;# 0x200: Interrupt Tracklet Processing Jump Address ;# ;############################################################################## ORG 0x40; #inc "boot.asm" ORG 0x100; ; HCM and BM tracklet program doesn't depend on the mode? ; may be in tp mode some other header? #inc "fit_tracklets_mrg.asm" ORG 0x200; ; do we need a special merger code in cosmic mode??? #ifeq TRACKLETS_MODE, TRACKLETS_COS_MODE #inc "fit_cosmic.asm" #endif #ifeq TRACKLETS_MODE, TRACKLETS_3Q_MODE #inc "fit_tracklets.asm" #endif #ifeq TRACKLETS_MODE, TRACKLETS_DIS_MODE #inc "fit_tracklets_tp.asm" #endif #ifeq TRACKLETS_MODE, TRACKLETS_TPT_MODE #inc "fit_tracklets_tp.asm" #endif ;############################################################################## ;# ;# 0x400: Interrupt Raw Data Transmission Jump Address ;# ;############################################################################## ORG 0x400 ; all MCMs, first load some constants from DB and jump to the specific BM and HCM if necessary raw: ; read some important parameters from hamming protected DBANK #ifdef cpu0 mov cmd_CPU_done, r0 ; CPU0 indicates upcoming data transmission sgio r0, SMCMD; jmpr cc_busy, 0 ; wait until IO bus is ready, this means that the requests of the other ; CPUs are ready, as they are read reqs with higher priorities #endif #ifdef cpu3 lgio 1, ChipPOS_DB sem 1 nop #endif #ifdef cpu2 ; the event counter is in c12, but the hamming protected version is in DBANK lgio 1, EvtCtr_DB sem 1 nop #endif #ifdef cpu1 iext h_0_DB lgio 1, h_0_DB sem 1 #ifdef OVERWR_UPPER_HC0 mov 0xFFF, r0 ; mask for the lower 12 bits of h0, used to extract the position dependent part mova HC_0_CNF, r1 ; the upper part of the h0, position independent and hard coded sll 12, r1, r1 ; move to bit 12, later will be shifted 2 bits more to the left #endif #endif #ifdef cpu0 mov 0, g0 ; release cpu1..3, as sgio has lower priority than lgio, ; the 3 reads started by the other CPUs should be done! #else syn ; cpu1..3 wait #endif #ifdef cpu3 lpio GBUSR1, r3 sgio r3, ChipPOS_ConIO jmpr cc_busy, 0 #else sem 1 #endif #ifdef cpu2 lpio GBUSR1, r3 sgio r3, EvtCtr_ConIO #endif #ifdef cpu1 lpio GBUSR1, r3 ; get the h0 from DB, here without the two LSBits, which are constant. Only the lower 12 bits are used #ifdef OVERWR_UPPER_HC0 and r3, r0, r3 ; extract only the lower 12 bits or r3, r1, r3 ; set the upper bits directly from the ASM constant, position independent #endif sgio r3, h_0_ConIO ; store to C15 to be used later #endif #ifdef cpu3 swp r3, g0 ; release cpu0..2 #else syn ; wait on cpu3 #endif ; now the chip position, H_0 and software event counter are updated in the const regs ; in addition, g0 contains the swapped ChipPos, so the readout flags are in bits 3..0 ; each CPU can check what to do ; up to here all MCMs run the same code swp ChipPOS, r2 ; load NI & SCSN readout flag in r2 in bits 3..0 ; bits 19..16, after swapping 3..0: hh mm - hh - set when HCM (1100), mm - set when normal MCM (0011) ; so when 00 00 - BM andt r2, 3 ; bits 0..1 are normal read flags, if both 0 => BM or HCM jmp cc_zero, raw_hcm_bm ; HCM or BM ; from here continue with normal readout ; this part is common for all 3 modes: FULL, ZS, TP, with variations in ZS for up to 30 or > 30 samples raw_adc_rout: #ifdef ConfigEvent ; check if this is the first event mov EventCounter, r0 ; provided this option is enabled #ifdef ConfEvMask mova ConfEvMask, r1 and r0, r1, r0 #endif cmpa r0, ConfigEvent jmp cc_eq, raw_send_conf #endif #ifdef cpu3 #ifeq EBSIM_VAL, 0 ; 0 means simulation - work is preloaded ADC data mov 1, r0 ; in case of simulation mode (work with preloaded ADC data) iext EBSIM ; the mode must be switched off in order to read sgio r0, EBSIM ; the event buffers properly! It will be restored at the end. #endif #endif #ifdef cpu1 ; this CPU helps to CPU0 to prepare the event counter field in the MCM header shl 12, EventCounter, r0 ; EC << 12, so we have the 20 LSBits of the EC (at 31..12) + 12x'0' slr 8, r0, g5 ; now the 20 EC bits are at positions 23..4 #endif #ifdef cpu0 ; prepare the MCM header mov 0x80, r0 ; 1 << 7 or r0, ChipPOS, r0 ; combine chip header, eventually ChipPos has some bits right from ; position 7 set, but they will be ignored later! shl 12, r0, r0 shl 12, r0, r0 ; 1 & ChipPOS(7) & 24 x '0' mov 0xC, r1 or r0, r1, r0 ; 1 & ChipPOS(7) & 20 x '0' & "1100" ; use g5 which was prepared before by CPU1 or r0, g5, r11 ; 1 & ChipPOS(7) & EventCounter(20) & "1100" ; do not send the MCM Header now ; nop #endif #ifeq RAW_RDOUT_MODE, RAW_RDOUT_TP #inc "fit_raw_tp.asm" ; RAW_RDOUT_MODE = RAW_RDOUT_TP #endif #ifeq RAW_RDOUT_MODE, RAW_RDOUT_ZS #inc "fit_raw_zs.asm" ; RAW_RDOUT_MODE = RAW_RDOUT_ZS #endif #ifeq RAW_RDOUT_MODE, RAW_RDOUT_FULL #inc "fit_raw_full.asm" ; RAW_RDOUT_MODE = RAW_RDOUT_FULL #endif raw_end_ni_tmsn: ;############################################## ;# CPU3: Increment Event Counter ;############################################## #ifdef cpu3 mov EventCounter, r0 add r0, 1, r0 jmpr cc_busy, 0 iext EvtCtr_DB sgio r0, EvtCtr_DB #ifeq EBSIM_VAL, 0 ; 0 means simulation - working with preloaded ADC data ; => in this case we wrote 1 in order to read the ADC values mov EBSIM_VAL, r0 ; ... and now have to restore the EBSIM jmpr cc_busy, 0 ; added by Tom 2008-10-09 iext EBSIM ; which was switched off (1) sgio r0, EBSIM ; in order to read the event buffers #endif #endif ;############################################## ;# NI&SCSN transfer end marker ;############################################## ; refresh the IRQ ACQ start address, it makes no sense to do this in the ACQ part mov acq, r0 jmpr cc_busy, 0 sgio r0, IA_ACQ; mova NSIG_RR_VAL, r0 ; load the endmaker rr spio r0, NODP #ifneq RAW_SCSN, RAW_SCSN_DIS sra+ r0 #endif ;############################################## ;# switch off own clock after transfer ;############################################## raw_coff: mov 0, r0 jmpr cc_busy, 0 sgio r0, clk_onoff ; jmpr cc_busy, 0 jmp cc_uncond, clr_endloop nop ; should not happen jmp cc_uncond, raw_coff nop ;############################################## ;# END data transfer loop ;############################################## nop #inc "fit_raw_hcm_bm.asm" ORG 0x700 ; Style recommendations ; ; 1) use include for the different parts of the CPU program ; ; 2) use prefix in the labels, e.g. ; ; -- start of the acq subroutine ; acq: ... ; ... ; acq_store: ; ... ; acq_delay: ; ... ; -- end of the acq subroutine ; ADDITIONAL PROGRAMS ; ; GENERAL RULES ; ; 1) The programs do not use any programmable constants ; 2) CPU3 is never used ; 3) The programs use for data exchange a small region in the DBANK ; or DMEM or IMEM3, accessible through GIO. The start addresses ; must be defined in the main program as follows: ; ; srv_command - command from the SCSN master, code of the service operation ; srv_indata - input data, stored by the SCSN master ; srv_outdata - output data, stored by the TRAP CPU ; ; 4) The programs may modify all registers (privat and global) ; ; 5) The programs end with command low power to the global state machine. ; This can be changed later - may be is reasonable to have the option for normal ; IRT (interrupt return) or just jump to some address. ; ; 6) By default the configuration of the main program enables interrupt TST for CPU0,1,2 ; but sets the start address to a small assembler code to switch the power off ; ; 7) When the SCSN master wants to start some service program, it must send the ; TRAP to the low power state, then modify the IVT (interrupt vector table) ; - store the correct start address of the service program. Then the SCSN master ; stores its request at srv_command and activates IRQ TST. The SCSN master checks ; the state of the TRAP and sends it to low power state if a timeout occurs. ; After finishing the service operation (which can consist of many service requests), ; the SCSN master restores the IVT to the original. ; J2C #ifdef cpu0 ;#inc "j2c.asm" tst: jmpr cc_uncond, 0 #endif #ifdef cpu1 ;#inc "I2C.asm" #endif ; send the packed configuration as a black event ; ORG 0x900 ; send the MCM header raw_send_conf: #ifdef cpu0 iext CHIPID lgio 0, CHIPID sll 7, 1, r0 or r0, ChipPOS, r0 ; combine chip header sll 10, r0, r0 sll 10, r0, r0 ; 1 & ChipPOS(7) & 24 x '0' mov 0xC, r1 jmpr cc_busy, 0 lpio GBUSR0, r2 or r0, r2, r0 ; 1 & ChipPOS(7) & ChipID sll 4, r0, r0 or r0, r1, r0 ; 1 & ChipPOS(7) & ChipId(20) & "1100" spio r0, NODP #endif jmp cc_uncond, raw_send_cnf ; jump to the include file #inc "pack_conf.asm" ORG 0xB00 ;#inc "conf_mann.asm" org 0xB80 ;#inc "adc2cpu.asm" ORG 0xC00 #inc "fit_load_dm_par.asm" org 0xFFE jmp cc_uncond, lpw2 jmp cc_uncond, lpw2