#***************************************************************************** #* File: LOADASM.S #* $Id: 555boot.s,v 1.1 2000/04/17 13:00:20 lavarenn Exp lavarenn $ #* Version: 1.00, 23/12/1999 #* Author: Meftah GHRISSI #----------------------------------------------------------------------------- #* Modification: #* 1.00 - Base version # CL: MODIFICATIONS EXPECTED TO BE DONE IN A NEAR FUTURE: # - add the step waiting for a "request" frame after each downloaded executive # see http://www-rocq.inria.fr/syndex/doc/CAN/CANload.htm, # "Descendant Station Boot-Loader Process" step 6 of first repeat loop # - identify all frames with the SynDEx-reserved frame-identifier "0x55"; # this will simplify the macros CAN_loadDnto_ and CAN_loadFrom_ in CAN.m4x; # this will also avoid interferences with yelling dumb CAN stations # - add the ability to download the code into FLASH, and to allow next # downloads to be limited to the "start" prefix-frame; this will require # to store in flash the "start" address of the downloaded executive. # - add the ability to bootload from any of TouCAN_A and TouCAN_B, # sticking on the first one receiving a frame # - store the SID (Station IDentifier, i.e. Robosoft board serial number) # in a fixed location, allowing to FLASH the SID separately from the code # of the bootloader, which will then not need to be recompiled for each SID # - WARNING: the 555.ld script must be modified to compile code in FLASH!!! #----------------------------------------------------------------------------- .name "loadasm.s" .text .include "555regsdef.s" # Exported function .xdef BootLoader555 #----------------------------------------------------------------------------- #-------------- Switch to DATA Space .data .lcomm Can_buff,12 .text #-------------- END Switch to DATA Space A_Entry_Flash = 0x00000100 A_Entry_ProgHi = 0x0000 A_Entry_ProgLo = 0x2000 #----------------------------------------------------------------------------- # Here the structure used to send and receive message, only the pointer is # passed to the function as parameter. # typedef struct # { # word id# // + 0x00 # byte rtr# // + 0x02 # byte dlen# // + 0x03 # byte data[8]# // + 0x04 # }TCanMsgStruct# # #***************************************************************************** # Syntax # A_Name : Refers LSB 16bit Address for "name" Register # V_Name : Refers 16bit Value to set "name" Register #----------------------------------------------------------------------------- Err_nCAN = 0x8001 # CAN Module selection out of range (nCAN!=0 or nCAN!=1) Err_NoMsg = 0x0001 Err_NotFree = 0x0002 A_TOUCANBASE = 0x0030 # TouCAN Base, upper address (0x00300000) BaseCAN_A = 0x0000 # Offset to access CAN Module "A" BaseCAN_B = 0x0400 # Offset to access CAN Module "B" A_TCNMCR = 0x7080 # TouCAN Configuration Register (16.7.1) A_TTRA = 0x7082 # TouCAN Test Register (16.7.2) A_CANICR = 0x7084 # TouCAN Interrupt Register (16.7.3) A_CANCTRL0 = 0x7086 # TouCAN Control Register 0 (16.7.4) A_CANCTRL1 = 0x7087 # TouCAN Control Register 1 (16.7.5) - BYTE ACCESS - A_PRESDIV = 0x7088 # TouCAN Control and Prescaler (16.7.6) A_CANCTRL2 = 0x7089 # TouCAN Control Register 2 (16.7.7) - BYTE ACCESS - A_TIMER = 0x708A # TouCAN Free running TIMER (16.7.8) A_RXGMSK = 0x7090 A_RXGMSKHI = 0x7090 # TouCAN Receive Global Mask Registers HI (16.7.9) A_RXGMSKLO = 0x7092 # TouCAN Receive Global Mask Registers LO A_RX14MASKHI = 0x7094 # TouCAN Receive 14 Mask Registers HI (16.7.10) A_RX14MASKLO = 0x7096 # TouCAN Receive 14 Mask Registers LO A_RX15MASKHI = 0x7098 # TouCAN Receive 15 Mask Registers HI (16.7.11) A_RX15MASKLO = 0x709A # TouCAN Receive 15 Mask Registers LO A_ESTAT = 0x70A0 # TouCAN Error and Status register (16.7.12) A_IMASK = 0x70A2 # TouCAN Interrupt Mask (16.7.13) A_IFLAG = 0x70A4 # TouCAN Interrupt Flag (16.7.14) A_BUFFER0 = 0x7100 A_BUFFER1 = 0x7110 A_BUFFER2 = 0x7120 A_BUFFER3 = 0x7130 A_BUFFER4 = 0x7140 A_BUFFER5 = 0x7150 A_BUFFER6 = 0x7160 A_BUFFER7 = 0x7170 A_BUFFER8 = 0x7180 A_BUFFER9 = 0x7190 A_BUFFER10 = 0x71A0 A_BUFFER11 = 0x71B0 A_BUFFER12 = 0x71C0 A_BUFFER13 = 0x71D0 A_BUFFER14 = 0x71E0 A_BUFFER15 = 0x71F0 cd_TXNOTREADY = 0b10000000 # Code for TouCAN buffer (see table 16-3, section 16.3.1.1) cd_TXSEND = 0b11000000 cd_TXREQUESTALW = 0b10100000 cd_TXREQUEST = 0b11100000 cb_RXNOTACTIVE = 0b00000000 # see section 16.3.1.2, table 16-2 cb_RXEMPTY = 0b00100000 cb_RXFULL = 0b01100000 cb_RXOVERRUN = 0b01100000 cb_RXBUSY = 0b00100000 #***************************************************************************** # prototype: # CanOpenNIT (use can line A in default) #----------------------------------------------------------------------------- # CanDiv determine CAN Clock frequency as follow: # CanFreq = FSys / (CanDiv + 1) # For 40Mhz system clock: 250K -> 19, 500K -> 9, 1M -> 4 # WARNING: Presdiv MUST be < 256 !!!!! # possible to set other lower rate using different CANCTRL0/1 setting #----------------------------------------------------------------------------- # For more detail see CAN Version 2.0, Section B.17, Timing configuration # BitTIME = [ 1 + (PropSeg+1) + (PSeg1+1) + (PSeg2+1) ] x CanFreq # If PropSeg=2, PSeg1=1, PSeg2=1, BitTIME = 8 x CanFreq #----------------------------------------------------------------------------- CanOpenNIT: stwu r1,-0x10(r1) # Save old SP into SP-0x10, SP=SP-0x10 mfspr r0,LR stw r30,8(r1) # [SP + 0x08] = r30 stw r31,0xC(r1) # [SP + 0x0C] = r31 stw r0,0x14(r1) # [SP + 0x14] = r0 li r31,0 addis r31,r31,A_TOUCANBASE # r31 = 0x0030 0000 # see: 16.4.2 for exact init sequence li r0,cd_TXNOTREADY # TX-CAN code for buffer NOT ready sth r0,A_BUFFER0(r31) # Store first word into CAN Buffer 0 sth r0,A_BUFFER1(r31) sth r0,A_BUFFER2(r31) sth r0,A_BUFFER3(r31) sth r0,A_BUFFER4(r31) sth r0,A_BUFFER5(r31) sth r0,A_BUFFER6(r31) sth r0,A_BUFFER7(r31) sth r0,A_BUFFER8(r31) # Store first word into CAN Buffer 8 sth r0,A_BUFFER9(r31) sth r0,A_BUFFER10(r31) sth r0,A_BUFFER11(r31) sth r0,A_BUFFER12(r31) sth r0,A_BUFFER13(r31) sth r0,A_BUFFER14(r31) sth r0,A_BUFFER15(r31) li r0,0x1200 # RESET CAN, no Wakeup interrupt, user & superuser register access sth r0,A_TCNMCR(r31) # Software CAN Reset sequence intiated, HALT Mode selected li r0,0x0000 # set INT to level 0 (for CAN Module A ) # cmpi cr0,0,r30,0 # R30 = CAN Module number (0 or 1) # beq CANOpen_01 # li r0,0x0100 # set INT to level 1 ( for CAN Module B ) #CANOpen_01: sth r0,A_CANICR(r31) # CL: 555UM says buf0=bit0=MSB; but this code does work, with buf0=LSB # li r0,0x0001 li r0,0x0000 # no interrupt : polling mode sth r0,A_IMASK(r31) # li r0,0x05 # Logic "1" is dominant bit for RX_0 and TX_0 li r0,0x00 # Logic "0" is dominant bit for RX_0 and TX_0 stb r0,A_CANCTRL0(r31) # Disable INT on CAN Error (16.7.4) li r0,0x02 # PROPSEG=2, no special setting stb r0,A_CANCTRL1(r31) li r0,0x09 # PSEG1=1, PSEG2=1, no special setting stb r0,A_CANCTRL2(r31) # determine CAN Clock frequency stb r4,A_PRESDIV(r31) li r0,0x28 # CL: 2.0B bits; why not simply 0? # stw r0,A_RXGMSK(r31) # Store Mask registers NO ID is set, CAN will receive ALL frame stw r0,A_RXGMSKHI(r31) # Store Mask registers NO ID is set, CAN will receive ALL frame # stw r0,A_RX14MASKHI(r31) # Not needed until now # stw r0,A_RX15MASKLO(r31) # Not needed until now lhz r0,A_ESTAT(r31) # Read ESTAT and clear bits li r0,0x0000 sth r0,A_TCNMCR(r31) # Software CAN Reset sequence intiated, NORMAL Mode selected li r0,cd_TXNOTREADY # TX-CAN code for buffer NOT ready sth r0,A_BUFFER1(r31) # Store first word into CAN Buffer 1 li r0,cb_RXEMPTY # RX-CAN code to activate RX buffer 0 in RX Mode sth r0,A_BUFFER0(r31) li r0,0 sth r0,A_BUFFER0+2(r31)# Set MSG.ID to 0000 sth r0,A_BUFFER0+4(r31) # CL: IFLAG can be written to zeros only! 555UM p16-32 li r0,0x0002 # Set IFLAG.1 to prepare for first TX sth r0,A_IFLAG(r31) li r3,0 # r3 = returned value = 0 = OK CANOpen_End: lwz r30,0x8(r1) lwz r31,0xC(r1) lwz r0,0x14(r1) mtspr LR,r0 # Restore Link Register (LR = r0) addi r1,r1,0x10 # restore Stack: r1 = r1 + 0x10 blr # return #***************************************************************************** # prototype: # CANClose #----------------------------------------------------------------------------- CANClose: stwu r1,-0x10(r1) # Save old SP into SP-0x10, SP=SP-0x10 mfspr r0,LR stw r30,8(r1) # [SP + 0x08] = r30 stw r31,0xC(r1) # [SP + 0x0C] = r31 stw r0,0x14(r1) # [SP + 0x14] = r0 li r0,0 addis r31,r31,A_TOUCANBASE # r31 = 0x0030 0000 # li r0,0x8000 # STOP CAN clock li r0,-0x8000 # STOP CAN clock stw r0,A_TCNMCR(r31) # Store into TCNMCR Register li r3,0 # r3 = returned value = 0 = OK CANClose_End: lwz r30,0x8(r1) lwz r31,0xC(r1) lwz r0,0x14(r1) mtspr LR,r0 # Restore Link Register (LR = r0) addi r1,r1,0x10 # restore Stack: r1 = r1 + 0x10 blr # return #***************************************************************************** # prototype: # int CANSendMsg (TCanMsgStruct *MsgPtr)# # r3 = address of MsgPtr #----------------------------------------------------------------------------- CANSendMsg: stwu r1,-0x10(r1) # Save old SP into SP-0x10, SP=SP-0x10 mfspr r0,LR stw r30,8(r1) # [SP + 0x08] = r30 stw r31,0xC(r1) # [SP + 0x0C] = r31 stw r0,0x14(r1) # [SP + 0x14] = r0 li r31,0 addis r31,r31,A_TOUCANBASE # r31 = 0x0030 0000 # here r3 point to MsgPtr, r31 point to TouCAN base address lhz r0,A_IFLAG(r31) # RO = IFlag andi. r0,r0,0x0002 # is Buffer1 set IFLAG.1 ? # beq CANSend_End # no, no message present #---------- lhz r0,A_IFLAG(r31) # RO = IFlag andi. r0,r0,0xFFFD # Reset IFLAG.1 sth r0,A_IFLAG(r31) #--- WARNING BUFFER1 is supposed to be free for transmission ! # See Section 16.4.3 #---- Disable transmit lbz r0,0x03(r3) # r1 = MsgPtr^.Len andi. r0,r0,0x0F # keep only 4 bit ori r0,r0,cd_TXNOTREADY# Add TX-CAN code sth r0,A_BUFFER1+0(r31)# Store first word into CAN Buffer 0 #---- Copy THE message lhz r0,0x00(r3) # r0 = MsgPtr^.ID rlwinm r0,r0,8,16,23 # SHIFT Left 8 time and keep only bit 16..31 sth r0,A_BUFFER1+2(r31)# Store MSG ID lwz r0,0x04(r3) # r0 = MsgPtr^.(DATA[0]...DATA[3]) stw r0,A_BUFFER1+6(r31) lwz r0,0x08(r3) # r0 = MsgPtr^.(DATA[4]...DATA[7]) stw r0,A_BUFFER1+10(r31) #---- Message is copyed, now enable transmit lhz r0,0x02(r3) # r1 = MsgPtr^.Len andi. r0,r0,0x0F # keep only 4 bit ori r0,r0,cd_TXSEND # Add TX-CAN code sth r0,A_BUFFER1+0(r31)# Store first word into CAN Buffer 0 CANWaitSendEnd: lhz r0,A_IFLAG(r31) # RO = IFlag andi. r0,r0,0x0001 # is Buffer0 set IFLAG.0 ? beq CANWaitSendEnd # no, the message is not yet send lhz r0,A_IFLAG(r31) andi. r0,r0,0xFFFE # reset IFLAG.0 sth r0,A_IFLAG(r31) # IFlag = r0 # we are ready to receive another message CANSend_End: lwz r30,0x8(r1) lwz r31,0xC(r1) lwz r0,0x14(r1) mtspr LR,r0 # Restore Link Register (LR = r0) addi r1,r1,0x10 # restore Stack: r1 = r1 + 0x10 blr # return #***************************************************************************** # prototype: # void CanReceiveFrame(TCanMsgStruct *MsgPtr) # # input: r3 = receive buffer #----------------------------------------------------------------------------- CanReceiveFrame: stwu r1,-0x10(r1) # Save old SP into SP-0x10, SP=SP-0x10 # mfspr r0,lr # stw r30,8(r1) # [SP + 0x08] = r30 stw r31,0xC(r1) # [SP + 0x0C] = r31 # stw r0,0x14(r1) # [SP + 0x14] = r0 li r31,0 addis r31,r31,A_TOUCANBASE # r31 = 0x0030 0000 # here r3 point to MsgPtr, r31 point to TouCAN base address CANWaitRecv: lhz r0,A_IFLAG(r31) # RO = IFlag andi. r0,r0,0x0001 # is Buffer0 set IFLAG.0 ? beq CANWaitRecv # no, no message present #---------- lhz r0,A_IFLAG(r31) andi. r0,r0,0xFFFE # reset IFLAG.0 sth r0,A_IFLAG(r31) # IFlag = r0 #---------- lhz r0,A_BUFFER0+0(r31)# r0 = Status WORD, BUFFER 0 is now locked andi. r0,r0,0x000F # only of 4 low bit for dLen sth r0,0x02(r3) # store it lhz r0,A_BUFFER0+2(r31)# Read message ID srawi r0,r0,5 # Shift 5 places to the right to keep only 11 bits ID sth r0,0x00(r3) # store it lwz r0,A_BUFFER0+6(r31)# r0 = MsgPtr^.(DATA[0]...DATA[3]) stw r0,0x04(r3) lwz r0,A_BUFFER0+10(r31)# r0 = MsgPtr^.(DATA[4]...DATA[7]) stw r0,0x08(r3) #---------- # Reactivate BUFFER0, set Status word and ID to 0 li r0,cb_RXEMPTY # RX-CAN code to activate RX buffer 0 in RX Mode sth r0,A_BUFFER0(r31) # li r0,0 # sth r0,A_BUFFER0+2(r31)# Set MSG.ID to 0000 # sth r0,A_BUFFER0+4(r31) lhz r0,A_TIMER(r31) # Read free running timer to UNLOCK the Buffer0 CANRecv_End: # lwz r30,0x8(r1) lwz r31,0xC(r1) # lwz r0,0x14(r1) # mtspr lr,r0 # Restore Link Register (LR = r0) NOT MODIFIED addi r1,r1,0x10 # restore Stack: r1 = r1 + 0x10 blr # return #***************************************************************************** # StoreData: r6 = dest address # size = len # data = r4[4] ...r4[11] # r4 not modfied = CAN buffer struct StoreData: stwu r1,-0x10(r1) # Save old SP into SP-0x10, SP=SP-0x10 mfspr r0,LR stw r30,8(r1) # [SP + 0x08] = r30 stw r4,0xC(r1) # [SP + 0x0C] = r31 stw r0,0x14(r1) # [SP + 0x14] = r0 subi r6,r6,1 lbzu r30,3(r4) # r30 = len received correctly mtspr 9,r30 l1: lbzu r30,1(r4) stbu r30,1(r6) bdnz l1 addi r6,r6,1 # +1 for next store lwz r30,0x8(r1) lwz r4,0xC(r1) lwz r0,0x14(r1) mtspr LR,r0 # Restore Link Register (LR = r0) addi r1,r1,0x10 # restore Stack: r1 = r1 + 0x10 blr # return #***************************************************************************** # r3 = value SendRequestFrame: stb r3,4(r4) # first byte = 1 stb r3,3(r4) # len = 1 li r3,0 sth r3,0(r4) # Id = 0 stb r3,2(r4) stb r3,5(r4) sth r3,6(r4) stw r3,8(r4) mr r3,r4 b CANSendMsg # send message #***************************************************************************** # Boot Loader #***************************************************************************** ProcID = 0x00004000 BootLoader555: li r4,19 # CLK setting bl CanOpenNIT # init can without interrupt lis r12,ProcID@h ori r12,r12,ProcID@l # r12 = ProcID WaitHeaderFrame: lis r3,Can_buff@h ori r3,r3,Can_buff@l # r3 =Can_buff address bl CanReceiveFrame # wait until received message lwz r5,4(r3) cmp cr0,0,r5,r12 beq HeaderFrameOk # wait ProcID lwz r5,8(r3) # r5 = executive length li r7,0 waitlength: bl CanReceiveFrame # wait until received empty frame for flow control lhz r6,0(r3) # number of data frame in ID mtspr 9,r6 WaitNbDataFrame: bl CanReceiveFrame # wait until received data lbz r8,3(r3) # len of data add r7,r7,r8 # somm data number bdnz WaitNbDataFrame cmp cr0,0,r7,r5 # if length reached bne waitlength b WaitHeaderFrame # wait header frame HeaderFrameOk: lwz r5,8(r3) # r5 = length executive li r9,0 WaitExecOk: mr r4,r3 li r3,1 bl SendRequestFrame # empty frame with Data0 and len = 1 mr r3,r4 bl CanReceiveFrame # wait until received address and size lwz r6,4(r3) # r6 = address lwz r7,8(r3) # r7 = section size cmpi cr0,0,r7,0 # if size = 0 then go at the entry address r6 beq EndThenGo waitdatatostore: mr r4,r3 li r3,1 bl SendRequestFrame # empty frame with Data0 and len = 1 (one frame for the momemnt) mr r3,r4 bl CanReceiveFrame # wait until received data to move in memory # StoreData use r6 for destination address and r4 for source address mr r4,r3 bl StoreData lbz r8,3(r3) # len of data received add r9,r9,r8 # r9 = total bytes received cmp cr0,0,r9,r7 bne waitdatatostore li r9,0 # init frame counter b WaitExecOk # wait until the executive is received and stored EndThenGo: mtspr lr,r6 # start frame blrl # branch to Entry Point #--------------------------------------------- # Entry point in 0x100 on reset when loader only # # .org A_Entry_Flash # li r0,0 # addis R6,r0,A_Entry_ProgHi # ori R6,r6,A_Entry_ProgLo # mtspr lr,r6 # start address of the resident loader # blrl