News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

multiplication out of range

Started by Pepe, Today at 12:10 PM

Previous topic - Next topic

Pepe

Is there any other way to be able to perform the multiplication without having to declare the scale as a floating-point constant or as a dword variable by assigning it the value of the scale, or use an intermediate dword variable and be able to declare the scale only as a dword constant to reduce the code size?

trastikata

#1
Hello Pepe,

What is target code size, is it for a bootloader area? If you don't need all characters to be displayed on that display, you can reduce the font.

QuoteIs there any other way to be able to perform the multiplication without having to declare the scale as a floating-point constant or as a dword variable

I don't understand what is the exact question here? What I do usually if I have enough free RAM is to declare variable and load one time the needed constant value, then use the variable in expressions.

Further optimization can be done in the counter loop where you don't need to scale the counter value because you have only multiplication - it is enough to scale the constant and then divide by the scale.

If you can provide the original code with all FP values and multiplications, as well as the range of the values, I could suggest an optimized variant, but without knowing the constraints, I have to assume the maximum range, which is in the Dword area.

Pepe

I can't show the code because it's a commercial product. The problem is that I can't replace the PIC with one of higher capacity right now, and if I declare the scaling constant as a float, the generated code exceeds the PIC's maximum capacity. The example provided is only to show the part where I use the scaling effect, which I employ in several parts of the commercial program.

trastikata

#3
Quote from: Pepe on Today at 05:31 PMThe problem is that I can't replace the PIC with one of higher capacity right now, and if I declare the scaling constant as a float, the generated code exceeds the PIC's maximum capacity.

This is because it will load various FP procedures in the FLASH. The example you provided is a bit confusing since you multiply by 100 and divide by 100 in the same line, which will not achieve what you want, if I understood your question.

Looking at your code example, should I assume the scale can be anything and not only 100 because if it is 100 then this line "wb = wa * scale / 100" makes no sense to me?

Any other glyph used in your code than "0-9", "/", "*" and space?

Can you share not the entire code, but only the FP part that you want to replace?


Pepe

Yes, the scale can be any value, I put 100 in the example as a sample

trastikata

#5
Quote from: Pepe on Today at 06:20 PMYes, the scale can be any value, I put 100 in the example as a sample

Ah I see, then can I assume 2 decimal digits precision? and what is the range of the original multiplicands?

Your existing code:

Symbol scale = 100
Symbol scale1 = 100.0
Dim scale2 As Dword = 100
Dim wa As Word
Dim wb As Word
Dim wc As Dword
....
Do
 For wa = 1000 To 2000 Step 100
     wb = wa * scale / 100
     Print At 0,0,Dec wa," * ",Dec scale," / 100 = ", Dec wb,"      "
     wb = wa * scale1 / 100
     Print At 0,15,Dec wa," * ",Dec0 scale1," / 100 = ", Dec wb,"      "
     wc = wa * scale
     wb= wc / 100
     Print At 0,30,Dec wa," * ",Dec scale," / 100 = ", Dec wb,"      "
     wb = wa * scale2 / 100
     Print At 0,45,Dec wa," * ",Dec scale2," / 100 = ", Dec wb,"      "
     RefreshDisplay
     DelayMS 1000
 Next
Loop




is equivalent to this:

Symbol scale = 18.35    'Just a random FP scale as example
Symbol scale1 = 321.47  'Just a random FP scale as example
Symbol scale2 = 5556.35 'Just a random FP scale as example

Dim wScale As Word = scale * 100    'Make sure the Word will not overflow
Dim wScale1 As Word = scale1 * 100  'Make sure the Word will not overflow
Dim dScale2 As Dword = scale2 * 100
Dim wa As Word
Dim wb As Word
Dim wc As Dword
....
Do
 For wa = 10 To 20 Step 1
     wb = wa * wScale  'Make sure the Word will not overflow
     Print At 0,0,Dec wa," * ",Dec scale," / 100 = ", Dec wb,"      "
     wb = wa * wScale1 'Make sure the Word will not overflow
     Print At 0,15,Dec wa," * ",Dec0 scale1," / 100 = ", Dec wb,"      "
     wc = wa * wScale
     Print At 0,30,Dec wa," * ",Dec scale," / 100 = ", Dec wb,"      "
     wb = wa * dScale2 'Make sure the Word will not overflow
     Print At 0,45,Dec wa," * ",Dec scale2," / 100 = ", Dec wb,"      "
     RefreshDisplay
     DelayMS 1000
 Next
Loop

and if you modify the font by removing unnecessary glyph, you can further reduce the code size.

top204

#6
As you know, for larger values within expressions, the larger variables must be used, either inside the expression, or as its assignment., otherwise, overflows will occur. The compiler does not use larger variables inside expressions as default, because this would make all expressions take up a lot of code memory space, and RAM, and time, because it would need to call the larger maths subroutines etc...

There is a way to get around using more RAM, by using a few of the compiler's system variables, that get overwritten anyway, so they are temporary. However, it must be remembered that the system variables are very volatile, and will not hold the value for very long, or when some commands are used, because they can be used to hold a commands parameters, or an expression stack etc...

Below is a simple code listing to show what I mean:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Use a set of compiler system variables as a larger temporary variable.
'
' Written by Les Johnson for the Positron8 compiler.
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook
'
    Device = 18F26K22                                                   ' Tell the compiler what device to compile for
    Declare Xtal = 64                                                   ' Tell the compiler what frequency the device will be operating at (in MHz)
    Declare Auto_Heap_Arrays = On                                       ' Tell the compiler to create arrays above standard variables, so assembler code is more efficient
    Declare Auto_Heap_Strings = On                                      ' Tell the compiler to create Strings above standard variables, so assembler code is more efficient
    Declare Auto_Variable_Bank_Cross = On                               ' Tell the compiler to create any multi-byte variables in the same RAM bank. For more efficiency
