CON XTALFREQ = 20_000_000 'PLL stage 0: crystal frequency XDIV = 2 'PLL stage 1: crystal divider XMUL = 8 'PLL stage 2: crystal / div * mul XDIVP = 1 'PLL stage 3: crystal / div * mul / divp (1,2,4..30) 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)) SETFREQ = 1<<24 + (XDIV-1)<<18 + (XMUL-1)<<8 + XPPPP<<4 + XOSC<<2 ENAFREQ = SETFREQ + XSEL ' %0000_000e_dddddd_mmmmmmmmmm_pppp_cc_ss ' enable oscillator 'Serial presets for data logging rx_pin = 63 tx_pin = 62 BAUDRATE = 115_200 ASYNCFG = round(float(CLOCKFREQ) * 64.0 / float(BAUDRATE))<<10 + 7 'bitrate format is 16.6<<10, 8N1 framing DAT 'not Spin code ORGH 0 'loaded to hubram at address 0 ORG 'longword addressing at 0 '******************************************************************************* ' COG Variables (Auto-copied to cogram on COGINIT #%0x_xxxx,#0 after program load) '******************************************************************************* count jmp #_diaginit sec long CLOCKFREQ/2 misc1 pincfg tickstart long 0 misc2 pin tickend long 0 '-------------------------------------------------------- '*** Boot-loader can fill all four of the following *** '-------------------------------------------------------- spare1 long 0 'hubRAM addr $010 - compatible reserved for system variable clk_freq long CLOCKFREQ '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 BAUDRATE 'hubRAM addr $01c - comport baud rate, integer baud in hertz '-------------------------------------------------------- loctest1 long $11111111 ' Cogram address is 8, hubram equivalent address is $20 '******************************************************************************* _main loc pa, #\@titlestr call #puts loc pa, #\@cogxstr call #puts loc pa, #\@hdrstr call #puts loc pa, #loctest1 call #diagloc loc pa, #loctest2 call #diagloc loc pa, #loctest3 call #diagloc loc pa, #loctest4 call #diagloc ' call #getch ' jmp #_main jmp #loctesthub ORGH $110 loctest2 long $22222222 ' Cogram equivalent address is $44 '******************************************************************************* ' HUB Code '******************************************************************************* ORGH $400 ALIGNL loctesthub loc pa, #\@hubxstr call #puts loc pa, #\@hdrstr call #puts loc pa, #loctest1 call #diagloc loc pa, #loctest2 call #diagloc loc pa, #loctest3 call #diagloc loc pa, #loctest4 call #diagloc ' call #getch ' jmp #_main jmp #loctestlut loctest3 long $33333333 '------------------------------------- diagloc mov misc1, pa 'stash PA pop misc2 'grab caller address push misc2 'restack it and misc2, ##$3fff_ffff 'mask out the condition codes cmp misc2, ##$400 wc 'test if caller is cogexec or hubexec, C = borrow of (D - S) if_c sub misc2, #2 'caller is cogexec if_nc sub misc2, #8 'caller is hubexec 'PC value to fetch LOC opcode mov pa, misc2 call #itoh 'print address of LOC opcode mov pb, #" " call #putch 'print a space 'LOC opcode if_nc rdlong pa, misc2 'fetch opcode from hubram modcz 0,_C wz 'copy C to Z cmp misc2, #$1ff wc 'test if caller is cogexec or lutexec, C = borrow of (D - S) if_z_and_c alts misc2 'MOV indirection - get register content of register number in "misc2" if_z_and_c mov pa, 0-0 'fetch opcode from cogram if_z_and_nc rdlut pa, misc2 'fetch opcode from lutram call #itoh 'print LOC opcode mov pb, #" " call #putch 'print a space 'PA content mov pa, misc1 call #itoh 'print stashed PA value call #putsp 'cog dereference alts misc1 'MOV indirection mov pa, 0-0 'fetch content from cogram location that the stashed PA pointed to call #itoh 'print mov pb, #" " call #putch 'print a space 'hub dereference rdlong pa, misc1 'fetch content from hubram location that the stashed PA pointed to call #itoh 'print mov pb, #" " call #putch 'print a space 'lut dereference rdlut pa, misc1 'fetch content from lutram location that the stashed PA pointed to call #itoh 'print jmp #putnl titlestr byte 13,10," loc pa, #label testing",13,10,"=========================",13,10,0 hdrstr byte 13,10," PC Op-code PA-data Cog-dref Hub-dref LUT-dref",13,10,0 cogxstr byte " cogexec",0 hubxstr byte 13,10," hubexec",0 lutxstr byte 13,10," lutexec",0 cogramstr byte "cogram ",0 hubramstr byte "hubram ",0 lutramstr byte "lutram ",0 '******************************************************************************* ' Subroutines '******************************************************************************* ORGH 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 'Silicon frequencies hubset clk_mode 'switch to RCFAST using known prior mode mov clk_mode, ##SETFREQ 'replace old with new ' mov clk_freq, ##CLOCKFREQ 'optional, if clk_freq used hubset clk_mode 'setup for new mode, still RCFAST waitx ##20_000_000/100 '~10ms for crystal/PLL to come up to speed hubset ##ENAFREQ 'engage 'Detect available smart pins 'Returns total number of available smart pins 'and a 64 bit mask indicating active smart pins. mov available, #0 mov smart_pin, #63 'test all 64 pins .searchloop wrpin #%11_0, smart_pin 'long repository mode dirh smart_pin mov pattern, ##$c0ffee00 add pattern, smart_pin 'unique pattern wxpin pattern, smart_pin 'write long to smart pin shl mask_lsb, #1 wc 'build valid smart pin mask rcl mask_msb, #1 rdpin response, smart_pin 'get long from smart pin repository cmp response, pattern wz 'valid response? if_e add available, #1 if_e bith mask_lsb, #0 dirl smart_pin wrpin #0, smart_pin 'disable smart pin djnf smart_pin, #.searchloop 'next smart pin '-------- 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 memory map '----- Configure diag comport to use smartpins instead of bit-bashing ----- wrpin #%00_11111_0, #rx_pin 'Asynchronous serial receive wxpin ##ASYNCFG, #rx_pin 'set baurdrate and framing dirh #rx_pin wrpin #%01_11110_0, #tx_pin 'Asynchronous serial transmit mode wxpin ##ASYNCFG, #tx_pin 'set X with baudrate and framing dirh #tx_pin ' wypin #0, #tx_pin 'trigger first tx ready state (not needed if dual checked) 'single check is buffer full only, dual checking adds in tx flag waitx ##CLOCKFREQ/4 '250 ms delay for diag terminal to start mov bcdlen, #1 'decide on reporting cogid pa cmp pa, #0 wz if_nz jmp #_main 'emit smartpin report loc pa, #\@initmsg3 call #puts mov pa, available call #itod call #putsp mov pa, mask_msb call #itob mov pa, mask_lsb call #itob ' jmp #putnl 'emit sysclock frequency loc pa, #\@initmsg1 call #puts mov pa, #CLOCKFREQ/1_000_000 call #itod loc pa, #\@initmsg2 call #puts 'derived crystal freq ' mov pa, xtal_freq ' call #itod ' call #putnl jmp #_main '----------------------------------------------------- initmsg10 byte 13,10,"w 60 . . . .50 . . . .40 . . . .30 . . . .20 . . . .10 . . . . 0",13,10,0 initmsg11 byte 13,10," OUT fed back",0 initmsg12 byte 13,10," Unregistered",0 initmsg13 byte 13,10," Registered",0 initmsg3 byte 10,13,"Total smartpins = ",0 initmsg1 byte 10,13,"System clock frequency set to ",0 initmsg2 byte " MHz",10,13,0 'initmsg2 byte " MHz. Crystal = ",0 ORG 80 pattern res 1 response res 1 smart_pin res 1 available res 1 mask_lsb res 1 mask_msb res 1 xtal_freq res 1 clk_mul res 1 clk_div res 1 bcdi temp1 res 1 bcdlen res 1 bcdstr temp2 res 1 a1 res 1 a3 res 1 b1 res 1 a64 res 1 a64h res 1 r64 res 1 r64h res 1 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 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: temp1, temp2, a1, a3, b1 ' mul64x32 getword a1, a64, #1 getword a3, a64h, #1 getword b1, pb, #1 mov temp1, a64h mul temp1, pb 'a2 * b0 mov r64h, a1 mul r64h, b1 '6: high, a1 * b1 add r64h, temp1 '3: high mul a3, pb 'a3 * b0 mov temp2, a64h mul temp2, b1 'a2 * b1 add temp2, a3 '4: high shl temp2, #16 add r64h, temp2 '7: high mov r64, a64 mul r64, pb '1: low, a0 * b0 mul a1, pb 'a1 * b0 mul b1, a64 'a0 * b1 getword temp1, a1, #1 getword temp2, b1, #1 shl a1, #16 shl b1, #16 add r64, a1 wc '2: low addx r64h, temp1 '2: high add r64, b1 wc '5: low addx r64h, temp2 '5: high ret wcz '=============================================== ' input: (none) ' result: pb 'scratch: (none) ' getch testp #rx_pin wz 'byte received? (IN high == yes) if_z rdpin pb, #rx_pin 'get data 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 is idle '=============================================== ' input: pb ' result: (none) 'scratch: (none) ' putch rqpin inb, #tx_pin wc 'transmiting? (C high == yes) *Needed to initiate tx testp #tx_pin wz 'buffer free? (IN high == yes) if_z_or_nc wypin pb, #tx_pin 'write new byte to Y buffer if_z_or_nc ret wcz 'restore C/Z flags of calling routine jmp #putch 'wait while Smartpin is both full (nz) and transmitting (c) '=============================================== 'Emit CR/LF ' input: (none) ' result: (none) 'scratch: pb ' putnl mov pb, #13 call #putch mov pb, #10 jmp #putch '=============================================== 'Emit three spaces ' input: (none) ' result: (none) 'scratch: pb ' putsp mov pb, #" " call #putch call #putch jmp #putch '=============================================== 'Emit status of C/Z flags ' input: (C/Z flags) ' result: (none) 'scratch: pb ' emitflags mov pb, #"C" call #putch mov pb, #"=" call #putch if_c mov pb, #"1" if_nc mov pb, #"0" call #putch call #putsp mov pb, #"Z" call #putch mov pb, #"=" call #putch if_z mov pb, #"1" if_nz mov pb, #"0" call #putch jmp #putnl '=============================================== '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) '=============================================== '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, #32 .emit rol pa, #1 wc if_nc mov pb, #"0" if_c mov pb, #"1" call #putch djnz 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, #7 'most significant nibble first (zero extended) .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 ' input: pa, bcdlen ' result: (none) 'scratch: pa, pb, bcdi, bcdstr ' 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 fle bcdlen, #16 'hard limit of 16 digits for string length fge bcdlen, #1 ' .makebcd getqx pa wz 'collect result for recursion getqy pb 'collect decimal digit 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, bcdlen '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 mov pb, #" " 'replace with leading spaces 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 loctestlut loc pa, #\@lutxstr call #puts loc pa, #\@hdrstr call #puts loc pa, #loctest1 call #diagloc loc pa, #loctest2 call #diagloc loc pa, #loctest3 call #diagloc loc pa, #loctest4 call #diagloc call #getch jmp #_main ORGF $3a0 loctest4 long $44444444 ' Lutram address $1a0, Hubram equivalent is $e80 LUT_end FIT $400