;xilinx bitstream downloader, Paul Stoffregen, Mar 1996 ;beta version 0.2 ;opps, screwed up 4000 series download in version 0.1.. fixed now ;To use this thing, just connect the 8051's uart to your ;serial port (via driver/receiver chip) and attach the ;five necessary lines from port1 to your xilinx chip. ;Just send the binary .bit file directly to the serial ;port (at the right baud rate) and this code will remove ;the .bit file's header and download the data into your ;xilinx chip. There is little to no error checking for ;3000 series parts, so be careful. ; --Paul Stoffregen (paul@ece.orst.edu) ;to do: ; -> add status led outputs -download "started" and "finished" ; -> check for another device (xchecker) starting a download ; and go into high impedance until it's finished ; -> add mode input (shown on schematic) and it master serial ; mode is selected general program pulse in response to ; reset pin but then let the serial prom do the work ; -> better messages to host computer in the unlikely event ; someone is using a terminal program and actually reading it ; -> add jumper and extra line to OE/R pin on serial prom and ; support multiple consecutive configurations in the proms. ; -> check that init signal goes is low before we see it go ; high so the chip-not-connected error can be detected ; instead of just downloading into nowhere and thinking it ; was successful because of pull-up resistors. ;timer reload calculation ; baud_const = 256 - (crystal / (12 * 16 * baud)) .equ baud_const, 253 ;19200 baud w/ 11.0592 MHz ;.equ baud_const, 250 ;9600 baud w/ 11.0592 MHz ;port pins required .equ cclk, 0x97 ;xilinx chip config clock .equ done, 0x94 ;xilinx chip done signal (D/P on 3000s) .equ din, 0x96 ;xilinx chip serial data input .equ prog, 0x95 ;xilinx chip program request line (reset on 3000s) .equ init, 0x93 ;xilinx chip init/error signal ;these aren't supported yet .equ mode, 0 ;xilinx mode select (0=ser master, 1=ser slave) .equ rst, 0 ;xilinx reset (begin reprogram if mode=0) .equ config, 0 ;LED driver, low if we're programming .equ ok, 0 ;LED driver, low if the chip is programmed ok ;internal ram memory usage .equ c_3000, 0x20 .equ c_4000, 0x21 .equ stack, 0x60 ;reset and interrupt vectors .org 0 ljmp poweron ;reset vector .org 3 ;ext int0 vector .org 11 ;timer0 vector .org 19 ;ext int1 vector .org 27 ;timer1 vector .org 35 ;uart vector .org 43 ;timer2 vector (8052) .org 48 ;finally we can begin main: mov sp, #stack mov c_3000, #0 mov c_4000, #0 mov dptr, #0 wait_begin: ;waiting for beginning of bit file acall cin mov r2, a mov dptr, #s_3000 mov r0, #c_3000 acall lexer jc begin3000 mov dptr, #s_4000 mov r0, #c_4000 acall lexer jc begin4000 sjmp wait_begin begin3000: ;assume the bit file is arriving... we better ;start the program sequence before the real ;data starts to show up clr prog clr done mov r0, #240 djnz r0, * setb prog setb done mov dptr, #s_3000 clr a movc a, @a+dptr mov dpl, a mov dph, #0 mov a, #'3' acall cout sjmp waitinit s_3000: .db 10 ;length of 3000 series bitstream id header` .db 0xF0, 0x0F, 0xF0, 0x0F, 0xF0 .db 0x0F, 0xF0, 0x0F, 0x00, 0x33 begin4000: ;assume the bit file is arriving... we better ;start the program sequence before the real ;data starts to show up clr prog mov r0, #240 djnz r0, * setb prog setb done mov dptr, #s_4000 clr a movc a, @a+dptr mov dpl, a mov dph, #0 mov a, #'4' acall cout sjmp waitinit s_4000: .db 13 ;length of 4000 series bitstream id header` .db 0x09, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0 .db 0x0F, 0xF0, 0x00, 0x00, 0x01, 0x61 waitinit: jnb ri, wtinit2 clr ri mov a, sbuf inc dptr wtinit2: jnb init, waitinit wait255: acall cin inc dptr cjne a, #255, wait255 mov r2, #0 sjmp shift next: acall cin inc dptr shift: mov b, r5 mov r4, b mov b, r6 mov r5, b mov b, r7 mov r6, b mov r7, a mov r0, #8 inc r2 sh_loop: rlc a mov din, c clr cclk nop setb cclk djnz r0, sh_loop nop nop nop jnb init, error nop jnb done, next ;now that it says it's done, it needs a few more ;cclk pulses to actually start up... see pg 2-29 ;in 1993 xilinx databook. setb din ;in case a 3000 series .bit file left it low mov r0, #32 ;need more cclk pulses to finish startup startup:clr cclk nop setb cclk djnz r0, startup mov dptr, #msg_done acall pstr acall delay acall delay acall delay ajmp main msg_done:.db "Done signal went high.",13,10,0 error: ;if we get here, it means the xilinx chip pulled ;init low to tell us it got a checksum error! mov a, #'E' acall cout mov a, #'r' acall cout acall cout mov a, #'@' acall cout mov a, dph ;offset in .bit file where error detected acall phex mov a, dpl acall phex mov a, #' ' acall cout mov a, r4 acall phex mov a, #' ' acall cout mov a, r5 acall phex mov a, #' ' acall cout mov a, r6 acall phex mov a, #' ' acall cout mov a, r7 acall phex mov a, #' ' acall cout acall cout acall cout mov a, r2 acall phex setb c jc * delay: mov r3, #200 delay2: nop mov r2, #228 djnz r2, * djnz r3, delay2 ret cin: jnb ri, cin jnb ri, cin clr ri mov a, sbuf ret cout: jnb ti, cout ;not ok to change carry bit here! clr ti mov sbuf, a ret newline:push acc mov a, #13 acall cout mov a, #10 acall cout pop acc ret phex: phex8: push acc swap a anl a, #15 add a, #246 jnc phex_b add a, #7 phex_b: add a, #58 acall cout pop acc phex1: push acc anl a, #15 add a, #246 jnc phex_c add a, #7 phex_c: add a, #58 acall cout pop acc ret PSTR: ;print string PUSH ACC PSTR1: CLR A MOVC A,@A+DPTR JZ PSTR2 mov c, acc.7 anl a, #01111111b acall cout Jc pstr2 inc dptr SJMP PSTR1 PSTR2: POP ACC RET poweron: MOV SP, #stack clr psw.3 clr psw.4 mov th1, #baud_const orl PCON,#10000000b ; set double baud rate MOV TMOD,#00100001b ; T0=16 bit, T1=8 bit auto reload ; both are timers, software control MOV SCON,#01010010b ; Set Serial for mode 1 & ; Enable reception, ti=1, ri=0 ORL TCON,#01010101b ; Start both timers, both int are ; falling edge trigger mov dptr, #welcome acall pstr ajmp main welcome:.db "Xilinx Bitstream Downloader",13,10 .db "Beta Version 0.2",13,10 .db "Paul Stoffregen, March 1996",13,10,13,10,0 lexer: mov a, @r0 inc a ;don't look at length byte movc a, @a+dptr ;get character from string clr c subb a, r2 jnz lex_nope ;at this point, it matches the string, so now ;the question becomes "are we at the end?" inc @r0 ;advance index clr a movc a, @a+dptr ;get string length clr c subb a, @r0 ;subtract index jz lex_match ;we're not at the end of the string yet clr c ret lex_match: ;we've found all of the string now mov @r0, a ;reset index automatically setb c ret lex_nope: ;the received character doesn't match the string ;so we set the index back to zero, and return with ;carry clear mov @r0, #0 clr c ret