'
' Setup USART1
'
    Declare Hserial_Baud = 9600                                         ' Set the Baud rate for USART1
    Declare HRsout1_Pin = PORTC.6                                       ' Set the pin to use for USART1 TX
'
' Create global variables, constants and aliases here
'
    Symbol cMultiplier = 100                                            ' Holds the constant multiplier value
    Dim wMultiplicand As Word                                           ' Holds the 16-bit multiplicand value

    Dim PP6    As Byte System                                           ' Create a compiler system Byte variable
    Dim PP6H   As Byte System                                           ' Create a compiler system Byte variable
    Dim PP6HH  As Byte System                                           ' Create a compiler system Byte variable
    Dim PP6HHH As Byte System                                           ' Create a compiler system Byte variable
    Dim wPP6   As PP6.Word                                              ' Create a compiler system Word alias variable
    Dim dPP6   As PP6.Dword                                             ' Create a compiler system Dword alias variable

    Dim TempDword As dPP6                                              ' Create an alias to a system Dword variable

'-------------------------------------------------------------------------------------------
' The main program starts here
' Calculate a 32-bit expression, and transmit the results to a serial terminal.
'
Main:
    Setup()                                                             ' Setup the program and any peripherals

    Do
        For wMultiplicand = 1000 To 2000 Step 100
            TempDword = (wMultiplicand * cMultiplier) / 100
            HRsout1Ln "(", Dec wMultiplicand, " * ", Dec cMultiplier, ") / 100 = ", Dec TempDword.Word0
            DelayMS 1000
        Next
    Loop

'----------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    Osc_64MHz()                                                         ' Set the device to 64MHz operation using its internal oscillator
EndProc

'---------------------------------------------------------------------------------------------
' Set the PIC18F26K22 device to 64MHz operation using its internal oscillator
' Input     : None
' Output    : None
' Notes     : None
'
Proc Osc_64MHz()
    OSCCON  = $70
    OSCCON2 = $04
    OSCTUNE = $40
    DelayMS 100
EndProc

'---------------------------------------------------------------------------------------------
' Setup the fuses to use the internal oscillator on a PIC18Fx6K22 devices.
' OSC pins RA6 and RA7 are general purpose I/O.
'
Config_Start
    FOSC     = INTIO67                                                  ' Internal oscillator
    PRICLKEN = Off                                                      ' Primary clock disabled
    MCLRE    = EXTMCLR                                                  ' MCLR pin enabled
    WDTEN    = Off                                                      ' Watchdog Timer disabled
    PLLCFG   = Off                                                      ' Oscillator used directly
    FCMEN    = Off                                                      ' Fail-Safe Clock Monitor disabled
    IESO     = Off                                                      ' Oscillator Switchover mode disabled
    PWRTEN   = On                                                       ' Power up timer enabled
    BOREN    = Off                                                      ' Brown-out Reset disabled
    BORV     = 190                                                      ' VBOR set to 1.9 V nominal
    WDTPS    = 128                                                      ' Watchdog Timer Postscale is 1:128
    HFOFST   = Off                                                      ' The Access clock is not held Off until the HF-INTOSC is stable
    PBADEN   = Off                                                      ' PORTB<4:0> pins are configured as digital on reset
    CCP2MX   = PORTC1                                                   ' CCP2 input/output is multiplexed with RC1
    CCP3MX   = PORTB5                                                   ' P3A/CCP3 input/output is multiplexed with RB5
    T3CMX    = PORTC0                                                   ' T3CKI is on RC0
    P2BMX    = PORTB5                                                   ' P2B is on RB5
    STVREN   = On                                                       ' Stack full/underflow will cause a reset
    LVP      = Off                                                      ' Single-Supply ICSP disabled
    Debug    = Off                                                      ' Background debugger disabled. RB6 and RB7 configured as general purpose I/O pins
    XINST    = Off                                                      ' Extra mnemonics disabled
    Cp0      = Off                                                      ' Block 0 (000800-001FFF) not code protected
    CP1      = Off                                                      ' Block 1 (002000-003FFF) not code protected
    CPB      = Off                                                      ' Boot block (000000-0007FF) not code protected
    CPD      = Off                                                      ' Data EEPROM not code protected
    WRT0     = Off                                                      ' Block 0 (000800-001FFF) not write protected
    WRT1     = Off                                                      ' Block 1 (002000-003FFF) not write protected
    WRTB     = Off                                                      ' Boot block (000000-0007FF) not write protected
    WRTC     = On                                                       ' Configuration registers (300000-3000FF) write protected
    WRTD     = Off                                                      ' Data EEPROM not write protected
    EBTR0    = Off                                                      ' Block 0 (000800-001FFF) not protected from table reads executed in other blocks
    EBTR1    = Off                                                      ' Block 1 (002000-003FFF) not protected from table reads executed in other blocks
    EBTRB    = Off                                                      ' Boot block (000000-0007FF) not protected from table reads executed in other blocks
Config_End

On a serial terminal, it shows:

(1000 * 100) / 100 = 1000
(1100 * 100) / 100 = 1100
(1200 * 100) / 100 = 1200
(1300 * 100) / 100 = 1300
(1400 * 100) / 100 = 1400


The code listing uses the compiler system variables: PP6\H\HH\HHH, and then aliases them as Word and DWord. So the code does not take more RAM. However, it will take more code memory space, because it must add and call the 32-bit multiply and divide routines, and there is no way around this.

Regards
Les


Pepe

Thank Les for your response.

JonW

#8
Quote "I can't show the code because it's a commercial product " 

No disrespect, but this is why Les needs to charge/diversify to a commercial route.