;############################################################################## ;# ;# Rudimentary Readout Program for TRAP3 chip ;# ;# Marcus Gutfleisch, Venelin Angelov ;# Universitaet Heidelberg, Kirchhoff-Institut fuer Physik ;# ;# $Id: fitred.asm 2666 2009-03-06 07:07:25Z angelov $: ;# ;############################################################################## #inc ; #def set_NFSM_acq = 1 ; #def delay_hcm = 350 ; #def FIT2DM = 1; store the fitregisters in DMEM #def trckl_delay = 13; ; #def AVOID_DTR = 1; ; define at which event (full readout) to send the configuration ;#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) ; ... ; ; -------------------- ; Ressources in TRAP: ; -------------------- ; DMEM (without BM/HCM chips) ; -------------------- ; Word-Addr Byte-Addr Used for Copied to: ; ; 0..0x01F 0..0x07C 2**31/N LUT - ; 0x020 0x080 pad row number g8 ; 0x021 0x084 y-coord offset g9 ; 0x022 0x088 deflection corr g10 ; 0x023 0x08C scale_y g11 ; 0x024 0x090 scale_d g12 ; 0x025 0x094 ndrift for fitprogram g13 ; 0x030..0x053 0x0C0..0x14C deflection range table ; ; 0x058..0x096 0x160..0x258 ADC statistics, see below: ; 0x058+3*ch 0x160+12*ch ch=0..20, Sum(ADC) ; 0x059+3*ch 0x164+12*ch ch=0..20, Sum(ADC**2), lower 32 bits ; 0x05A+3*ch 0x168+12*ch ch=0..20, Sum(ADC**2), higher 32 bits ; 0x100..0x13F 0x400..0x4FC fit register for debugging ; 0x140..0x143 0x500..0x50C tracklets for scsn readout ; or ; 0x100..0x2FF 0x400..0xBFF e/pi probability LUT (not implemented) ; 0x300..0x33F 0xC00..0xCFF ADC data of CPU0 for scsn readout ; 0x340..0x37F 0xD00..0xDFF ADC data of CPU1 for scsn readout ; 0x380..0x3BF 0xE00..0xEFF ADC data of CPU2 for scsn readout ; 0x3C0..0x3FF 0xF00..0xFFF ADC data of CPU3 for scsn readout ; -------------------- ; DBANK ; -------------------- ; Address Used for ; ; 0xF000..0xF0DF packed configuration, used for refreshing ; 0xF0E0..0xF0FF packed configuration and single GIO instructions used for init ; 0xF0E0..0xF0FF MCM3,7,11,15: mailbox, used for service routines, like i2c, j2c and more ; 0xF0F0..0xF0FF HCM only: headers for SCSN readout ; -------------------- ; Constants ; -------------------- ; CPU0 ; 8 : the start address in GIO of the packed configuration, used in unpack ; 9 : counter for L0A without tracklet, CPU0 ; 10 : temporary used ifdef set_NFSM_acq ; 11 : - ; -------------------- ; CPU1 ; 8 : HCM only, used to detect the first irq_clr ; 9 : counter for L0A without tracklet, CPU1 ; 10 : - ; 11 : - ; -------------------- ; CPU2 ; 8 : - ; 9 : counter for L0A without tracklet, CPU2 ; 10 : - ; 11 : - ; -------------------- ; CPU3 ; 8 : programmable network interface readout delay ; 9 : counter for L0A without tracklet, CPU3 ; 10 : - ; 11 : ; -------------------- ; CPU-all ; 12 : event counter, incremented by CPU3 after raw data readout ; 13 : number of samples, used for raw data readout ; 14 : Chip Position for MCM Header (bits 0..6) and readout flags (bits 16..) ; 15 : half-chamber header 0 ; Testpatterns ; ;############################################################################## ;# ;# defines ;# ;############################################################################## #def FIT_SVN_REV = $Rev: 2666 $; ; ASM_SVN_REV is internally defined in the assembler, its own revision ; for I2C and JTAG #def srv_command = 0xF0E0 #def srv_indata = 0xF0E1 #def srv_outdata = 0xF0F0 #def LP_REP = 0xF0E4 ; #def DBANKscsn = 1 ; store the ADC data to DBANK for scsn readout ; otherwise use the DMEM #def nachkommast = 5 #def minus_nachk = -5 #def rounding_add = 17; 2**(nachkommast-1)+1 #def pad_ext = 13; 8 + nachkommast. ; the constants here are used to move the corresponding bit to carry #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 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 ; For the tracklet calculation ; Name GIO Addr DMEM Addr #def pad_row_n = g8; pad row number 0xC020 0x080 #def yoffs = g9; y-coord offset 0xC021 0x084 #def defl_cor = g10; deflection corr 0xC022 0x088 #def scale_y = g11; 0.162354 = 0x29900000 / 2^32 0xC023 0x08C #def scale_d = g12; 0.185547 = 0x2F800000 / 2^32 0xC024 0x090 #def ndrift = g13; drift time in ADC samples 0xC025 0x094 #def endsig_rr_tr = g15 ; end signature for raw data[31..16] and tracklet[15..0] readout #def nsamples = c13 ; number of ADC samples per pad #def ChipPOS = c14 ; Chip Position for Header #def EventCounter = c12 ; event counter #def EvtCtrGIOAdr = 0xC04 ; Address of Event Counter in GIO #def h_0 = c15 ; half-chamber header 0 #def func_code = g14 ; functional code (copied from DMEM) #def L0AnTRcnt = c9 ; counter for L0A without tracklet, for each CPU #def rstack = r8 ; program counter stack (depth=1) #def rio = r14 ; local I/O auto incrementer register #def mask_7F = g1 ; mask for the deflection #def mask_FF = g2 ; mask for the total charge #def mask_1FFF = g3 ; mask for the offset #def ClrCntCxx = c11 ; constant used for clear counter, only for debugging #ifdef cpu0 ; #def FIT_READ = 1 ; read the fitreg[0..8] from fit_values.asm ; Note: Merging is not supported in this case! #def clk_onoff = CPU0SS ; own clock #def LSBdata = 0x03 ; LSBs for data transfer words #def AddrSCdata = 0xF000 ; Address in GIO to store the ADC data for SCSN readout #def AddrDMdata = 0x0C00 ; Address in DM to store the ADC data for SCSN readout #def AddrDMstat = 0x0160 ; Address in DM to store the ADC statistics #def lpcount0 = 0xF03C ; counts the number of starts at address 0 #def lpcount1 = 0xF07C ; counts the number of starts at address 0xFFE #def adc_ch_msk = g4 #def L0AnTRcntIO = 0x0C01 ; #def TimerCPU = 0x0A0 ; timer to measure the runtimes ; #def TimerCPUsendc = 0x0A0 ; timer to measure the runtimes #def TrcklDMEMa = 0x500 ; store the tracklet for scsn readout #def TPCI = TPCI0 ; ;#def ClrCntGio = 0x0C03 #ifdef FIT_READ #inc "fit_values0.asm" #endif #endif #ifdef cpu1 ; #def FIT_READ = 1 ; read the fitreg[0..8] from fit_values.asm ; Note: Merging is not supported in this case! #def clk_onoff = CPU1SS ; own clock #def LSBdata = 0x02 ; LSBs for data transfer words #def AddrSCdata = 0xF040 ; Address in GIO to store the ADC data for SCSN readout #def AddrDMdata = 0x0D00 ; Address in DM to store the ADC data for SCSN readout #def AddrDMstat = 0x019C ; Address in DM to store the ADC statistics #def lpcount0 = 0xF03D ; counts the number of starts at address 0 #def lpcount1 = 0xF07D ; counts the number of starts at address 0xFFE #def adc_ch_msk = g5 #def L0AnTRcntIO = 0x0C09 #def TrcklDMEMa = 0x504 ; store the tracklet for scsn readout ; #def TimerCPU = 0x0A4 ; timer to measure the runtimes ; #def TimerCPUsendc = 0x0A4 ; timer to measure the runtimes #def TPCI = TPCI1 ; ;#def ClrCntGio = 0x0C0B #ifdef FIT_READ #inc "fit_values1.asm" #endif #endif #ifdef cpu2 #def clk_onoff = CPU2SS ; own clock #def LSBdata = 0x03 ; LSBs for data transfer words #def AddrSCdata = 0xF080 ; Address in GIO to store the ADC data for SCSN readout #def AddrDMdata = 0x0E00 ; Address in DM to store the ADC data for SCSN readout #def AddrDMstat = 0x01D8 ; Address in DM to store the ADC statistics #def lpcount0 = 0xF03E ; counts the number of starts at address 0 #def lpcount1 = 0xF07E ; counts the number of starts at address 0xFFE #def adc_ch_msk = g6 #def L0AnTRcntIO = 0x0C11 ; #def TimerCPU = 0x0A8 ; timer to measure the runtimes ; #def TimerCPUsendc = 0x0A8 ; timer to measure the runtimes #def TrcklDMEMa = 0x508 ; store the tracklet for scsn readout #def TPCI = TPCI2 ; ;#def ClrCntGio = 0x0C13 #ifdef FIT_READ #inc "fit_values2.asm" #endif #endif #ifdef cpu3 #def clk_onoff = CPU3SS ; own clock #def LSBdata = 0x02 ; LSBs for data transfer words #def AddrSCdata = 0xF0C0 ; Address in GIO to store the ADC data for SCSN readout #def AddrDMdata = 0x0F00 ; Address in DM to store the ADC data for SCSN readout #def AddrDMstat = 0x0214 ; Address in DM to store the ADC statistics #def lpcount0 = 0xF03F ; counts the number of starts at address 0 #def lpcount1 = 0xF07F ; counts the number of starts at address 0xFFE #def adc_ch_msk = g7 #def L0AnTRcntIO = 0x0C19 ; #def TimerCPU = 0x0AC ; timer to measure the runtimes ; #def TimerCPUsendc = 0x0AC ; timer to measure the runtimes #def TrcklDMEMa = 0x50C ; store the tracklet for scsn readout #def TPCI = TPCI3 ; ;#def ClrCntGio = 0x0C1B #ifdef FIT_READ #inc "fit_values3.asm" #endif #def NI_tmsn_delay = c8 ; programmable network interface readout delay, cpu3 only! #endif ;############################################################################## ;# ;# 0x000: Infinite Loop at Instruction Memory Reset Address ;# ;############################################################################## ORG 0x0; lpw: nop nop nop iext lpcount0 lgio 0, lpcount0 jmpr cc_busy, 0 lpio GBUSR0, r1 add r1, c1, r1 iext lpcount0 sgio r1, lpcount0 jmpr cc_uncond, 0 nop lpw2: nop nop iext lpcount1 lgio 0, lpcount1 jmpr cc_busy, 0 lpio GBUSR0, r1 add r1, c1, r1 iext lpcount1 sgio r1, lpcount1 jmpr cc_uncond, 0 nop ;############################################################################## ;# ;# 0x100: 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 0x100; clr: mov 0, r12 #ifdef cpu0 #ifdef ClrCntGio mov ClrCntCxx, r1 add r1, c1, r1 sgio r1, ClrCntGio #endif iext b1111_0000_0000_0000_0010_0000; mov b1111_0000_0000_0000_0010_0000, r1 jmpr cc_busy, 0 sgio r1, SMOFFON ; switch off all NI LVDS cells, clk_prepr, clk_ni (VA), clk_fil ON mov 0x28, r0 ; clear NI fifo jmpr cc_busy, 0 sgio r0, NMOD mov 0x08, r0 jmpr cc_busy, 0 sgio r0, NMOD #else ; cpu1,2,3 #ifdef ClrCntGio mov ClrCntCxx, r1 add r1, c1, r1 sgio r1, ClrCntGio #endif ; check the type of the chip swp ChipPOS, r1 ; the flags are in the upper 16 bits andt r1, c3 ; if 0, HCM or BM jmp cc_zero, clr_bm_hcm ; clr for normal chips, cpu1,2,3 #ifdef cpu1 mov 0x080, r15; prepare for reading from DMEM, the IO address was 0xC020 mov 18, r0 ; or may be 17? lra rr_dword, r1 lra+ rr_dword, r1 mov r1, pad_row_n lra rr_dword, r1 lra+ rr_dword, r1 shl pad_ext, r0, r0 ; 18*256*2**nachkomm add r1, r0, yoffs #endif #ifdef cpu2 mov 0x088, r15 ; prepare for reading from DMEM nop nop lra rr_dword, r1 lra+ rr_dword, r1 mov r1, defl_cor lra rr_dword, r1 lra+ rr_dword, r1 mov r1, scale_y #endif #ifdef cpu3 mov 0x090, r15 ; prepare for reading from DMEM ; switch off the NIICE lvds cells mov 0, r0 sgio r0, NIICE lra rr_dword, r1 lra+ rr_dword, r1 mov r1, scale_d lra rr_dword, r1 lra+ rr_dword, r1 mov r1, ndrift #endif #endif clr_endloop: nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop jmpr cc_uncond, 0 nop clr_bm_hcm: #ifdef cpu1 mov c8, g0 ; flag to check if this is the first call cmp r12, g0 ; r12=0, g0 is 0 (first call) or 1 jmp cc_neq, clr_endloop ; if r12 /= g0 - skip init ; store 1 to c8 via GIO mov 1, r0 sgio r0, 0xC08 ; init the privat counter/timer as counter/up/int/cont - 120MHz mov 0x640, r0 spio r0, CTPCTRL spio r12, CTPDINI #endif #ifdef cpu2 nop nop cmp r12, g0 ; r12 is 0, g0 is 0(first call) or 1 jmp cc_neq clr_endloop ; init the privat counter/timer as counter/down/int/cont - 120MHz mov 0xA40, r0 spio r0, CTPCTRL mov 11, r0 spio r0, CTPDINI #endif #ifdef cpu3 nop ; switch off the NIICE lvds cells mov 0, r0 sgio r0, NIICE cmp r12, g0 jmp cc_neq, clr_endloop ; init the privat counter/timer as counter/up/pre mov 0x700, r0 spio r0, CTPCTRL spio r12, CTPDINI #endif jmp cc_uncond, clr_endloop nop ;############################################################################## ;# ;# 0x200: Interrupt Tracklet Processing Jump Address ;# ;############################################################################## ORG 0x200; acq: #ifdef TimerCPU mov 0x640, r0 spio r0, CTPCTRL mov 0, r0 spio r0, CTPDINI #endif #ifndef testmode_t ; by only one CPU! #ifdef cpu0 shl nachkommast, c1, r13 neg r13, r13 ; load -2**nachkommast, in order to invert the position nop nop ; switch on the NIICE lvds cells mov 1, r0 sgio r0, NIICE #endif #ifdef cpu1 shl nachkommast, c1, r13 neg r13, r13 ; load -2**nachkommast, in order to invert the position mov 0x7F, mask_7F ; copy the end signature words NES into GRF mov 0xFF, mask_FF iext 0x1FFF mov 0x1FFF, mask_1FFF #endif #ifdef cpu2 shl nachkommast, c1, r13 neg r13, r13 ; load -2**nachkommast, in order to invert the position shl -11, h_0, func_code shl -11, func_code, func_code nop nop #endif #ifdef cpu3 lgio 0, NES shl nachkommast, c1, r13 neg r13, r13 ; load -2**nachkommast, in order to invert the position jmpr cc_busy, 0 lpio GBUSR0, r2 mov r2, endsig_rr_tr #endif shlt TDISflag, func_code jmp cc_carry, acq_no_tr shlt COSMflag, func_code jmp cc_carry, acq_cosmic #ifdef AVOID_DTR #ifdef FIT_READ mov f00_value, adc_ch_msk #else mov f0, adc_ch_msk ; g[4+CPU#], same register used in zero suppression #endif #endif ;############################################################## ;# ;# check for tracklets: CHANNEL !=31 ;# ;############################################################## #ifdef FIT_READ mov f00_value, r8 cmp r8, 31 #else cmp f0, 31 #endif jmp cc_eq, acq_no_tr ; if CHANNEL = 31 then exit #ifdef AVOID_DTR #ifdef cpu1 #ifdef FIT_READ sub r8, g4, r0 ; r0 = f0(CPU1) - f0(CPU0) #else sub f0, g4, r0 ; r0 = f0(CPU1) - f0(CPU0) #endif #endif #ifdef cpu2 #ifdef FIT_READ sub r8, g5, r0 ; r0 = f0(CPU2) - f0(CPU1) #else sub f0, g5, r0 ; r0 = f0(CPU2) - f0(CPU1) #endif #endif #ifdef cpu3 #ifdef FIT_READ sub r8, g6, r0 ; r0 = f0(CPU3) - f0(CPU2) #else sub f0, g6, r0 ; r0 = f0(CPU3) - f0(CPU2) #endif #endif #ifdef cpu0 nop nop nop nop nop #else cmp r0, c1 ; compare with 1 jmp cc_eq, acq_no_tr1 cmp r0, c7 ; compare with -1 jmp cc_eq, acq_no_tr2 #endif #endif ;############################################################## ;# ;# fit parameter calculation ;# ;# SLOPE = ( N * XY - X * Y ) / ( N * XX - X * X ) ;# OFFSET = ( XX * Y - X * XY ) / ( N * XX - X * X ) ;# ;############################################################## #ifdef FIT_READ mov f01_value, r15 ; f9_value is 0, f1 is 5 bit mov f03_value, r1 ; f3+f11, f11 is 0, f3 is 9 bit #else add f1, f9, r15 ; N = N0 + N1 add f3, f11, r1 ; X = X0 + X1 #endif mul32 r1, r1, r3 ; X * X #ifdef FIT_READ iext f04_value mov f04_value, r2 ; f4 is 14 bit, f12_value is 0 #else add f4, f12, r2 ; XX = XX0 + XX1 #endif mul32 r15, r2, r4 ; N * XX #ifdef FIT_READ iext f02_value mov f02_value, r7 #else add f2, f10, r7 ; Q = Q0 + Q1 #endif sub r4, r3, r3 ; N * XX - X * X ; r12 = 0 in clear procedure ; r13 = -4 in clear procedure div r12, r3 ; 2**(32+nachkomma)/DENOMINATOR after 19 clocks #ifdef FIT_READ iext f05_value mov f05_value, r5 #else shl 8, f9, r5 ; 256 * N1 ( 1) add f13, r5, r5 ; Y1 + 256 * N1 ( 2) add f5, r5, r5 ; Y = Y0 + Y1 + 256 * N1 ( 3) #endif #ifdef FIT_READ iext f06_value mov f06_value, r6 #else shl 8, f11, r6 ; 256 * X1 ( 4) add f14, r6, r6 ; XY1 + 256 * X1 ( 5) add f6, r6, r6 ; XY = XY0 + XY1 + 256 * X1 ( 6) #endif mus32 r1, r5, r3 ; X * Y ( 7) mus32 r1, r6, r4 ; X * XY ( 8) mus32 r2, r5, r1 ; XX * Y ( 9) mus32 r15, r6, r2 ; N * XY (10) sub r1, r4, r1 ; OF = XX * Y - X * XY (11) sub r2, r3, r2 ; SL = N * XY - X * Y (12) shl 2, r15, r15 ; byte adressing in DMEM (13) ; QA = low word of Q, ignored shl -16, r7, r4 ; QB = high word of Q (14) lra rr_dword, r0 ; 2**31 / N (15) lra rr_dword, r0 ; 2**31 / N (16) mul r0, r4, r0 ; QB * 2**31 / N (17) nop ; do something useful here !!! (18) - optimize later and r13, mask_FF, r6 ; QB * 2**(-1) / N (19) ; QB / N >= 2**10 not catched shl 4, r6, r6 ; E.PROBABILITY & 0[4] (20) or r6, pad_row_n, r6 ; E.PROBABILITY & PAD ROW (21) die r7 ; get 2**(32+nachkomma)/DENOMINATOR mus r7, r1, r1 ; lower 32 bit word of OFFSET, we use the upper bits mus r7, r2, r2 ; lower 32 bit word of SLOPE, we use the upper bits in r13 add r13, yoffs, r1 ; save the offset+chip_size+yoffs in r1 mus32 r13, ndrift, r2 ; save the slope * ndrift ; here we have: ; offset in r1 (1 PAD = 256*2**nachkommast) ; slope in r2 (1 PAD = 256*2**nachkommast) ; the deflection table is at address 0x0C0 in DMEM (initialized at 0xC030 in GIO) mov 0x0C0, r15 ; the start address of the min-max table in DMEM #ifdef FIT_READ mov f00_value, r13 shl 3, r13, r13 #else shl 3, f0, r13 ; 2**3 (=8) * ch - the offset in the table, 2 entries/ch #endif add r13, r15, r15 ; the address in DMEM #ifdef FIT_READ mov f00_value, r8 shl pad_ext, r8, r8 #else shl pad_ext, f0, r8 ; 256*2**nachkomma #endif sub r1, r8, r1 ; OFFSET [15] ( * 256 * 4 ) - sub the channel*256*4 add r2, defl_cor, r2 ; add the deflection corr const ; check if the deflection is in the proper range lra rr_dword, r13 lra+ rr_dword, r13 ; the min limit cmp r13, r2 jmp cc_gts, acq_out_min ; jump if min > deflection lra rr_dword, r13 lra+ rr_dword, r13 ; the min limit cmp r2, r13 jmp cc_gts, acq_out_max ; jump if deflection > max mov rounding_add, r8 ; prepare for the rounding mus r1, scale_y, r1 ; scale properly, the factor is multiplied by 2**32 mus r2, scale_d, r2 ; the result is in bits 63..32 (r13) add r13, r8, r1 ; rounding, save the result with one clock delay add r13, r8, r2 sha minus_nachk, r1, r1 ; remove the 2 additional bits sha minus_nachk, r2, r2 and r1, mask_1FFF, r1 and r2, mask_7F, r2 shl 7, r6, r6 ; prepare for OR with r2 or r6, r2, r6 ; put the deflection (r2) shl 13, r6, r6 ; prepare for OR with r1 or r6, r1, r6 ; the tracklet is ready!!! ;############################################################## ;# ;# tracklet synthesis and transmission ;# Bits Name Size Type 1bit= ;# 12.. 0 OFFSET 13 signed 160um r1 ;# 19..13 DEFLECTION 7 signed 140um r2 ;# 23..20 PAD ROW 4 unsigned 1 \ already in r6 ;# 31..24 QTOTAL 8 unsigned mean cluster charge / ;# ;############################################################## acq_write_tr: #ifdef trckl_delay mov trckl_delay, r1 ; delay transmission acq_tr_del: sub r1, c1, r1 jmp cc_nzero, acq_tr_del #endif #ifdef cpu0 mov b0000_0010_0000, r1 jmpr cc_busy, 0 sgio r1, SMOFF ; switch off clk_fil, can be moved after division below #else nop nop nop #endif #ifdef set_NFSM_acq #ifdef cpu0 lgio 0, NFSM jmpr cc_busy, 0 lpio GBUSR0, r5 lgio 1, SMCMD shl 12, r5, r5 jmpr cc_busy, 0 lpio GBUSR1, r4 or r5, r4, r5 sgio r5, 0xC02 #else nop nop nop nop nop nop nop nop nop #endif #endif acq_send_tr_mult: #ifdef TimerCPU lpio CTPDOUT, r5 ; the number of CPU clocks #endif spio r6, NODP sra r6, TrcklDMEMa ; store in DMEM for debugging #ifdef TimerCPU sra r5, TimerCPU ; store in DMEM for debugging #else sra r6, TrcklDMEMa ; store in DMEM for debugging #endif ; spio r6, NODP ; second write to NI, not necessary, should try to remove! jmp cc_uncond, clr_endloop nop ;############################################################## ;# ;# send end signature if there is no tracklet ;# ;# do any power management here (to be implemented !!!) ;# ;############################################################## acq_no_tr0: nop nop nop nop acq_no_tr: nop nop nop acq_no_tr1: nop nop nop acq_no_tr2: mov 16, r1 ; delay transmission acq_nt_del: sub r1, c1, r1 jmp cc_nzero, acq_nt_del acq_L1AnTRcnt: mov L0AnTRcnt, r1 add r1, c1, r1 sgio r1, L0AnTRcntIO mov endsig_rr_tr, r6 jmp cc_uncond, acq_write_tr nop acq_out_min: nop nop nop nop acq_out_max: nop; nop; nop; nop; jmp cc_uncond, acq_L1AnTRcnt nop #else ; testmode_t=1 ;############################################################## ;# ;# Test mode, send tracklets from CPU0,1,2,3 ;# ;# depending on C14, C15 ;# ;# The tracklet is composed so: ;# ;# [31..16] = c15[31..16] (ROC HEADER) ;# [19..16] = bit mask, which CPU must send a tracklet ;# [15.. 8] = c14[ 4.. 0] (MCM ID) ;# [ 7.. 0] = C & CPU ID (c5) ;# ;############################################################## #ifdef cpu0 mov b0000_0010_0000, r1 jmpr cc_busy, 0 sgio r1, SMOFF ; switch off clk_fil, can be moved after division below #else nop ; could be omitted later nop nop #endif iext 0xFFFF mov 0xFFFF, r0 swp r0, r0 and r0, c15, r0 mov 0x1F, r1 and r1, ChipPOS, r1 shl 8, r1, r1 or r1, r0, r0 mov 0xC0, r1 or r1, r0, r0 or r0, c5, r0 shl -8, ChipPOS, r2 shl -8, r2, r2 neg c5, r3 shl r3, r2, r2 and r2, c1, r2 jmp cc_zero, acq_no_tr shl 1, ChipPOS jmp cc_nzero, acq_no_tr ; in case of BM or HCM nop mov 36, r1 ; delay transmission acq_tr_del: sub r1, c1, r1 jmp cc_nzero, acq_tr_del nop spio r0, NODP nop spio r0, NODP jmpr cc_uncond, 0 nop acq_no_tr: mov 36, r1 ; delay transmission acq_nt_del: sub r1, c1, r1 jmp cc_nzero, acq_nt_del mov endsig_rr_tr, r5 #ifdef cpu0 xor r5,c1,r5 ; emulate 1 bit error #else nop #endif spio r5, NODP nop spio r5, NODP jmpr cc_uncond, 0 nop #endif ;############################################################## ;# ;# Test mode, send tracklets from CPU0,1,2,3 ;# ;# depending on C14, C15 ;# ;# The tracklet is composed so: ;# ;# [31..16] = charge sum ;# [15.. 0] = Hit Sum ;# ;############################################################## acq_cosmic: SEM b1111_0000 #ifdef cpu0 ; switch on the NIICE lvds cells nop nop nop mov 1, r0 sgio r0, NIICE #endif ; bypass the automatic selection of the fit-registers #ifdef cpu1 mov 0, r0 IEXT TPCBY SGIO r0, TPCBY nop nop #endif #ifdef cpu2 nop nop nop nop nop #endif #ifdef cpu3 iext TPFP lgio 0, TPFP jmpr cc_busy, 0 lpio GBUSR0, r5 mul32 r5, c3, r5 ; 3 channels in the hit-charge #endif #ifdef cpu0 iext TPCI0 mov TPCI0, r1 ; lower channel number mov 1, r2 ; start channel add r2, c3, r3 ; end channel = start channel + 3 mov 0x400, r15 ; start address in DMEM #endif #ifdef cpu1 iext TPCI1 mov TPCI1, r1 ; lower channel number mov 5, r2 ; start channel add r2, c3, r3 ; end channel = start channel + 3 mov 0x420, r15 ; start address in DMEM #endif #ifdef cpu2 iext TPCI2 mov TPCI2, r1 ; lower channel number mov 9, r2 ; start channel add r2, c4, r3 ; end channel = start channel + 3 mov 0x440, r15 ; start address in DMEM #endif #ifdef cpu3 iext TPCI3 mov TPCI3, r1 ; lower channel number mov 14, r2 ; start channel add r2, c4, r3 ; end channel = start channel + 3 mov 0x468, r15 ; start address in DMEM #endif sgio r2, r1 mov 0, r6 ; hit accu mov 0, r7 ; charge accu acq_cosmic_next_ch: jmpr cc_busy, 0 swp f8, r4 or f9, r4, r4 add r6, f9, r6 ; accumulate Nhits shl -16, f10, r4 add r2, c1, r2 sgio r2, r1 add r7, r4, r7 ; accumulate Q cmp r2, r3 jmp cc_leu, acq_cosmic_next_ch ; here we have: ; the number of Hits in r6 ; the accumulated charge (+ pedestal) in r7 mov r6, adc_ch_msk SYN SEM b1111_0000 #ifdef cpu3 add r6, g4, r6 add r6, g5, r6 add r6, g6, r6 #else nop nop nop #endif mov r7, adc_ch_msk SYN #ifdef cpu3 add r7, g4, r7 add r7, g5, r7 add r7, g6, r7 sra+ r7 #else #ifdef cpu1 mov 1, r0 ; switch back to automatic select, necessary IEXT TPCBY ; for the zero suppression SGIO r0, TPCBY nop #else nop nop nop nop #endif #endif #ifdef cpu3 mul32 r5, r6, r5 ; the pedestal in the charge sra+ r5 shl -2, r5, r5 ; the TPFP is with 2 more bits, therefore /4 sub r7, r5, r7 ; the charge without pedestal sra+ r7 #else mov 0, r6 mov 0, r7 nop nop nop #endif mov 0x1F, r1 shl -3, c10, r0 ; the min hits is in bits 15..8 and r1, r0, r0 cmp r6, r0 ; min number of hits jmp cc_leu, acqco_no_tr shl -8, c10, r1 ; the min cluster charge is in bits 23..8 cmp r7, r1 jmp cc_leu, acqco_no_tr mov 0x7, r0 and r0, c10, r0 ; the shift (right) distance neg r0, r0 shl r0, r7, r7 ; shift right the charge shl r0, r1, r1 ; shift right the threshold cmp r7, 0xFF ; check if Q > 255 jmpr cc_leu, +2 mov 0xFF, r7 ; clip to 255 cmp r1, 0xFF ; check if Q > 255 jmpr cc_leu, +2 mov 0xFF, r1 ; clip to 255 shl 8, r7, r7 ; shift left 8 bits or r7, r1, r7 ; add the threshold shl 8, r7, r7 ; shift left 8 bits or r7, r6, r6 ; add the Nhits shl 8, r6, r6 ; shift left 8 bits mov 0xFF, r1 ; and r1, c10, r1 ; lower 8 bits of c10 or r1, r6, r6 ; COSMIC_Q_SHR | COSMIC_MIN_HITS << 3 ; the tracklet is ready! jmp cc_uncond, acq_send_tr_mult nop acqco_no_tr: mov 6, r6 sub r6, c1, r6 jmpr cc_nzero, -1 mov endsig_rr_tr, r6 jmp cc_uncond, acq_send_tr_mult ;############################################################################## ;# ;# 0x400: Interrupt Raw Data Transmission Jump Address ;# ;############################################################################## ORG 0x400 raw: #ifdef cpu0 mov cmd_CPU_done r0 ; CPU0 indicates upcoming data transmission sgio r0 SMCMD; nop #endif #ifdef cpu1 mov 1, r0 ; switch back to automatic select, necessary IEXT TPCBY ; for the zero suppression SGIO r0, TPCBY ; already done in cosmic fitprogram!!! #endif #ifdef cpu3 iext EBSIM lgio 1, EBSIM nop #endif #ifdef cpu2 nop nop nop #endif ;############################################## ;# Store Start addresses for SCSN transfer via Databank ;############################################## #ifdef DBANKscsn iext AddrSCdata mov AddrSCdata, rio #else mov AddrDMstat, r15 swp r15, r15 mov AddrDMdata, r2 or r15, r2, r15 #endif swp ChipPOS, r2 ; load NI&SCSN readout flag in c14 shlt -3, r2 ; move bit 2 to C flag jmp cc_carry, raw_hc0 ; bit 2=1 means additional header(s) -> HC MCM!!! #ifdef DBANKscsn swp rio, rio ; swap DBANK address to high word of rio #endif andt r2, c3 jmp cc_zero, raw_complete_ni_tmsn ; check for transmission flags, if not BM - exit #ifdef ConfigEvent mov EventCounter, r0 cmp r0, ConfigEvent jmp cc_eq, raw_send_conf #endif #ifdef cpu0 shl 7, c1, r0 or r0, ChipPOS, r0 ; combine chip header 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" or r0, g5, r11 ; 1 & ChipPOS(7) & EventCounter(20) & "1100" ; do not send the MCM Header now #ifdef DBANKscsn swp rio, rio sgio+ r11 ; no busy flag check due to large delay swp rio, rio ; till next access #else sra+ r11 #endif #endif #ifdef cpu1 ; this CPU helps to CPU0 to prepare the event counter field in the MCM header iext 0xFFFFF ; 20 bits with 1 mov 0xFFFFF, r0 ; mask for the event counter and r0, EventCounter, r0 ; event counter's 20 bits. shl 4, r0, g5 ; the lower 20 bits of the event counter << 4, ready for the header jmp cc_uncond raw_check_zs nop nop nop #ifdef DBANKscsn nop nop #endif #endif #ifdef cpu2 nop nop nop nop nop nop nop jmp cc_uncond raw_check_zs #ifdef DBANKscsn nop nop #endif #endif #ifdef cpu3 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! jmp cc_uncond raw_check_zs nop nop nop nop #ifdef DBANKscsn nop nop #endif #endif raw_check_zs: #ifdef DBANKscsn iext 0xFFFF0000 ; high word mask for Channel switching mov 0xFFFF0000, r15 ; Note: this works because of the sign extension! #endif mov nsamples, r1 ; initially load number of samples cmp r1, 0 jmp cc_zero, raw_complete_ni_tmsn ; check for transmission flags ; first check if the zero suppression is on shlt ZSflag, func_code jmp cc_ncarry raw_no_zsup ; ZERO SUPPRESSION case ; check if some events should be send without ZS SEM b1111_0000 ; sync mask for the CPUs, all must write to g4..g7 shl OPTs, func_code, r8 shl -1, r8, r8 ; only bits 2..1 and r8, c3, r8 jmp cc_zero, raw_ebi_read ; 00 means normal ZS on all events mov 0x07F, r9 ; in case of 01 cmp r8, 2 jmpr cc_neq, +2 mov 0x0FF, r9 ; in case of 10 cmp r8, 3 jmpr cc_neq, +2 mov 0x3FF, r9 ; in case of 11 and r9, EventCounter, r9 ; take the lower n-bits in Event Counter cmp r9, 1 ; and compare with 1 jmp cc_neq, raw_ebi_read ; normal ZS mode #ifdef cpu3 mov b11_1111, r6 ; set which channels to send, here all #else mov b01_1111, r6 ; set which channels to send, here all #endif jmp cc_uncond, raw_ebiscan_done ; skip the reading of the indicators ; now read the indicators and mark the ADC channels with non-zero indicators raw_ebi_read: mov c1, r8 ; mask, will be shifted left in each loop mov EBI0, r9 ; address of the first indicator mov 15, r10 mov nsamples, r0 mov 1, r6 ; r6 = 1 cmp r0, 15 ; if shift distance up to 15, do directly jmp cc_leu, raw_ebi_mask sub r0, r10, r0 ; decrease the distance by 15 shl 15, r6, r6 ; and shift the r6 to left, r6 = 1 << 15 cmp r0, 15 ; compare again the remaining distance with 15 jmp cc_leu, raw_ebi_mask ; and jump to shift directly if up to 15 sub r0, r10, r0 ; decrease the distance by 15 shl 15, r6, r6 ; and shift the r6 to left, r6 = 1 << 30 raw_ebi_mask: shl r0, r6, r6 ; r6 = r6 << r0 (remaining shift) sub r6, c1, r10 ; r10 (mask) = r6 - 1 = (1 << nsamples) - 1 mov c0, r6 ; clear r6 raw_ebiscan: lpio r9, r0 ; read twice because of the latency in LIO lpio r9, r0 not r0, r0 ; invert the mask, active low and r0, r10, r0 ; mask the unused bits and test if zero jmpr cc_zero, +2 or r6, r8, r6 ; set the bit!!! add r9, c2, r9 ; increment the address of the indicator : 2 addresses per channel! shl 1, r8, r8 ; shift the mask left #ifdef cpu3 cmp r8, b100_0000 ; check for last channel, CPU3 #else cmp r8, b010_0000 ; check for last channel, CPU0..2 #endif jmp cc_neq, raw_ebiscan ; the adc mask in r6 is not absolute, now shift properly raw_ebiscan_done: #ifdef cpu0 nop ; cpu0 has channels 0..4, no shift! #endif #ifdef cpu1 shl 5, r6, r6 ; cpu1 has channels 5..9 #endif #ifdef cpu2 shl 10, r6, r6 ; cpu2 has channels 10..14 #endif #ifdef cpu3 shl 15, r6, r6 ; cpu3 has channels 15..20 #endif ; calculate the ADC mask for the zero suppression in case of tracklets cmp f8, 0 ; ch+1 is 0 if no tracklet present jmp cc_zero raw_notrack mov 0xF, r0 ; 1111b, take the 4 ADC channels cmp f9, 0 ; number of hits in ch+1 jmp cc_nzero raw_4pads shl -1, r0, r0 ; 0111b but if ch+1 has no hit, remove the last channel raw_4pads: mov f0, r1 cmp r1, 16 ; the max shift left is 15! jmpr cc_ltu, +3 shl 4, r0, r0 sub r1, c4, r1 ; continue, r1 is < 16 here shl r1, r0, r0 ; X111b << f0, here are the bit positions absolute or r0, r6, r6 raw_notrack: mov r6, adc_ch_msk SYN; SEM b1111_0000 ; sync mask for the CPUs, all must write to g4..g7 ; here all CPUs start simultaneously or r6, g4, r6 ; CPU0 or r6, g5, r6 ; CPU1 or r6, g6, r6 ; CPU2 or r6, g7, r6 ; CPU3 ; shift back to the right to get the mask relative to the CPU's start channel #ifdef cpu0 nop #endif #ifdef cpu1 shl -5, r6, r6 #endif #ifdef cpu2 shl -10, r6, r6 #endif #ifdef cpu3 shl -15, r6, r6 #endif ; count the number of 1 in r6 mov 0, r7 ; clear the counter shlt -1, r6 ; copy bit 0 to carry adc r7, c0, r7 ; add the carry to r7 shlt -2, r6 ; copy bit 1 to carry adc r7, c0, r7 ; add the carry to r7 shlt -3, r6 ; copy bit 2 to carry adc r7, c0, r7 ; add the carry to r7 shlt -4, r6 ; copy bit 3 to carry adc r7, c0, r7 ; add the carry to r7 shlt -5, r6 ; copy bit 4 to carry adc r7, c0, r7 ; add the carry to r7 #ifdef cpu3 shlt -6, r6 ; copy bit 5 to carry adc r7, c0, r7 ; add the carry to r7 #else nop nop #endif mov r7, adc_ch_msk ; move to GRF SYN #ifdef cpu0 add r7, g5, r7 ; accumulate all number of channels add r7, g6, r7 ; accumulate all number of channels add r7, g7, r7 ; accumulate all number of channels #else nop nop nop #endif nop mov r6, adc_ch_msk ; copy back the adc channel mask to the grf register mov raw_ChTML_adc, r9 ; use the ADC transfer mode, zero suppression is not compatible with test patterns! #ifdef cpu0 nop #else jmp cc_uncond, raw_transf_ch ; cpu0 must send the MCM header, the others can continue #endif; ; CPU0 only shlt ZS_no_empty, func_code jmpr cc_ncarry +3 cmp r7, 0 jmp cc_eq raw_transf_ch ; skip sending of MCM header and empty ADC mask ; start storing the ADC values to DMEM spio r11 NODP ; NI transfer chip header ; combine the full mask not r7, r7 ; the number of ADC channels, inverted shl 13, r7, r7 shl 13, r7, r7 shl -1, r7, r7 shl 2, r6, r6 or r6, c3, r6 ; 11 shl 2, r6, r6 ; 01 & not(ADC count) & adc_msk[3] & adc_msk[2] & adc_msk[1] & adc_msk[0] & "1100" or r7, r6, r6 spio r6, NODP ; send the ADC mask jmp cc_uncond raw_transf_ch raw_no_zsup: #ifdef cpu0 spio r11 NODP ; NI transfer chip header #else nop #endif #ifdef cpu3 mov b11_1111, adc_ch_msk ; show which channels to send, here all #else mov b01_1111, adc_ch_msk ; show which channels to send, here all #endif shlt TPATTflag, func_code jmp cc_carry, raw_pattern_sel mov raw_ChTML_adc, r9 ; use the ADC transfer mode shlt ZS_no_empty, func_code ; here used to select statistics mode jmp cc_ncarry, raw_transf_ch mov raw_ChTML_adcS, r9 ; use the ADC transfer mode with statistics jmp cc_uncond, raw_transf_ch ; raw_pattern_sel: ; patterns shl OPTs, func_code, r9 mov 0x7, r6 ; 3 bit mask and r6, r9, r6 ; the pattern is now in r6 mov raw_ChTML_p0, r9 ; pattern 0, default if not found/implemented cmp r6, 2 jmpr cc_neq, +3 mov raw_ChTML_p2, r9 ; pattern 2 jmp cc_uncond, raw_prepare_23 cmp r6, 6 jmpr cc_neq, +3 mov raw_ChTML_p6, r9 ; pattern 6 jmp cc_uncond, raw_prepare_23 cmp r6, 3 jmp cc_neq, raw_check_psrg mov raw_ChTML_p3, r9 ; pattern 3 raw_prepare_23: shl -1, h_0, r13 ; sector/plane/chamber in 11 bits mov 0x7FF, r3 and r3, r13, r13 mov b100_1001, r3 add r3, r13, r13 ; add 1 to sector, plane and chamber to avoid 0000 mov ChipPos, r3 and r3, mask_7F, r3 shl 7, r13, r13 or r13, r3, r13 ; sector(5)/plane(3)/chamber(3)/rob(3)/mcm(4) : 18 bits shl 2, r13, r13 or r13, c5, r13 ; sector(5)/plane(3)/chamber(3)/rob(3)/mcm(4)/cpu(2) : 20 bits jmp cc_neq, raw_transf_ch raw_check_psrg: cmp r6, 1 jmp cc_neq, raw_transf_ch mov raw_ChTML_p1, r9 ; pattern 1, psrg10 ; init the local counter mov b101001, r6 ; inc after read, 10 bit, psrg spio r6, CTPCTRL shl 7, c1, r6 ; 1000 0000b add r6, ChipPOS, r6 ; 1rrr mmmmb rrr ROB#, mmmm MCM# shl 2, r6, r6 ; 1r rrmm mm00b or r6, c5, r6 ; 1r rrmm mmccb cc CPU# spio r6, CTPDINI raw_transf_ch: ;############################################## ;# NI&SCSN transfer 1st channel ;############################################## mov LSBdata, r7 ; pass the two LSBs for data transmission mov 0, r3 ; used in testpattern mode mov NODP, r6 ; the NI output port shl -1, adc_ch_msk, adc_ch_msk ; check the flag jmpr cc_carry, +2 mov GBUSR0, r6 ; dummy output port, GBUSR0 is readonly! #ifdef DBANKscsn mov EBR0, r0 ; address in LIO of the event buffer or r0, rio, rio ; to low word of rio #else mov EBR0, rio #endif cmp r9, raw_ChTML_adcS ; check if ADC statistics should be stored jmpr cc_neq, +3 mov 0, r11 mov 0, r13 mov nsamples,r1 ; number of samples to read (done above) mvpcr +2, rstack jmp cc_uncond, r9; ;############################################## ;# NI&SCSN transfer 2nd channel ;############################################## mov NODP, r6 ; the NI output port shl -1, adc_ch_msk, adc_ch_msk ; check the flag jmpr cc_carry, +2 mov GBUSR0, r6 ; dummy output port, GBUS0 is readonly! #ifdef DBANKscsn and r15, rio, rio mov EBR1, r0 ; address in LIO of the event buffer or r0, rio, rio ; to low word of rio #else mov EBR1, rio #endif cmp r9, raw_ChTML_adcS ; check if ADC statistics should be stored jmpr cc_neq, +3 mov 0, r11 mov 0, r13 mov nsamples,r1 ; number of samples to read mvpcr +2, rstack jmp cc_uncond, r9; ;############################################## ;# NI&SCSN transfer 3rd channel ;############################################## mov NODP, r6 ; the NI output port shl -1, adc_ch_msk, adc_ch_msk ; check the flag jmpr cc_carry, +2 mov GBUSR0, r6 ; dummy output port, GBUS0 is readonly! #ifdef DBANKscsn and r15, rio, rio mov EBR2, r0 ; address in LIO of the event buffer or r0, rio, rio ; to low word of rio #else mov EBR2, rio #endif cmp r9, raw_ChTML_adcS ; check if ADC statistics should be stored jmpr cc_neq, +3 mov 0, r11 mov 0, r13 mov nsamples,r1 ; number of samples to read mvpcr +2, rstack jmp cc_uncond, r9; ;############################################## ;# NI&SCSN transfer 4th channel ;############################################## mov NODP, r6 ; the NI output port shl -1, adc_ch_msk, adc_ch_msk ; check the flag jmpr cc_carry, +2 mov GBUSR0, r6 ; dummy output port, GBUS0 is readonly! #ifdef DBANKscsn and r15, rio, rio mov EBR3, r0 ; address in LIO of the event buffer or r0, rio, rio ; to low word of rio #else mov EBR3, rio #endif cmp r9, raw_ChTML_adcS ; check if ADC statistics should be stored jmpr cc_neq, +3 mov 0, r11 mov 0, r13 mov nsamples,r1 ; number of samples to read mvpcr +2, rstack jmp cc_uncond, r9; ;############################################## ;# NI&SCSN transfer 5th channel ;############################################## mov NODP, r6 ; the NI output port shl -1, adc_ch_msk, adc_ch_msk ; check the flag jmpr cc_carry, +2 mov GBUSR0, r6 ; dummy output port, GBUS0 is readonly! #ifdef DBANKscsn and r15, rio, rio mov EBR4, r0 ; address in LIO of the event buffer or r0, rio, rio ; to low word of rio #else mov EBR4, rio #endif cmp r9, raw_ChTML_adcS ; check if ADC statistics should be stored jmpr cc_neq, +3 mov 0, r11 mov 0, r13 mov nsamples,r1 ; number of samples to read mvpcr +2, rstack jmp cc_uncond, r9; ;############################################## ;# NI&SCSN transfer 6th channel (CPU3 only) ;############################################## #ifdef cpu3 mov NODP, r6 ; the NI output port shl -1, adc_ch_msk, adc_ch_msk ; check the flag jmpr cc_carry, +2 mov GBUSR0, r6 ; dummy output port, GBUS0 is readonly! #ifdef DBANKscsn and r15, rio, rio mov EBR5, r0 ; address in LIO of the event buffer or r0, rio, rio ; to low word of rio #else mov EBR5, rio #endif cmp r9, raw_ChTML_adcS ; check if ADC statistics should be stored jmpr cc_neq, +3 mov 0, r11 mov 0, r13 mov nsamples,r1 ; number of samples to read mvpcr +2, rstack jmp cc_uncond, r9; #else nop nop nop nop nop nop nop nop nop nop nop nop #ifdef DBANKscsn nop nop #endif; #endif; ; save the fit register pairs in DMEM #ifdef FIT2DM mov r15, r2 mov 0x400, r15; DMEM pointer shl 6, c5, r1 ; 16 * 4 * CPUid add r1, r15, r15 mov f0, r1 sra+ r1 mov f1, r1 sra+ r1 mov f2, r1 sra+ r1 mov f3, r1 sra+ r1 mov f4, r1 sra+ r1 mov f5, r1 sra+ r1 mov f6, r1 sra+ r1 mov f7, r1 sra+ r1 mov f8, r1 sra+ r1 mov f9, r1 sra+ r1 mov f10, r1 sra+ r1 mov f11, r1 sra+ r1 mov f12, r1 sra+ r1 mov f13, r1 sra+ r1 mov f14, r1 sra+ r1 mov f15, r1 sra+ r1 mov r2, r15 #endif ;############################################## ;# Slow down NI transmission if NI_tmsn_delay != 0 ;############################################## raw_complete_ni_tmsn: #ifdef cpu3 mov NI_tmsn_delay, r1 ; mov doesn't set the flags! andt r1, r1 jmp cc_zero, raw_end_ni_tmsn cli lgio 0, IRQHW3 jmpr cc_busy, 0 lpio 0x300, r11 mov 0x415, r0 ; the new IRQ mask, IRQ NI fifo empty enabled sgio r0, IRQHW3 ; modify the IVT jmpr cc_busy, 0 sgio r0, IRQHL3 jmpr cc_busy, 0 jmp cc_uncond, raw_coff #else nop nop nop nop nop nop nop nop nop nop nop nop nop #endif ;############################################## ;# CPU0, CPU1: start CPU2 and CPU3 for delayed transfer ;############################################## raw_end_ni_tmsn: ;############################################## ;# CPU3: Increment Event Counter ;############################################## #ifdef cpu3 mov EventCounter, r0 add r0, c1, r0 jmpr cc_busy, 0 sgio r0 EvtCtrGIOAdr lpio GBUSR1, r0 ; 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 #else nop nop nop nop nop nop nop #endif ;############################################## ;# NI&SCSN transfer end marker ;############################################## swp endsig_rr_tr, r0 ; the upper 16 bits are the endmaker rr spio r0 NODP #ifdef DBANKscsn swp rio, rio jmpr cc_busy, 0 sgio+ r0 swp rio, rio #else 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 nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop #ifdef cpu3 jmp cc_uncond, clr_endloop #else jmp cc_uncond, raw_coff #endif nop ;############################################################################## ;# ;# NI transmission of one channel ;# ;############################################################################## ;# ;# Interface: ;# ;# Input: r14 start address of event buffer in LIO ;# r1 number of time bins to read (>0, multiple of three) ;# r7 OR mask for the 32 bit word ;# r2 Readout Flags ;# r6 address in LIO of the output port, either 0 (NI) or dummy (zero suppressed channel) ;# r8 rstack, return address ;# r9 the begin address of the procedure, dependent on the pattern/ ;# ;# Output: sends data to the NI output port ;# Modifies: r3, r4, r5, r14, r1, r13 ;# ;############################################################################## ;############################################## ;# BEGIN data transfer loop raw_ChTML_p0: ; (0x0800+i) << 16 | 0rrr mmmm 0000 0ccc mov 0xFF, r3 and r3, ChipPOS, r3 ; for mode 0 shl 8, rio, r5 or r3, r5, r5 shl 8, r5, r5 or r5, c5, r5 add r5, c1, r5 add rio, c1, rio jmp cc_uncond, raw_wadc raw_ChTML_p1: ; ADCs replaced by 10 bit pseudorandom generator lpio CTPDOUT, r3 mov 0x3FF, r5 ; mask for 10 bit psrg and r3, r5, r3 lpio CTPDOUT, r4 and r4, r5, r4 shl 10, r4, r4 or r4, r3, r3 lpio CTPDOUT, r5 shl 10, r5, r5 jmp cc_uncond, raw_ADCcor raw_ChTML_p2: shl 10, EventCounter, r5 shl 10, r5, r5 or r5, r13, r5 ; evncnt(6)/sector(5)/plane(3)/chamber(3)/rob(3)/mcm(4)/cpu(2) shl 6, r5, r5 add r3, c1, r3 ; counter++, for 1 CPU 6 bit counter is enough! or r5, r3, r5 ; ... counter(6) jmp cc_uncond, raw_wadc raw_ChTML_p6: shl 10, EventCounter, r5 shl 10, r5, r5 or r5, r13, r5 ; evncnt(6)/sector(5)/plane(3)/chamber(3)/rob(3)/mcm(4)/cpu(2) shl 6, r5, r5 add r3, c1, r3 ; counter++, for 1 CPU 6 bit counter is enough! or r5, r3, r5 ; ... counter(6) shl 2, r5, r5 ; add the two LSB as in case of normal ADC data or r5, r7, r5 jmp cc_uncond, raw_wadc raw_ChTML_p3: shl 10, EventCounter, r5 shl 10, r5, r5 or r5, r13, r5 ; evncnt(12)/sector(5)/plane(3)/chamber(3)/rob(3)/mcm(4)/cpu(2) jmp cc_uncond, raw_wadc raw_ChTML_adcS: lpio+ r3 ; initial read has to be done twice due to lpio+ r3 ; memory delay (synchronous read) lpio+ r4 lpio rio, r5 mul32 r3, r3, r0 ; calculate ADC**2 add r11, r3, r11 ; accumulate sum(ADC) add r13, r0, r13 ; accumulate sum(ADC**2) mul32 r4, r4, r0 ; calculate ADC**2 add r11, r4, r11 ; accumulate sum(ADC) add r13, r0, r13 ; accumulate sum(ADC**2) mul32 r5, r5, r0 ; calculate ADC**2 add r11, r5, r11 ; accumulate sum(ADC) add r13, r0, r13 ; accumulate sum(ADC**2) jmp cc_uncond, raw_ChTML_shift raw_ChTML_adc: lpio+ r3 ; initial read has to be done twice due to lpio+ r3 ; memory delay (synchronous read) lpio+ r4 lpio rio, r5 raw_ChTML_shift: shl 10, r5, r5 ; combine three 10 bit data words or r5, r4, r5 ; to one (32=10+10+10+2) bit data word jmp cc_zero, raw_ADCzero ; correct data if the two ADC samples are 0 raw_ADCcor: shl 10, r5, r5 or r5, r3, r5 shl 2, r5, r5 or r5, r7, r5 ; set the two LSBs raw_wadc: spio r5, r6 ; write to NI or dummy ;raw_scsn_readout: #ifdef DBANKscsn swp rio, rio ; switch to SCSN storage address jmpr cc_busy, 0 sgio+ r5 ; write to DBANK for SCSN reading swp rio, rio ; switch back to event buffer read address #else sra+ r5 #endif sub r1, c3, r1 ; decrease number of samples to read jmp cc_gtu, r9 ; loop, the start address depends on the mode and is programmed before xor r7, c1, r7 ; turn the LSB cmp r9, raw_ChTML_adcS ; check if ADC statistics should be stored jmp cc_neq, rstack ; return from subroutine swp r15, r15 ; swap the two DMEM pointers nop lra4 r4 ; read the old sum(ADC) lra4 r4 add r11, r4, r11 ; add the current sum(ADC) sra+ r11 ; and write back nop ; the reg r15 should be NOT modified befire MCM-read! lra4 r4 ; read the old sum(ADC**2) lra4 r4 add r13, r4, r13 ; add the current sum(ADC**2) sra+ r13 ; and store back nop lra4 r4 ; load the upper 32 bits of sum(ADC**2) lra4 r4 adc r4, c0, r4 ; add the carry, sra+ and lra don't modify the carry! sra+ r4 ; and write back swp r15, r15 ; swap the two DMEM pointers again jmp cc_uncond, rstack ; return from subroutine raw_ADCzero: mov 0x400, r4 ; set the LSB of the ADC sample or r5, r4, r5 ; to prevent sending the end-marker 0x0000 in the upper 16 bits jmp cc_uncond, raw_ADCcor ;############################################## ;# END data transfer loop ;############################################## nop ;############################################## ;# This is our HCM header[0], stored always in DBANK ;############################################## raw_hc0: #ifdef cpu0 iext 0xF0F0 mov 0xF0F0, rio ; the HC headers are stored always in DBANK shl 2, h_0, r0 ; the header itself is in bits 30..2 or r0, c1, r4 ; last two bits 01 #ifdef ConfigEvent mov EventCounter, r0 cmp r0, ConfigEvent jmp cc_neq, raw_hc0_cont iext 0x1FFFF mov 0x1FFFF, r0 ; 17 bits mask and r0, r4, r4 ; mask the upper bits mov 0xC7, r0 ; TP=1, pattern=7 shl 12, r0, r0 shl 12, r0, r0 or r0, r4, r4 ; new header, TP=1, pattern=7, the rest = #endif raw_hc0_cont: sgio+ r4 ; spio r4 NODP ; NI transfer header h[0] ; r4 contains the h[0], postpone sending ; prepare h[1] shl 8, nsamples, r0 ; timebins shl 8, r0, r0 or r0, g5, r0 ; timebins & BC(16 bits) shl 4, r0, r0 or r0, g7, r0 ; timebins & BC & pre_cnt(4bits) shl 4, r0, r0 or r0, g6, r0 ; timebins & BC & pre_cnt(4bits) & pre_phase(4bits) shl 2, r0, r5 or r5, c1, r5 ; timebins & BC & pre_cnt(4bits) & pre_phase(4bits) & "10" sgio+ r5 ; SVN revisions header h[3] mov FIT_SVN_REV, r0 shl 13, r0, r0 mov ASM_SVN_REV, r1 or r0, r1, r0 shl 6, r0, r0 mov 0x35, r1 or r0, r1, r6 sgio+ r6 ; h[3] ; h[0] is in r4 ; h[1] is in r5 ; h[3] is in r6 ; now wait until CPU0 of the first MCM with ADC data has stored all in FIFO #ifdef delay_hcm mov delay_hcm, r0 sub r0, c1, r0 jmpr cc_nzero, -1 #endif mov 0x7, r1 ; prepare a mask shl -12, h_0, r0 ; the number of add. header words, 3 bits and r0, r1, r1 spio r4 NODP ; NI transfer header h[0] jmp cc_zero, raw_no_add_header spio r5 NODP ; NI transfer header h[1] cmp r1, 2 jmp cc_ltu, raw_no_add_header spio r6 NODP ; NI transfer header h[2] raw_no_add_header: nop #endif #ifdef cpu1 ; prepare the BC counter lpio CTPDOUT, r0 iext 0xFFFF mov 0xFFFF, r1 and r0, r1, g5 #endif #ifdef cpu2 ; prepare the pretrigger phase lpio CTPDOUT, r0 mov 0xF, r1 and r0, r1, g6 #endif #ifdef cpu3 ; prepare the pretrigger counter lpio CTPDOUT, r0 mov 0xF, r1 and r0, r1, g7 #endif #ifdef DBANKscsn swp rio, rio ; swap DBANK address to high word of rio #endif andt r2, c3 jmp cc_zero, raw_end_ni_tmsn ; do not check for the delay: HCM doenst need it. ;############################################################################## ;# ;# 0x600 Interrupt NI FIFO empty, irq10 ;# ;############################################################################## ORG 0x600 #ifdef cpu3 nififoe: sgio r11, IRQHL3 jmpr cc_busy, 0 sgio r11, IRQHW3 jmpr cc_busy, 0 ; program the delay mov NI_tmsn_delay, r1 spio r1, 0x200 mov b1010_0101_1111, r1 ; counter, down, irq spio r1, 0x201 ; enable IRQ local timer mov b0101_0101, r1 sgio r1, IRQHL3 jmpr cc_busy, 0 sgio r1, IRQHW3 jmpr cc_busy, 0 jmp cc_uncond, raw_coff #else nop #endif ORG 0x640 ;raw_send_cnf: ; NOT USED NOW! #ifdef TimerCPUsendc mov 0x640, r0 spio r0, CTPCTRL mov 0, r0 spio r0, CTPDINI #endif mov 0x34, r0 mul32 r0, c5, r1 iext 0xF000 mov 0xF000, r13 add r13, r1, r14 ; start address #ifdef cpu3 swp g4, r2 ; the number of conf.words is stored in bits 23..16 mov 0xFF, r3 and r2, r3 add r13, r3, r15 ; end address+1 iext 0xf0d0 mov 0xf0d0, r15 #else add r14, r0, r15 ; end address+1 nop nop nop #endif raw_send_cnf_a: lgio+ 0 jmpr cc_busy, 0 lpio GBUSR0, r0 spio r0, NODP cmp r14, r15 jmp cc_ltu, raw_send_cnf_a #ifdef cpu3 iext 0x00FF7FFF mov 0x00FF7FFF, r0 swp r0, r0 spio r0, NODP ; end marker for config #endif #ifdef TimerCPUsendc lpio CTPDOUT, r0 ; the number of CPU clocks sra r0, TimerCPUsendc ; store in DMEM for debugging #else jmp cc_uncond, raw_complete_ni_tmsn ;############################################################################## ;# ;# 0x6E0 Interrupt Local Counter/Timer ;# ;############################################################################## ORG 0x6E0 localtm: ; restore the interrupt mask sgio r11, IRQHL3 jmpr cc_busy, 0 sgio r11, IRQHW3 jmpr cc_busy, 0 ; send end signature jmp cc_uncond, raw_end_ni_tmsn nop 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" #endif #ifdef cpu1 #inc "I2C.asm" #endif org 0xB00 ; send the MCM header raw_send_conf: #ifdef cpu0 iext CHIPID lgio 0, CHIPID shl 7, c1, r0 or r0, ChipPOS, r0 ; combine chip header shl 10, r0, r0 shl 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 shl 4, r0, r0 or r0, r1, r0 ; 1 & ChipPOS(7) & ChipId(20) & "1100" spio r0, NODP #endif jmp cc_uncond, raw_send_cnf #inc "pack_conf.asm" org 0xD00 ;#inc "config_man.asm" #inc "conf_mann.asm" org 0xE00 #inc "adc2cpu.asm" org 0xFFE jmp cc_uncond, lpw2 jmp cc_uncond, lpw2