News:

Let's find out together what makes a PIC Tick!

Main Menu

Adding a new command?

Started by keytapper, Feb 04, 2021, 09:55 AM

Previous topic - Next topic

keytapper

There are times that the processing may require a division and the reminder.
In a normal vision we may do this in a couple of commands
Dim dividend As word
Dim divisor as Byte
Dim quotient As Byte
Dim remainder As Byte

quotient = Divisor / dividend
remainder = Divisor // dividend

When looking at the assembly we may discover that the code is repeated twice for both cases, but the first operation will discard the reminder. So in my mind I made a little consideration to process the result with two variable in return, which I don't know whether is feasible within a procedure.

Dim cntx As Byte                    ' returning integer value
Dim cnti As Byte                    ' returning decimal value


Proc convADC(Value As Word)
  Value = Value * 50 / 1023
  Movf convADCValueH,W             ' divide by 10
  Movwf PP0H
  Movf convADCValue,W
  Movwf PP0
  Clrf PP1H
  Movlw 10
  Movwf PP1
  Call __divide_u1616_
  Movwf cntx                        ' put the result in cntx
  cnti = PP2                        ' and the reminder in cnti
 EndProc
The above is just one of several cases. Another example would imply to divide by 60, as well, then it will return the result in sexagesimal between hours and minutes or minutes and seconds.

Certain case it may be used the Dig command to get similar option, but slightly complex.
Ignorance comes with a cost

top204

It's always nice to see assembler being used, however, your code is not taking RAM banks into account, so if the variables reside in different RAM banks, it will fail subtly, and cause other variables to be loaded instead of the intended ones.

Another way of performing the division and remainder in a single operation is:

'------------------------------------------------------------------
' Perform a single 16-bit division and extract the result of the division and the remainder
' Input     : pDivid holds the value to divide
'           : pDivisor holds the value to divide with
' Output    : The 32-bit result holds the division value in its lower 16-bits and the remainder in its higher 16-bits
' Notes     : The compiler's 16-bit division library routine loads system variables PP0\PP0H with the divide result
'           : And system variables PP2\PP2H with the remainder result from a division
'
Proc DivRem16(pDivid As Word, pDivisor As Word), Dword
    Dim PP2 As Byte System              ' Bring a compiler system variable into the BASIC code
    Dim PP2H As Byte System             ' Bring a compiler system variable into the BASIC code
    Dim wPP2 As PP2.Word                ' Combine them into a 16-bit Word variable
   
    Result.Word0 = pDivid / pDivisor    ' Perform the 16-bit division into the low Word of Result
    Result.Word1 = wPP2                 ' Load the high word of Result with the remainder value held in PP2\PP2H
EndProc

'---------------------------------------------------
Main:
    Dim MyDword As Dword                    ' Create a 32-bit variable to hold the results
    Dim wResultDiv As MyDword.Word0         ' The low word of the result holds the division return
    Dim wResultRem As MyDword.Word1         ' The high word of the result holds the remainder return
     
    MyDword = DivRem16(1000, 33)              ' Perform the division and remainder
   
    HRSOutLn "Division = ", Dec wResultDiv, " Remainder = ", Dec wResultRem

You had worked out that the 16-bit division library subroutine gives the division value in system variables PP0\PP0H and the remainder in system variables PP2\PP2H, however, on larger devices, without RAM bank manipulation, your Asm code would have caused problems because the same position of the variable in a different RAM bank will be altered instead of the variable position in a set RAM bank, unless the appropriate RAM bank is manipulated before the variable is altered. The procedure above uses your method, but lets the compiler sort out the RAM bank manipulation.

keytapper

#2
Thanks a lot, Mr Les.

I was pretty aware that the midrange family is a nightmare  :) Usually I try to stick to the same RAM bank. Some time I manage the variables position in order to obtain none (or less) bank swapping.

Definitely you know thousand time better than me what is necessary to handle.
Also a came across another idea about to return an array from a procedure. I saw that you preferred to handle the bytes in a Dword. Great idea!!
Ignorance comes with a cost