'****************************************************************************** ' Subroutines '****************************************************************************** { Nominally this source is #include'd but can just as easily be pasted at end of main source The following predefined constants are required for this source to assemble XTALFREQ = PLL stage 0: crystal frequency (20 MHz for ES_EVAL board) XDIV = PLL stage 1: crystal divider (1..64) XMUL = PLL stage 2: crystal / div * mul (1..1024) XDIVP = PLL stage 3: crystal / div * mul / divp (1,2,4,6..30) Also, the following block of source code is required at beginning of main source: ========================================================================================= DAT ORG 0 'longword addressing from 0 msec jmp #_diaginit 'have to jump somewhere to dogde the reserved variables xtalmul long XMUL FIT 4 'DON'T TOUCH THIS! - more than four preceding variables stops assembly with error ORGF 4 'DON'T TOUCH THIS! - fills unused memory to align with fixed reserved variables '-------------------------------------------------------- '*** Boot-loader can fill all four of the following *** '-------------------------------------------------------- hw_rev long 0 'hubRAM addr $010 - compatibility reserved variable - using to hold revA/B clk_freq long 25_000_000 'hubRAM addr $014 - sysclock frequency, integer frequency in hertz clk_mode long 0 'hubRAM addr $018 - clock mode config word, used directly in HUBSET asyn_baud long 115_200 'hubRAM addr $01c - comport baud rate, integer baud in hertz '-------------------------------------------------------- ========================================================================================= } CON ' Serial presets for host terminal DIAGRXPIN = 63 DIAGTXPIN = 62 ' Clock modes ' %0000_000e_dddddd_mmmmmmmmmm_pppp_cc_ss ' enable oscillator XOSC = %10 ' OSC ' %00=OFF, %01=OSC, %10=15pF, %11=30pF XSEL = %11 ' XI+PLL ' %00=rcfast(20+MHz), %01=rcslow(~20KHz), %10=XI(5ms), %11=XI+PLL(10ms) XPPPP = ((XDIVP>>1) + 15) & $F ' 1->15, 2->0, 4->1, 6->2...30->14 CLOCKFREQ = round(float(XTALFREQ) / float(XDIV) * float(XMUL) / float(XDIVP)) ' CLK_MODE = 1<<24 | (XDIV-1)<<18 | (XMUL-1)<<8 | XPPPP<<4 | XOSC<<2 | XSEL 'Select Event (SEx) modes E_LOCK_RISE = (%01 << 4) ' hub-lock rise event trigger E_LOCK_FALL = (%10 << 4) ' hub-lock fall event trigger E_LOCK_DIFF = (%11 << 4) ' hub-lock change event trigger E_PIN_RISE = (%001 << 6) ' pin rise event trigger E_PIN_FALL = (%010 << 6) ' pin fall event trigger E_PIN_DIFF = (%011 << 6) ' pin change event trigger E_PIN_LOW = (%100 << 6) ' pin low event trigger E_PIN_HIGH = (%110 << 6) ' pin high event trigger 'IRQ source IRQ_OFF = 0 IRQ_CT1 = 1 IRQ_CT2 = 2 IRQ_CT3 = 3 IRQ_SE1 = 4 IRQ_SE2 = 5 IRQ_SE3 = 6 IRQ_SE4 = 7 IRQ_PAT = 8 IRQ_FBW = 9 IRQ_XMT = 10 IRQ_XFI = 11 IRQ_XRO = 12 IRQ_XRL = 13 IRQ_ATN = 14 IRQ_QMT = 15 ' Pin modes ' *********************************************************** ' ***** PIN MODES INCOMPLETE ***** ONLY HAS WHAT I USED ***** ' *********************************************************** P_REGD = (%1 << 16) ' turn on clocked digital I/O (registered pins) P_IINV = (%1 << 15) ' invert digital pin input P_OINV = (%1 << 14) ' invert digital pin output P_FB_A = (%0001 << 17) ' feedback, inverted pinA -> output P_FB_B = (%0010 << 17) ' feedback, inverted pinB -> output P_FLOAT = (%111111 << 8) ' float digital output P_1K5R = (%001001 << 8) ' 1.5 kiloOhm digital output P_15KR = (%010010 << 8) ' 15 kiloOhm digital output P_1mA = (%100100 << 8) ' 1 milliAmp digital output P_COGDAC = (%01 << 6) ' select a cog/streamer for DAC level, smartpin must be off P_BITDAC = (%10 << 6) ' preset for DAC level (split in revB), smartpin off (default for smartpins when DACMODE) PM_DAC = (%101 << 18) ' DAC output (with optional ADC input), preset level PM_DAC_990 = PM_DAC |(%00 << 16) ' 990 Ohm, 3.3 Volt range PM_DAC_124 = PM_DAC |(%10 << 16) ' 124 Ohm, 3.3 Volt range PM_DAC_600 = PM_DAC |(%01 << 16) ' 600 Ohm, 2.0 Volt range PM_DAC_75 = PM_DAC |(%11 << 16) ' 75 Ohm, 2.0 Volt range PM_COMPDAC = (%1100 << 17) ' Analogue comparator with DAC as preset reference PM_ADC = (%100 << 18) ' turn on custom pin ADC input PM_ADC_GIO = (%000 << 15) |PM_ADC PM_ADC_VIO = (%001 << 15) |PM_ADC PM_ADC_B1 = (%010 << 15) |PM_ADC PM_ADC_A1 = (%011 << 15) |PM_ADC PM_ADC_A3 = (%100 << 15) |PM_ADC PM_ADC_A10 = (%101 << 15) |PM_ADC PM_ADC_A30 = (%110 << 15) |PM_ADC PM_ADC_A100 = (%111 << 15) |PM_ADC AF_PLUS1 = (%0001 << 28) AF_PLUS2 = (%0010 << 28) AF_PLUS3 = (%0011 << 28) AF_MINUS1 = (%0111 << 28) AF_MINUS2 = (%0110 << 28) AF_MINUS3 = (%0101 << 28) AF_OUT = (%0100 << 28) AF_NOT = (%1000 << 28) AF_PLUS1NOT = (%1001 << 28) AF_PLUS2NOT = (%1010 << 28) AF_PLUS3NOT = (%1011 << 28) AF_MINUS1NOT = (%1111 << 28) AF_MINUS2NOT = (%1110 << 28) AF_MINUS3NOT = (%1101 << 28) AF_OUTNOT = (%1100 << 28) BF_PLUS1 = (%0001 << 24) BF_PLUS2 = (%0010 << 24) BF_PLUS3 = (%0011 << 24) BF_MINUS1 = (%0111 << 24) BF_MINUS2 = (%0110 << 24) BF_MINUS3 = (%0101 << 24) BF_OUT = (%0100 << 24) BF_NOT = (%1000 << 24) BF_PLUS1NOT = (%1001 << 24) BF_PLUS2NOT = (%1010 << 24) BF_PLUS3NOT = (%1011 << 24) BF_MINUS1NOT = (%1111 << 24) BF_MINUS2NOT = (%1110 << 24) BF_MINUS3NOT = (%1101 << 24) BF_OUTNOT = (%1100 << 24) FA_AND = (%001 << 21) FA_OR = (%010 << 21) FA_XOR = (%011 << 21) F0_DEGLITCH = (%100 << 21) F1_DEGLITCH = (%101 << 21) F2_DEGLITCH = (%110 << 21) F3_DEGLITCH = (%111 << 21) H_DEGLITCH = (%1 << 30) 'HUBSET deglitch filter setup - Choose one of below, plus encoded divider H_F0_L2 = (%0000 << 5) |H_DEGLITCH H_F0_L3 = (%0001 << 5) |H_DEGLITCH H_F0_L5 = (%0010 << 5) |H_DEGLITCH H_F0_L8 = (%0011 << 5) |H_DEGLITCH H_F1_L2 = (%0100 << 5) |H_DEGLITCH H_F1_L3 = (%0101 << 5) |H_DEGLITCH H_F1_L5 = (%0110 << 5) |H_DEGLITCH H_F1_L8 = (%0111 << 5) |H_DEGLITCH H_F2_L2 = (%1000 << 5) |H_DEGLITCH H_F2_L3 = (%1001 << 5) |H_DEGLITCH H_F2_L5 = (%1010 << 5) |H_DEGLITCH H_F2_L8 = (%1011 << 5) |H_DEGLITCH H_F3_L2 = (%1100 << 5) |H_DEGLITCH H_F3_L3 = (%1101 << 5) |H_DEGLITCH H_F3_L5 = (%1110 << 5) |H_DEGLITCH H_F3_L8 = (%1111 << 5) |H_DEGLITCH ' Smartpin modes SP_OUT = (%01 << 6) ' enable digital output when DIR operates smartpin SPM_OFF = 0 ' smart pin off (default) SPM_REPOSITORY = %00001_0 ' long repository (P[12:10] != %101) SPM_DAC_RANDOM = %00001_0 |SP_OUT|PM_DAC ' DAC noise (P[12:10] = %101) SPM_DAC_RND = %00010_0 |SP_OUT|PM_DAC ' DAC 16-bit dither, noise (P[12:10] = %101) SPM_DAC_PWM = %00011_0 |SP_OUT|PM_DAC ' DAC 16-bit dither, PWM (P[12:10] = %101) SPM_PULSES = %00100_0 |SP_OUT ' pulse/cycle output SPM_STEPS = %00101_0 |SP_OUT ' transition output SPM_NCO_FREQ = %00110_0 |SP_OUT ' NCO frequency, X[15:0] = base period, Z += Y, OUT = Z[31] SPM_NCO_DUTY = %00111_0 |SP_OUT ' NCO duty, X[15:0] = base period, Z += Y, OUT = Z rollover SPM_PWM_TRI = %01000_0 |SP_OUT ' PWM triangle SPM_PWM_SAW = %01001_0 |SP_OUT ' PWM sawtooth SPM_PWM_SAW_FB = %01010_0 |SP_OUT ' PWM switch-mode power supply, V and I feedback SPM_CNT_QUAD = %01011_0 ' count: A-B quadrature encoder SPM_CNT_UP_ENA = %01100_0 ' count: A clock up, B enable SPM_CNT_DIR = %01101_0 ' count: A clock, B direction SPM_CNT_UP = %01110_0 ' count: (Y=%0) A clock up SPM_CNT_UP_DN = %01110_0 ' count: (Y=%1) A clock up, B clock down SPM_ACC_UP = %01111_0 ' accumulate: (Y=%0) A up SPM_ACC_UP_DN = %01111_0 ' accumulate: (Y=%1) A up, B down SPM_TIM_STEP = %10000_0 ' interval: of most recent step duration SPM_TIM_PULSE = %10001_0 ' interval: of most recent pulse duration SPM_TIM_MANY = %10010_0 ' interval: (Y=%0xx) of X number of accum/pulses/steps SPM_TIMEOUT = %10010_0 ' interval: (Y=%1xx) since most recent high/rise/edge, with X compare SPM_TIM_PULS = %10011_0 ' interval: of X number of A-B pulses/steps SPM_ACC_PULS = %10100_0 ' accumulate: pulses/steps, of X number of A-B pulses/steps SPM_TIM_OVER = %10101_0 ' interval: of A-B pulses/steps, for at least X duration SPM_ACC_OVER = %10110_0 ' accumulate: A-B pulses/steps, for at least X duration SPM_CNT_OVER = %10111_0 ' count: A-B pulses/steps, for at least X duration #ifdef PROP2_REVA SPM_USB_HOSTL = %11000_0 |SP_OUT ' USB host, low-speed (even/odd pin pair = DM/DP) SPM_USB_HOSTH = %11001_0 |SP_OUT ' USB host, high-speed (even/odd pin pair = DM/DP) SPM_USB_DEVL = %11010_0 |SP_OUT ' USB device, low-speed (even/odd pin pair = DM/DP) SPM_USB_DEVH = %11011_0 |SP_OUT ' USB device, high-speed (even/odd pin pair = DM/DP) #endif #ifdef PROP2_REVB SPM_ADX_ISINC = %11000_0 ' ADC sample/filter/capture, internally clocked SPM_ADX_ESINC = %11001_0 ' ADC sample/filter/capture, externally clocked SPM_ADX_SCOPE = %11010_0 ' ADC scope-mode, with trigger, internally clocked SPM_USB = %11011_0 |SP_OUT ' USB v1.0 host or device, (even/odd pin pair = DM/DP) #endif SPM_SSER_TX = %11100_0 |SP_OUT ' sync serial transmit (A-data, B-clock) SPM_SSER_RX = %11101_0 ' sync serial receive (A-data, B-clock) SPM_ASER_TX = %11110_0 |SP_OUT ' async serial transmit (baud) SPM_ASER_RX = %11111_0 ' async serial receive (baud) ADX_SAMPLE = (%00 << 20) ADX_SINC2 = (%01 << 20) ADX_SINC3 = (%10 << 20) ADX_BITSTM = (%11 << 20) ADX_1 = (%0000 << 16) ADX_2 = (%0001 << 16) ADX_4 = (%0010 << 16) ADX_8 = (%0011 << 16) ADX_16 = (%0100 << 16) ADX_32 = (%0101 << 16) ADX_64 = (%0110 << 16) ADX_128 = (%0111 << 16) ADX_256 = (%1000 << 16) ADX_512 = (%1001 << 16) ADX_1024 = (%1010 << 16) ADX_2048 = (%1011 << 16) ADX_4096 = (%1100 << 16) ADX_8192 = (%1101 << 16) ADX_16384 = (%1110 << 16) ADX_32768 = (%1111 << 16) SSTX_STOP = (%1 << 5) ' sync serial transmit first bit direct when empty (start-stop mode) SSRX_LATE = (%1 << 5) ' sync serial receiver post-clock sampling ' ***************************************************************** ' ***** STREAMER MODES ***** INCOMPLETE, ONLY HAS WHAT I USED ***** ' #ifdef PROP2_REVA ' Streamer modes for revA silicon 'XINIT D/#[15:0] transfer count (Number of NCO rollovers that the command will be active for) 'XINIT D/#[31:16] (x = don’t care) 'dddd = %0000 no streamer DAC output 'eppp = %1000 enable output on pins 31..0 ' mode dacs pins base S/# description ' ---- ---- ---- ---- ------ --------------------------- '%0011_dddd_eppp_xxxx %0 32-bit RFLONG '%1100_dddd_eppp_xxxx 32-bit immediate '%1000_dddd_eppp_bbbb 1-bit immediate LUT '%0001_dddd_eppp_pppx %00r00 1-bit RFBYTE, r=reorder '%0001_dddd_eppp_ppxx %00r01 2-bit RFBYTE, r=reorder '%0001_dddd_eppp_pxxx %00r10 4-bit RFBYTE, r=reorder '%0001_dddd_eppp_xxxx %00r11 8-bit RFBYTE, r=reorder DM_08bRF = (%0001 << 28) ' 8-bit RFBYTE DM_16bRF = (%0010 << 28) ' 16-bit RFWORD DM_32bRF = (%0011 << 28) ' 32-bit RFLONG DM_32bIMM = (%1100 << 28) ' 32-bit immediate DM_LUT1bIMM = (%1000 << 28) ' 1-bit immediate LUT, little-endian DM_LUT2bIMM = (%1001 << 28) ' 2-bit immediate LUT, little-endian DM_LUT4bIMM = (%1010 << 28) ' 4-bit immediate LUT, little-endian DM_LUT8bIMM = (%1011 << 28) ' 8-bit immediate LUT, little-endian #endif #ifdef PROP2_REVB ' Streamer modes for revB silicon 'XINIT D/#[15:0] transfer count (Number of NCO rollovers that the command will be active for) 'XINIT D/#[31:16] (x = don’t care) 'dddd = %0000 no streamer DAC output 'eppp = %1000 enable output on pins 31..0 ' mode dacs pins base S/# description ' ---- ---- ---- ---- ------ --------------------------- '%1000 dddd eppp pppa - 1/8 RFBYTE -> 1-pin + 1-DAC1 '%1001 dddd eppp pp0a - 1/4 RFBYTE -> 2-pin + 2-DAC1 '%1001 dddd eppp pp1a - 1/4 RFBYTE -> 2-pin + 1-DAC2 '%1010 dddd eppp p00a - 1/2 RFBYTE -> 4-pin + 4-DAC1 '%1010 dddd eppp p01a - 1/2 RFBYTE -> 4-pin + 2-DAC2 '%1010 dddd eppp p10a - 1/2 RFBYTE -> 4-pin + 1-DAC4 '%1010 dddd eppp 0110 - RFBYTE -> 8-pin + 4-DAC2 '%1010 dddd eppp 0111 - RFBYTE -> 8-pin + 2-DAC4 '%1010 dddd eppp 1110 - RFBYTE -> 8-pin + 1-DAC8 '%1010 dddd eppp 1111 - RFWORD -> 16-pin + 4-DAC4 '%1011 dddd eppp 0000 - RFWORD -> 16-pin + 2-DAC8 '%1011 dddd eppp 0001 - RFLONG -> 32-pin + 4-DAC8 '%0000 dddd eppp bbbb imm -> 32 x 1-bit LUT '%0100 dddd eppp pppa imm 32 x 1 -> 1-pin + 1-DAC1 '%0111 dddd eppp 0001 imm 1 x 32 -> 32-pin + 4-DAC8 DM_1bRFbe = (%1000 << 28)|(%1 << 16) ' 1-bit RFBYTE, big-endian DM_1bRFle = (%1000 << 28)|(%0 << 16) ' 1-bit RFBYTE, little-endian DM_2bRFbe = (%1001 << 28)|(%11 << 16) ' 2-bit RFBYTE, big-endian DM_2bRFle = (%1001 << 28)|(%10 << 16) ' 2-bit RFBYTE, little-endian DM_4bRFbe = (%1010 << 28)|(%101 << 16) ' 4-bit RFBYTE, big-endian DM_4bRFle = (%1010 << 28)|(%100 << 16) ' 4-bit RFBYTE, little-endian DM_8bRF = (%1010 << 28)|(%1110 << 16) ' 8-bit RFBYTE DM_16bRF = (%1011 << 28) ' 16-bit RFWORD DM_32bRF = (%1011 << 28)|(%0001 << 16) ' 32-bit RFLONG DM_1bIMMbe = (%0100 << 28)|(%1 << 16) ' 1-bit immediate, big-endian DM_1bIMMle = (%0100 << 28)|(%0 << 16) ' 1-bit immediate, little-endian DM_2bIMMbe = (%0101 << 28)|(%11 << 16) ' 2-bit immediate, big-endian DM_2bIMMle = (%0101 << 28)|(%10 << 16) ' 2-bit immediate, little-endian DM_4bIMMbe = (%0110 << 28)|(%101 << 16) ' 4-bit immediate, big-endian DM_4bIMMle = (%0110 << 28)|(%100 << 16) ' 4-bit immediate, little-endian DM_8bIMM = (%0110 << 28)|(%1110 << 16) ' 8-bit immediate DM_16bIMM = (%0111 << 28)|(%0000 << 16) ' 16-bit immediate DM_32bIMM = (%0111 << 28)|(%0001 << 16) ' 32-bit immediate DM_LUT1bIMM = (%0000 << 28) ' 1-bit immediate LUT, little-endian DM_LUT2bIMM = (%0001 << 28) ' 2-bit immediate LUT, little-endian DM_LUT4bIMM = (%0010 << 28) ' 4-bit immediate LUT, little-endian DM_LUT8bIMM = (%0011 << 28) ' 8-bit immediate LUT, little-endian '1100 dddd wppp pppa - 1-pin -> 1-DAC1 + 1/8 WFBYTE '1101 dddd wppp pp0a - 2-pin -> 2-DAC1 + 1/4 WFBYTE '1101 dddd wppp pp1a - 2-pin -> 1-DAC2 + 1/4 WFBYTE '1110 dddd wppp p00a - 4-pin -> 4-DAC1 + 1/2 WFBYTE '1110 dddd wppp p01a - 4-pin -> 2-DAC2 + 1/2 WFBYTE '1110 dddd wppp p10a - 4-pin -> 1-DAC4 + 1/2 WFBYTE '1110 dddd wppp 0110 - 8-pin -> 4-DAC2 + WFBYTE '1110 dddd wppp 0111 - 8-pin -> 2-DAC4 + WFBYTE '1110 dddd wppp 1110 - 8-pin -> 1-DAC8 + WFBYTE '1110 dddd wppp 1111 - 16-pin -> 4-DAC4 + WFWORD '1111 dddd wppp 0000 - 16-pin -> 2-DAC8 + WFWORD '1111 dddd wppp 0001 - 32-pin -> 4-DAC8 + WFLONG DM_1bWFbe = (%1100 << 28)|(%1 << 16) ' 1-bit WFBYTE, big-endian DM_1bWFle = (%1100 << 28)|(%0 << 16) ' 1-bit WFBYTE, little-endian DM_2bWFbe = (%1101 << 28)|(%11 << 16) ' 2-bit WFBYTE, big-endian DM_2bWFle = (%1101 << 28)|(%10 << 16) ' 2-bit WFBYTE, little-endian DM_4bWFbe = (%1110 << 28)|(%101 << 16) ' 4-bit WFBYTE, big-endian DM_4bWFle = (%1110 << 28)|(%100 << 16) ' 4-bit WFBYTE, little-endian DM_8bWF = (%1110 << 28)|(%1110 << 16) ' 8-bit WFBYTE DM_16bWF = (%1111 << 28) ' 16-bit WFWORD DM_32bWF = (%1111 << 28)|(%0001 << 16) ' 32-bit WFLONG #endif ' Common streamer constants DM_DIGI_IO = (1 << 23) DAT ALIGNL ORG $200 'longword addressing '****************************************************************************** ' LUT Code (Has to be copied from hubram to lutram) '****************************************************************************** _LUT_code '=============================================== 'Integer multiply 32-bit x 16-bit. pa = pa x pb. 10 clocks ' input: pa, pb ' result: pa 'scratch: temp1 ' mul32x16 getword temp1, pa, #1 mul temp1, pb 'pah * pbl mul pa, pb 'pal * pbl shl temp1, #16 _ret_ add pa, temp1 '=============================================== 'Integer multiply 32-bit x 32-bit. pa = pa x pb. 16 clocks ' input: pa, pb ' result: pa 'scratch: temp1, temp2 ' mul32x32 getword temp1, pa, #1 getword temp2, pb, #1 mul temp1, pb 'pah * pbl mul temp2, pa 'pal * pbh mul pa, pb 'pal * pbl (importantly, MUL only uses lower 16 bits as inputs) add temp1, temp2 shl temp1, #16 _ret_ add pa, temp1 '=============================================== 'Integer multiply 64-bit x 32-bit. r64 = a64 x pb. 52 clocks excluding CALL/RET ' input: a64, pb (all remain intact) ' result: r64 'scratch: pa, a1, b1 ' 'https://forums.parallax.com/discussion/169698/substantially-faster-shorter-multiply/p1 ' 1 2 3 4 5 6 7 ' result = a0*b0 + a1*b0 + a2*b0 + a3*b0 + a0*b1 + a1*b1 + a2*b1 ' mul64x32 mov r64, a64 mul r64, pb '1: low, a0 * b0 getword r64h, a64, #1 getword b1, pb, #1 mul r64h, b1 '6: high, a1 * b1 mov pa, a64h mul pa, pb '3: a2 * b0 :Note that all MUL's are 16b x 16b = 32b add r64h, pa '3: high mov pa, a64h mul pa, b1 '7: a2 * b1 getword a1, a64h, #1 mul a1, pb '4: a3 * b0 add pa, a1 '4: high shl pa, #16 add r64h, pa '7: high getword a1, a64, #1 mul a1, pb '2: a1 * b0 getword pa, a1, #1 ' a1 is 50% in both r64 and r64h shl a1, #16 add r64, a1 wc '2: low addx r64h, pa '2: high mul b1, a64 '5: a0 * b1 getword pa, b1, #1 ' b1 is 50% in both r64 and r64h shl b1, #16 add r64, b1 wc '5: low addx r64h, pa '5: high ret wcz '=============================================== ' input: (none) ' result: pb 'scratch: (none) ' getch testp #DIAGRXPIN wz 'byte received? (IN high == yes) if_z rdpin pb, #DIAGRXPIN 'get data from Z buffer if_z shr pb, #32-8 'shift the data to bottom of register if_z ret wcz 'restore C/Z flags of calling routine jmp #getch 'wait while Smartpin buffer is empty '=============================================== ' input: pb ' result: (none) 'scratch: (none) ' putch rqpin inb, #DIAGTXPIN wc 'transmiting? (C high == yes) *Needed to initiate tx testp #DIAGTXPIN wz 'buffer free? (IN high == yes) if_nc_or_z wypin pb, #DIAGTXPIN 'write new byte to Y buffer if_nc_or_z ret wcz 'restore C/Z flags of calling routine jmp #putch 'wait while Smartpin is both full (nz) and transmitting (c) '=============================================== 'Wait for comport transmitting to complete ' input: (none) ' result: (none) 'scratch: (none) ' waittx rqpin inb, #DIAGTXPIN wc 'transmiting? (C high == yes) if_nc ret wcz jmp #waittx '=============================================== 'Emit CR/LF ' input: (none) ' result: (none) 'scratch: pb ' putnl callpb #13, #putch mov pb, #10 jmp #putch '=============================================== 'Emit three spaces ' input: (none) ' result: (none) 'scratch: pb ' putsp callpb #" ", #putch call #putch jmp #putch '=============================================== 'Emit string ' input: pa - hubRAM address of string ' result: (none) 'scratch: pa, pb ' puts rdbyte pb, pa wz if_z ret wcz 'null termination, C/Z preserved call #putch 'emit character ijnz pa, #puts 'increment pointer (assumes non-zero address) '=============================================== 'Emit string from immediate code in hubRAM ' input: (hardware call stack) - hubRAM address of string ' result: (none) 'scratch: pa, pb ' putsi pop pa 'address of immediate data following the CALL (includes the calling C/Z flags) .loop rdbyte pb, pa wz 'get next charater, Z sets with null termination add pa, #1 'not using PTRA retains binary compatibility between revA and revB if_z calld pa, pa wcz 'RET equivalent, prior C/Z restored call #putch 'emit character jmp #.loop { mov temp1, ptra 'preserve existing PTRA pop ptra 'address of immediate data following the CALL (includes the calling C/Z flags) .loop rdbyte pb, ptra++ wz 'get next charater, Z sets with null termination if_nz call #putch 'emit character if_nz jmp #.loop push ptra 'update return address to instruction following the null character mov ptra, temp1 'PTRA restored ret wcz 'C/Z restored } '=============================================== 'Emit status of C/Z flags ' input: (C/Z flags) ' result: (none) 'scratch: pb ' emitflags call #putsp callpb #"C", #putch callpb #"=", #putch if_c callpb #"1", #putch if_nc callpb #"0", #putch call #putsp callpb #"Z", #putch callpb #"=", #putch if_z callpb #"1", #putch if_nz callpb #"0", #putch jmp #putsp '=============================================== 'Integer (32-bit) to ascii binary and emit ' input: pa ' result: (none) 'scratch: pa, pb, bcdi ' itobl rev pa 'least significant first itob mov bcdi, bcdlen sub bcdi, #1 .emit testb pa, bcdi wc if_c callpb #"1", #putch if_nc callpb #"0", #putch djnf bcdi, #.emit ret wcz 'restore C/Z flags of calling routine '=============================================== 'Integer (32-bit) to ascii hexidecimal and emit ' input: pa ' result: (none) 'scratch: pa, pb, bcdi ' itohl rev pa 'least significant first itoh mov bcdi, bcdlen 'most significant nibble first (zero extended) sub bcdi, #1 .emit altgn bcdi, #pa '(instruction prefix) getnib pb 'retrieve next hex digit from pa register: pb = pa[bcdi] cmp pb, #10 wcz 'test if below 10, C = borrow of (D - S) if_c add pb, #"0" 'ASCII encode 0-9 if_nc add pb, #"a"-10 'ASCII encode a-f call #putch djnf bcdi, #.emit ret wcz 'restore C/Z flags of calling routine '=============================================== 'Integer (32-bit) to ascii decimal and emit ' Note: Uses the CORDIC. This means that any already running operations will be corrupted ' Also requires bcdlen set for the number of digits to be emitted ' If bit8 of bcdlen is set then leading zeros will be emitted ' input: pa, bcdlen ' result: (none) 'scratch: pa, pb, bcdi, bcdstr, temp1 ' itos cmps pa, #0 wc if_c neg pa if_c mov pb, #"-" if_c call #putch itod 'bundle 32-bit integer to BCD array qdiv pa, #10 'had to cheat. It's hard without divide and modulo mov bcdstr, #0 'clear bcdstr to all zeros mov bcdstr+1, #0 mov bcdi, #0 'reset digit index mov temp1, bcdlen and temp1, #$ff fle temp1, #16 'hard limit of 16 digits for string length fge temp1, #1 testb bcdlen, #8 wc 'prepend leading zeros (early test) .makebcd getqx pa wz 'collect divided result for recursion jnqmt #.makebcd 'wait for QMT flag to collect final results - CORDIC pipeline flushed getqy pb 'collect decimal digit (modulo'd remainder) if_nz qdiv pa, #10 'recurse for next digit altsn bcdi, #bcdstr '(instruction prefix) setnib 0-0, pb, #0-0 '(p2asm neeeds extended form) File the decimal digit as BCD: bcdstr[bcdi] = pb add bcdi, #1 if_nz jmp #.makebcd 'Emit BCD as an ASCII string to comport fge bcdi, temp1 'set minimum string length sub bcdi, #1 wz 'to suit zero based indexing if_z jmp #.emit .leadin altgn bcdi, #bcdstr '(instruction prefix) getnib pb 'retrieve next digit from BCD: pb = bcdstr[bcdi] cmp pb, #0 wz if_z_and_nc mov pb, #" " 'replace with leading spaces if_z_and_c mov pb, #"0" 'replace with leading zeros if_z call #putch 'Relies on #putch preserving C/Z flags if_z djnz bcdi, #.leadin .emit altgn bcdi, #bcdstr '(instruction prefix) getnib pb 'retrieve next digit from BCD: pb = bcdstr[bcdi] add pb, #"0" 'encode ASCII call #putch djnf bcdi, #.emit ret wcz 'restore C/Z flags of calling routine '=============================================== 'Emit sysclock frequency ' Note: Uses the CORDIC. This means that any already running operations will be lost ' input: clk_freq ' result: (none) 'scratch: pa, pb, temp2 ' emitclkfrq qdiv clk_freq, ##1_000_000 pollqmt 'clear old event .flushloop getqx pa 'MHz whole number - at final pipeline result jnqmt #.flushloop 'wait for QMT flag to collect final results - CORDIC pipeline flushed getqy temp2 'remainder - six decimal places call #itod 'uses cordic! qdiv temp2, #100 'remove least two digits mov temp2, bcdlen 'preserve bcdlen callpb #".", #putch mov bcdlen, #$104 'format to four decimal places with leading zeros getqx pa call #itod 'uses cordic! _ret_ mov bcdlen, temp2 'restore bcdlen '=============================================== 'Set new sysclock frequency from a dynamic XMUL(xtalmul) 'and also adjusts the diag comport to suit ' Note: Uses the CORDIC. This means that any already running operations will be lost ' Also uses the crystal constants ' input: xtalmul, asyn_baud, clk_mode ' result: clk_mode, clk_freq 'scratch: pa, pb, temp1 ' setclkfrq getqx inb 'get excess results, final one sets event flag jnqmt #setclkfrq 'wait for flag to collect final results - CORDIC pipeline flushed 'recalculate sysclock hertz using cordic qmul xtalmul, ##(XTALFREQ / XDIV / XDIVP) 'integer component of pre-divided crystal frequency mov pa, xtalmul mul pa, ##round((float(XDIV*XDIVP)+0.5) * (float(XTALFREQ)/float(XDIV)/float(XDIVP) - float(XTALFREQ/XDIV/XDIVP))) qdiv pa, ##(XDIV * XDIVP) 'fractional component of pre-divided crystal frequency getqx clk_freq 'result of integer component getqx pa 'result of fractional component add clk_freq, pa 'de-error the integer rounding { 'this section disabled, more compact alternative below 'recalculate baud divider (clk_freq / asyn_baud) of diag comport using cordic ' low bauds won't operate at high sysclocks, the divider only has 16-bit reach 'apply max of *64 to copy of clk_freq to achieve 16.6 format encod temp1, clk_freq 'bit position of msb subr temp1, #31 'distance from bit position 31 fle temp1, #6 'cap at distance 6 mov pa, clk_freq shl pa, temp1 'shift significant bits up to bit position 31 'apply remaining of /64 to copy of asyn_baud subr temp1, #6 'remaining distance mov pb, asyn_baud shr pb, temp1 'shift down to make up distance 6 if needed, truncates baud 'comport divider (clk_freq / asyn_baud) in 16.6 format qdiv pa, pb getqx pa shl pa, #10 'WXPIN format = %DDDDDDDDDDDDDDDD.DDDDDD_xxxxx_FFFFF sets pa, #7 'comport 8N1 framing } 'recalculate baud divider (clk_freq / asyn_baud) of diag comport using cordic ' low bauds won't operate at high sysclocks, the divider only has 16-bit reach qdiv clk_freq, asyn_baud 'comport divider qfrac #1, asyn_baud 'remainder scale factor, 2**32 / baud getqx pa 'comport divider getqy pb 'divider remainder, for .6 fraction getqx temp1 'scale factor qmul pb, temp1 'convert remainder to a "big" fraction getqx pb 'fractional component of comport divider rolword pa, pb, #1 '16.16 comport divider sets pa, #7 'comport 8N1 framing (bottom 10 bits should be replaced but 9's enough) call #waittx wxpin pa, #DIAGTXPIN 'set tx baud and framing (divider format is 16.0 if divider >= 1024.0) wxpin pa, #DIAGRXPIN 'set rx baud and framing (divider format is 10.6 if divider < 1024.0) { 'adjust hardware to new XMUL sysclock frequency andn clk_mode, #%11 'clear the two select bits to force RCFAST selection hubset clk_mode '**IMPORTANT** Switches to RCFAST using known prior mode mov clk_mode, xtalmul 'replace old with new ... sub clk_mode, #1 'range 1-1024 shl clk_mode, #8 or clk_mode, ##(1<<24 + (XDIV-1)<<18 + XPPPP<<4 + XOSC<<2) hubset clk_mode 'setup PLL mode for new frequency (still operating at RCFAST) or clk_mode, #XSEL 'add PLL as the clock source select waitx ##25_000_000/100 '~10ms (at RCFAST) for PLL to stabilise hubset clk_mode 'engage! Switch back to newly set PLL ret wcz } 'adjust hardware to new XMUL sysclock frequency hubset #$f0 | XOSC<<2 'Switches to RCFAST using safe PLL config (needed work-around) mov clk_mode, xtalmul 'replace old with new ... sub clk_mode, #1 'range 1-1024 shl clk_mode, #8 or clk_mode, ##(1<<24 + (XDIV-1)<<18 + XPPPP<<4 + XOSC<<2) hubset clk_mode 'setup PLL mode for new frequency (still operating at RCFAST) or clk_mode, #XSEL 'add PLL as the clock source select waitx ##25_000_000/100 '~10ms (at RCFAST) for PLL to stabilise hubset clk_mode 'engage! Switch back to newly set PLL ret wcz _LUT_end FIT $400 ORGH ($ < $400) ? $400 : $ ALIGNL '=============================================== _diaginit 'only called once at beginning 'FPGA frequencies ' hubset #$0f 'change to 5 MHz sysclock ' hubset #$1f 'change to 10 MHz sysclock ' hubset #$2f 'change to 15 MHz sysclock ' hubset #$3f 'change to 20 MHz sysclock ' hubset #$4f 'change to 25 MHz sysclock ' hubset #$5f 'change to 30 MHz sysclock ' hubset #$6f 'change to 35 MHz sysclock ' hubset #$7f 'change to 40 MHz sysclock ' hubset #$8f 'change to 45 MHz sysclock ' hubset #$9f 'change to 50 MHz sysclock ' hubset #$af 'change to 55 MHz sysclock ' hubset #$bf 'change to 60 MHz sysclock ' hubset #$cf 'change to 65 MHz sysclock ' hubset #$df 'change to 70 MHz sysclock ' hubset #$ef 'change to 75 MHz sysclock ' hubset #$ff 'change to 80 MHz sysclock '-------- Copy lut code into position -------- setq2 #(_LUT_end - _LUT_code - 1) 'copy length, in longwords rdlong 0, ##@_LUT_code 'the "0" is lutRAM zero, or $200 in program memory map '--------- Detect available smartpins ------- 'Returns a 64-bit bitmap indicating active smartpins - mask_lsb/mask_msb. mov smart_pin, #63 'test all 64 pins .searchloop mov pa, ##$c0ffee00 add pa, smart_pin 'unique pattern wrpin #%11_0, smart_pin 'longword repository smartpin mode dirh smart_pin wxpin pa, smart_pin 'write longword to smartpin, two instructions to take effect wxpin #0, smart_pin 'clear it again rdpin pb, smart_pin 'get longword from smartpin repository dirl smart_pin wrpin #0, smart_pin 'turn off smartpin cmp pb, pa wz 'valid response? altb smart_pin, #mask_lsb 'extracts cogRAM address as if bitfield addressing - bitwise ALTxx bitz 0-0, smart_pin 'S value (smart_pin) is masked to least 5 bits by the instruction djnf smart_pin, #.searchloop 'next pin '----- Configure diag comport to use smartpins instead of bit-bashing ----- wrpin ##SPM_ASER_TX|P_REGD, #DIAGTXPIN 'Asynchronous serial transmit mode dirh #DIAGTXPIN ' wypin #0, #DIAGTXPIN 'trigger first tx ready state (not needed if dual checked) 'single check is buffer full only, dual checking adds in tx flag wrpin ##SPM_ASER_RX|P_REGD, #DIAGRXPIN 'Asynchronous serial receive dirh #DIAGRXPIN 'silicon rev A/B detect mov pa, #1 xoro32 pa 'revA (D = $42a01290 S = $50ad0021), revB (D = $84908405 S = $62690201) mov pa, 0-0 cmp pa, ##$50ad0021 wz if_z mov hw_rev, #01 'revA if_nz mov hw_rev, #02 'revB (or something else) ' mov ptra, #1 ' rdlut pa,ptra++ 'this is an error with assemblers targetting revA (v32) ' mov hw_rev, ptra '1 = revA, 2 = revB 'set initial sysclock frequency call #setclkfrq '........................................... 'NOTE: Comport is now fully configered! '........................................... mov msec, clk_freq shr msec, #2 '250 ms delay for diag terminal to start waitx msec ' mov bcdlen, #8 ' mov pa, temp4 'copy of shift left for clk_freq ' call #itoh ' call #putsp ' mov pa, temp1 'copy of shift right for asyn_baud ' call #itoh ' call #putsp mov bcdlen, #1 'decide on reporting cogid pa cmp pa, #0 wz if_nz jmp #.skip_report 'emit smartpin report ' loc pa, #initmsg3 call #putsi byte 10,13,"Total smartpins = ",0 ones pa, mask_msb ones pb, mask_lsb add pa, pb call #itod call #putsp mov bcdlen, #32 mov pa, mask_msb call #itob mov pa, mask_lsb call #itob mov bcdlen, #1 ' jmp #putnl 'silicon rev A/B detect cmp hw_rev, #2 wc 'C = 1 if revA (D = $42a01290 S = $50ad0021), C = 0 if revB (D = $84908405 S = $62690201) if_c loc pa, #initmsg4 'revA if_nc loc pa, #initmsg5 'revB call #puts 'emit sysclock frequency call #putsi byte " silicon. Sysclock ",0 call #emitclkfrq call #putsi byte " MHz",10,13,0 .skip_report call #waittx mov dirb, #0 mov outb, #0 mov dira, #0 mov outa, #0 dirh #DIAGTXPIN dirh #DIAGRXPIN jmp #_main '----------------------------------------------------- 'initmsg1 byte " silicon. System clock frequency set to ",0 'initmsg2 byte " MHz",10,13,0 'initmsg3 byte 10,13,"Total smartpins = ",0 initmsg4 byte 10,13,"Rev A",0 initmsg5 byte 10,13,"Rev B",0 ORG $1e0 bcdlen res 1 ' itod's minimum print length - setable parameter bcdi smart_pin a1 res 1 bcdstr ' itod's temporary BCD buffer b1 res 1 temp4 a64 res 1 mask_lsb temp3 a64h res 1 mask_msb temp2 r64 res 1 temp1 r64h res 1