I need to use a 32/16bit unsigned Divide in assembler with the mc9s08aw32 or MC9S08GB60 .
Unfortunately I am a Beginner .
I have copied and editated the unsigned divide in this mode :
; export symbols
XDEF Entry, main
; we use export 'Entry' as symbol. This allows us to
; reference 'Entry' either in the linker .prm file
; or from C/C++ later on
XREF __SEG_END_SSTACK ; symbol defined by the linker for the end of the stack
; include derivative specific macros
INCLUDE 'mc9s08aw32.inc'
; variable/data section
MY_ZEROPAGE: SECTION SHORT ; Insert here your data definition
INTACC1 RMB 4 ;32-bit integer accumulator #1
INTACC2 RMB 4 ;32-bit integer accumulator #2
SPVAL RMB 2 ;storage for stack pointer value
; code section
MyCode: SECTION
main:
Entry:
; Insert your code here
;*******Assegnazione Valori test.
MOV #$01,INTACC1
MOV #$F4,INTACC1+1
MOV #$F4,INTACC1+2
MOV #$01,INTACC2
MOV #$F4,INTACC2+1
;*******Assegnazione Valori test.
START LDHX #$450 ;load H:X with upper RAM boundary + 1
TXS ;move stack pointer to upper RAM boundary
CLRH ;clear H:X
JSR UDVD32 ;call 32 x 16 multiply routine
BRA * ;end of main routine
;********************************************************************************
;* 32 x 16 Unsigned Divide
;*
;* This routine takes the 32-bit dividend stored in INTACC1:INTACC1+3
;* and divides it by the 16-bit divisor stored in INTACC2:INTACC2+1.
;* The quotient replaces the dividend and the remainder replaces the divisor.
;*
UDVD32 EQU *
DIVIDEND EQU INTACC1+2
DIVISOR EQU INTACC2
QUOTIENT EQU INTACC1
REMAINDER EQU INTACC1
;*
PSHH ;save h-reg value
PSHA ;save accumulator
PSHX ;save x-reg value
AIS #-3 ;reserve three bytes of temp storage
LDA #!32 ;
STA 3,SP ;loop counter for number of shifts
LDA DIVISOR ;get divisor MSB
STA 1,SP ;put divisor MSB in working storage
LDA DIVISOR+1 ;get divisor LSB
STA 2,SP ;put divisor LSB in working storage
;*
;* Shift all four bytes of dividend 16 bits to the right and clear
;* both bytes of the temporary remainder location
;*
MOV DIVIDEND+1,DIVIDEND+3 ;shift dividend LSB
MOV DIVIDEND,DIVIDEND+2 ;shift 2nd byte of dividend
MOV DIVIDEND-1,DIVIDEND+1 ;shift 3rd byte of dividend
MOV DIVIDEND-2,DIVIDEND ;shift dividend MSB
CLR REMAINDER ;zero remainder MSB
CLR REMAINDER+1 ;zero remainder LSB
;*
;* Shift each byte of dividend and remainder one bit to the left
;*
SHFTLP LDA REMAINDER ;get remainder MSB
ROLA ;shift remainder MSB into carry
ROL DIVIDEND+3 ;shift dividend LSB
ROL DIVIDEND+2 ;shift 2nd byte of dividend
ROL DIVIDEND+1 ;shift 3rd byte of dividend
ROL DIVIDEND ;shift dividend MSB
ROL REMAINDER+1 ;shift remainder LSB
ROL REMAINDER ;shift remainder MSB
;*
;* Subtract both bytes of the divisor from the remainder
;*
LDA REMAINDER+1 ;get remainder LSB
SUB 2,SP ; subtract divisor LSB from remainder LSB
STA REMAINDER+1 ; store new remainder LSB
LDA REMAINDER ; get remainder MSB
SBC 1,SP ;subtract divisor MSB from remainder MSB
STA REMAINDER ;store new remainder MSB
LDA DIVIDEND+3 ;get low byte of dividend/quotient
SBC #0 ;dividend low bit holds subtract carry
STA DIVIDEND+3 ;store low byte of dividend/quotient
;*
;* Check dividend/quotient LSB. If clear, set LSB of quotient to indicate
;* successful subraction, else add both bytes of divisor back to remainder
;*
BRCLR 0,DIVIDEND+3,SETLSB ;check for a carry from subtraction
;and add divisor to remainder if set
LDA REMAINDER+1 ;get remainder LSB
ADD 2,SP ;add divisor LSB to remainder LSB
STA REMAINDER+1 ;store remainder LSB
LDA REMAINDER ;get remainder MSB
ADC 1,SP ;add divisor MSB to remainder MSB
STA REMAINDER ;store remainder MSB
LDA DIVIDEND+3 ;get low byte of dividend
ADC #0 ;add carry to low bit of dividend
STA DIVIDEND+3 ;store low byte of dividend
BRA DECRMT ;do next shift and subtract
SETLSB BSET 0,DIVIDEND+3 ;set LSB of quotient to indicate successive subtraction
DECRMT DBNZ 3,SP,SHFTLP ;decrement loop counter and do next shift
;*
;* Move 32-bit dividend into INTACC1:INTACC1+3 and put 16-bit
;* remainder in INTACC2:INTACC2+1
;*
LDA REMAINDER ;get remainder MSB
STA 1,SP ;temporarily store remainder MSB
LDA REMAINDER+1 ;get remainder LSB
STA 2,SP ;temporarily store remainder LSB
MOV DIVIDEND,QUOTIENT ;
MOV DIVIDEND+1,QUOTIENT+1 ;shift all four bytes of quotient
MOV DIVIDEND+2,QUOTIENT+2 ; 16 bits to the left
MOV DIVIDEND+3,QUOTIENT+3 ;
LDA 1,SP ;get final remainder MSB
STA INTACC2 ;store final remainder MSB
LDA 2,SP ;get final remainder LSB
STA INTACC2+1 ;store final remainder LSB
;*
;* Deallocate local storage, restore register values, and return from
;* subroutine
;*
AIS #3 ;deallocate temporary storage
PULX ;restore x-reg value
PULA ;restore accumulator value
PULH ;restore h-reg value
RTS
;******FINE_SUB************************************
I use CW_6.0 and when i try to use MAKE ; it show mi this message of warning :
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 94
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 94
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 95
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 95
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 96
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 96
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 97
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 97
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 98
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 99
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 105
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 106
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 107
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 108
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 109
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 110
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 127
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 139
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 149
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 149
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 150
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 150
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 151
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 151
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 152
Warning : A13003: Value is truncated to one byte
Conversione_Gradi_HEX_OK.asm line 152
Who can help mi to understand the correct way for make the unsigned Divide .......PLEASE ?
where' s the trouble?
Sorry for my bad English.
Solved! Go to Solution.
Hello, and welcome to the forum.
Does the subroutine perform correctly, in spite of the warnings? I suspect that it may do so.
The instructions to which the warnings apply can utilize zero page variables only. However, the labels that are used within the instructions are actually defined within some equates. So presumably the assembler is not explicitly aware of their validity, and assumes 8-bit addressing mode, thus resulting in the warnings.
The warnings appear to be eliminated by using the variables INTACC1 and INTACC2 directly, rather than the equates DIVIDEND, REMAINDER, etc.
Another possibility is to define the variables and equates in a separate file, containing XDEFs for both the variables and the equates. Then, within the main file, by using XREFB for the variables and equates, the addressing mode is explicitly defined, and the warnings should be eliminated.
The code within the application note was originally written for a different assembler than CW, probably as an absolute assembly project. Presumably these warnings were not generated by the ooriginal assembler.
Another important point - you do not appear to have initialised the stack pointer at the start of your main code.
Regards,
Mac
It's a BEAUTIFUL DAY.
Now with " LDA #32" work.
Many many THANK's to everybody for the help.
Have a nice day to everibady.
Hallo bigmac and many thank's for the anwer :
I have tried to reedited my asm_file with initalizzated the RAM at (Z_RAMStart).
This is the file.asm :
INCLUDE 'MC9S08AW32.inc'
XDEF _Startup
ABSENTRY _Startup
ORG Z_RAMStart ;ORG RAMStart ; Insert your data definition here
INTACC1 RMB 4 ;32-bit integer accumulator #1
INTACC2 RMB 4 ;32-bit integer accumulator #2
SPVAL RMB 2 ;storage for stack pointer value
ORG ROMStart
_Startup:
LDHX #RAMEnd+1 ; initialize the stack pointer
TXS
CLI ; enable interrupts
mainLoop:
START LDHX #$100 ;load H:X with upper RAM boundary + 1
TXS ;move stack pointer to upper RAM boundary
CLRH ;clear H:X
;*******Assegnazione Valori test.
MOV #$00,INTACC1
MOV #$F4,INTACC1+1
MOV #$00,INTACC1+2
MOV #$00,INTACC1+3
MOV #$01,INTACC2
MOV #$A0,INTACC2+1
;***********************************
JSR UDVD32
nop
nop
nop
STOP ; END..........
;* SUB:UDVD32 ______ 32 x 16 Unsigned Divide
;* This routine takes the 32-bit dividend stored in INTACC1:INTACC1+3
;* and divides it by the 16-bit divisor stored in INTACC2:INTACC2+1.
;* The quotient replaces the dividend and the remainder replaces the divisor.
UDVD32 EQU *
DIVIDEND EQU INTACC1+2
DIVISOR EQU INTACC2
QUOTIENT EQU INTACC1
REMAINDER EQU INTACC1
PSHH ;save h-reg value
PSHA ;save accumulator
PSHX ;save x-reg value
AIS #-3 ;reserve three bytes of temp storage
LDA #!32 ;
STA 3,SP ;loop counter for number of shifts
LDA DIVISOR ;get divisor MSB
STA 1,SP ;put divisor MSB in working storage
LDA DIVISOR+1 ;get divisor LSB
STA 2,SP ;put divisor LSB in working storage
;* Shift all four bytes of INTACC11 16 bits to the right and clear
;* both bytes of the temporary remainder location
MOV DIVIDEND+1,DIVIDEND+3 ;shift dividend LSB
MOV DIVIDEND,DIVIDEND+2 ;shift 2nd byte of dividend
MOV DIVIDEND-1,DIVIDEND+1 ;shift 3rd byte of dividend
MOV DIVIDEND-2,DIVIDEND ;shift dividend MSBshift 3rd byte of dividend
MOV DIVIDEND-2,DIVIDEND ;shift dividend MSB
CLR REMAINDER ;zero remainder MSB
CLR REMAINDER+1 ;zero remainder LSB
;* Shift each byte of dividend and remainder one bit to the left
SHFTLP LDA REMAINDER ;get remainder MSB
ROLA ;shift remainder MSB into carry
ROL DIVIDEND+3 ;shift dividend LSB
ROL DIVIDEND+2 ;shift 2nd byte of dividend
ROL DIVIDEND+1 ;shift 3rd byte of dividend
ROL DIVIDEND ;shift dividend MSB
ROL REMAINDER+1 ;shift remainder LSB
ROL REMAINDER ;shift remainder MSB
;* Subtract both bytes of the divisor from the remainder
LDA REMAINDER+1 ;get remainder LSB
SUB 2,SP ; subtract divisor LSB from remainder LSB
STA REMAINDER+1 ; store new remainder LSB
LDA REMAINDER ; get remainder MSB
SBC 1,SP ;subtract divisor MSB from remainder MSB
STA REMAINDER ;store new remainder MSB
LDA DIVIDEND+3 ;get low byte of dividend/quotient
SBC #0 ;dividend low bit holds subtract carry
STA DIVIDEND+3 ;store low byte of dividend/quotient
;* Check dividend/quotient LSB. If clear, set LSB of quotient to indicate
;* successful subraction, else add both bytes of divisor back to remainder
BRCLR 0,DIVIDEND+3,SETLSB ;check for a carry from subtraction
;and add divisor to remainder if set
LDA REMAINDER+1 ;get remainder LSB
ADD 2,SP ;add divisor LSB to remainder LSB
STA REMAINDER+1 ;store remainder LSB
LDA REMAINDER ;get remainder MSB
ADC 1,SP ;add divisor MSB to remainder MSB
STA REMAINDER ;store remainder MSB
LDA DIVIDEND+3 ;get low byte of dividend
ADC #0 ;add carry to low bit of dividend
STA DIVIDEND+3 ;store low byte of dividend
BRA DECRMT ;do next shift and subtract
SETLSB BSET 0,DIVIDEND+3 ;set LSB of quotient to indicate successive subtraction
DECRMT DBNZ 3,SP,SHFTLP ;decrement loop counter and do next shift
;* Move 32-bit dividend into INTACC1:INTACC1+3 and put 16-bit
;* remainder in INTACC2:INTACC2+1
LDA REMAINDER ;get remainder MSB
STA 1,SP ;temporarily store remainder MSB
LDA REMAINDER+1 ;get remainder LSB
STA 2,SP ;temporarily store remainder LSB
MOV DIVIDEND,QUOTIENT ;
MOV DIVIDEND+1,QUOTIENT+1 ;shift all four bytes of quotient
MOV DIVIDEND+2,QUOTIENT+2 ; 16 bits to the left
MOV DIVIDEND+3,QUOTIENT+3 ;
LDA 1,SP ; get final remainder MSB
STA INTACC2 ;store final remainder MSB
LDA 2,SP ;get final remainder LSB
STA INTACC2+1 ;store final remainder LSB
;* Deallocate local storage, restore register values, and return from
;* subroutine
AIS #3 ;deallocate temporary storage
PULX ;restore x-reg value
PULA ;restore accumulator value
PULH ;restore h-reg value
RTS ;return
;**************************************************************
;* spurious - Spurious Interrupt Service Routine. *
;* (unwanted interrupt) *
;**************************************************************
spurious: ; placed here so that security value
NOP ; does not change all the time.
RTI
;**************************************************************
;* Interrupt Vectors *
;**************************************************************
ORG $FFFA
DC.W spurious ;
DC.W spurious ; SWI
DC.W _Startup ; Reset
Now It start and run in debug with IDE_WORK.
Now there is another problem ; I find a wrong result at the end of the Subrutine.
If you take a look to the value of the variable :
MOV #$00,INTACC1
MOV #$F4,INTACC1+1
MOV #$00,INTACC1+2
MOV #$00,INTACC1+3
MOV #$01,INTACC2
MOV #$A0,INTACC2+1
the result must be >>>>> 96.27h ; bat unfortunately isn't so .
Where is the miss match ???
Many THANK'S again for the help.
Hello,
It seems that the problem is with the following code.
AIS #-3 ; reserve three bytes of temp storage
LDA #!32
STA 3,SP ; loop counter for number of shifts
The CW assembler seems to have problems with the highlighted line, but did not generate an error message. It interprets the line as lda #0x00, which is obviously not correct. When the line was altered to LDA #32, the expected result was obtained from the sub-routine.
The lack of some sort of error message did surprise me.
Regards,
Mac
Dear Bigmac,
The Codewarrior assembler accepts C expressions so interprets !32 as 'not' 32. 32 being 'true' this gives 'false' i.e. 0.
Certainly a bit confusing but legal.
bye
Hello pgo,
The main problem here is that the code in question appears in a Freescale Application Note (admittedly originating in the Motorola days), which is therefore not now entirely compatible with the CW assembler. I wonder how many other AN's also have problems with the published assembly code?
For the earlier assemblers, the prefix '!' was used to explicitly indicate a decimal number (since some assemblers defaulted to hexadecimal). Unfortunately, this does give incompatibility with "C expression" notation.
In the process of converting old assembly files over to CW, the incompatibilities will generally produce errors or warnings. This is the first instance I have come across where there was no warning of a potential problem, for whatever reason.
Regards,
Mac
Hello, and welcome to the forum.
Does the subroutine perform correctly, in spite of the warnings? I suspect that it may do so.
The instructions to which the warnings apply can utilize zero page variables only. However, the labels that are used within the instructions are actually defined within some equates. So presumably the assembler is not explicitly aware of their validity, and assumes 8-bit addressing mode, thus resulting in the warnings.
The warnings appear to be eliminated by using the variables INTACC1 and INTACC2 directly, rather than the equates DIVIDEND, REMAINDER, etc.
Another possibility is to define the variables and equates in a separate file, containing XDEFs for both the variables and the equates. Then, within the main file, by using XREFB for the variables and equates, the addressing mode is explicitly defined, and the warnings should be eliminated.
The code within the application note was originally written for a different assembler than CW, probably as an absolute assembly project. Presumably these warnings were not generated by the ooriginal assembler.
Another important point - you do not appear to have initialised the stack pointer at the start of your main code.
Regards,
Mac