Slowly getting there. I am now getting correct results from the 8x8 Hardware Multiplier of the PIC 18F57Q84. -Great stuff!
I hacked back and forth and finally made it work after sliding around for a good while, but I wonder why I can sometimes use variables to the get numbers in and in other cases not. Is it because GC-basic decides to not interfer as soon as it detects assembler?
When using ASM the compile will pass whatever you write direct to the assembler. It has NO constrains and to be honest.. even I no longer use ASM. I trust GCBASIC compiler more and more.
The compile will use hardware multiple for PIC, AVR and LGT when it can. There has to be a hardware multiplier and it has to be 'safe' calculation. Safe being byte calculations as these hardware instructions do not update status flags (e.g., Zero or Carry), unlike the GCBASIC arithmetic operations.
GCBASIC writes very tight maths routines using the hardware when it can.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It's not an issue. I just wondered why this behaviour and didn't understand it.
If GCBASIC is already using the hardware multiplier, then I just wasted time. I searched and saw no mention about it, so I figured I it would be worth testing.
It was late yesterday and I skipped measuring. I was thinking of doing it later, but there is no point if it is already used and then it is really great and now there is a thread about it, so the next fool is pointed in the right direction.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
'Use hardware multiply instruction for byte*byte multiply
If CalcType = "BYTE" And Act = "*" And ChipFamily = 16 Then
If IsConst(V1) Then
CurrLine = LinkedListInsert(CurrLine, " movlw " + Str(MakeDec(V1)))
Else
CurrLine = LinkedListInsert(CurrLine, " movf " + V1 + ",W")
End If
If IsConst(V2) Then
CurrLine = LinkedListInsert(CurrLine, " mullw " + Str(MakeDec(V2)))
Else
CurrLine = LinkedListInsert(CurrLine, " mulwf " + V2)
End If
AV = "PRODL"
End If
What the compiler is doing internally
Load operand 1 into WREG
Either via movlw (constant) or movf.
Execute MULWF or MULLW
This triggers the hardware multiplier.
Assume the low byte of the result is in PRODL
The compiler sets AV = "PRODL" because PIC stores the low byte there.
Ignore flags
Because the multiplier never sets them.
Trust the user not to need PRODH unless explicitly requested
Many compile languages only return an 8‑bit result for byte×byte.
This is why PIC compilers must be careful: PRODL/PRODH are global, shared, and volatile.
AVR/LGT code generation
This is the source for the compiler.
'Use hardware multiply instruction for byte*byte multiply
If CalcType = "BYTE" And Act = "*" And ModeAVR And HMult Then
CurrLine = LinkedListInsert(CurrLine, " mul SysByteTempA,SysByteTempB")
AV = "SysByteTempX"
End If
What the compiler is doing internally
AVR has a true ALU-integrated multiplier.
The result always goes into:
R0 = low byte
R1 = high byte
The compiler uses temporary registers (SysByteTempA/B) because AVR multiply destroys R0/R1.
The compiler sets AV = "SysByteTempX" meaning:
“The result is now in the temp register where we copied R0.”
AVR flags are also not updated by MUL.
Same reason: MUL is not part of the ALU flag path.
🔍 Architectural comparison
Feature
PIC16/18
AVR/LGT
Multiplier integrated with ALU?
No
Yes-ish (still separate but closer)
Updates Zero/Carry?
No
No
Result registers
PRODL/PRODH
R0/R1
Side‑effects
Global registers overwritten
Global registers overwritten
Compiler complexity
High (banking, PRODL/PRODH)
Moderate (R0/R1 save/restore)
🧠 Why GCBASIC compiler treats PIC multipliers very carefully
PRODL/PRODH are global and not banked.
Interrupts can corrupt them.
Inline ASM can corrupt them.
Library routines may use them.
Flags are not updated, so conditional logic must be explicit.
Multi‑precision arithmetic must manually check PRODH.... hence this is not implemented
This is why GCBASIC compilers wrap multiply operations in helper routines or generate defensive code.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This reads like I am the smart one. I am not. I am looking at the code Hugh wrote when he was a youngling. He made the right decision from an architectual approach. Use the harware ONLY when safe and generated defensive/robust code.
Thank you, Hugh.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
"5. Trust the user not to need PRODH unless explicitly requested"
So should I mutliply as usual with GCbasic and then read from prodh directly to paste a word together. Is that what this says? I could really use the resulting word value.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The warnings are likely no problem in my case. I will be using inside one single interrupt. It will be for generating audio, so a failure will not exactly be life threateneing to most humans. Good to know though.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I find this is intriging. Sorry for being persistant.
If I am doing the multiplication inside the only interrupt, immediately storing the result. What may interrupt/corrupt it?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Slowly getting there. I am now getting correct results from the 8x8 Hardware Multiplier of the PIC 18F57Q84. -Great stuff!
I hacked back and forth and finally made it work after sliding around for a good while, but I wonder why I can sometimes use variables to the get numbers in and in other cases not. Is it because GC-basic decides to not interfer as soon as it detects assembler?
I am not sure I get the issue.
When using ASM the compile will pass whatever you write direct to the assembler. It has NO constrains and to be honest.. even I no longer use ASM. I trust GCBASIC compiler more and more.
The compile will use hardware multiple for PIC, AVR and LGT when it can. There has to be a hardware multiplier and it has to be 'safe' calculation. Safe being byte calculations as these hardware instructions do not update status flags (e.g., Zero or Carry), unlike the GCBASIC arithmetic operations.
GCBASIC writes very tight maths routines using the hardware when it can.
It's not an issue. I just wondered why this behaviour and didn't understand it.
If GCBASIC is already using the hardware multiplier, then I just wasted time. I searched and saw no mention about it, so I figured I it would be worth testing.
It was late yesterday and I skipped measuring. I was thinking of doing it later, but there is no point if it is already used and then it is really great and now there is a thread about it, so the next fool is pointed in the right direction.
🛠️ GCBASIC compiler behaviour
PIC code generation
This is the source for the compiler.
What the compiler is doing internally
Load operand 1 into WREG
Either via
movlw(constant) ormovf.Execute MULWF or MULLW
This triggers the hardware multiplier.
Assume the low byte of the result is in PRODL
The compiler sets
AV = "PRODL"because PIC stores the low byte there.Ignore flags
Because the multiplier never sets them.
Trust the user not to need PRODH unless explicitly requested
Many compile languages only return an 8‑bit result for byte×byte.
This is why PIC compilers must be careful: PRODL/PRODH are global, shared, and volatile.
AVR/LGT code generation
This is the source for the compiler.
What the compiler is doing internally
AVR has a true ALU-integrated multiplier.
The result always goes into:
R0 = low byte
R1 = high byte
The compiler uses temporary registers (
SysByteTempA/B) because AVR multiply destroys R0/R1.The compiler sets
AV = "SysByteTempX"meaning:“The result is now in the temp register where we copied R0.”
AVR flags are also not updated by MUL.
Same reason: MUL is not part of the ALU flag path.
🔍 Architectural comparison
🧠 Why GCBASIC compiler treats PIC multipliers very carefully
This is why GCBASIC compilers wrap multiply operations in helper routines or generate defensive code.
This reads like I am the smart one. I am not. I am looking at the code Hugh wrote when he was a youngling. He made the right decision from an architectual approach. Use the harware ONLY when safe and generated defensive/robust code.
Thank you, Hugh.
"5. Trust the user not to need PRODH unless explicitly requested"
So should I mutliply as usual with GCbasic and then read from prodh directly to paste a word together. Is that what this says? I could really use the resulting word value.
Just use normal maths. I would not underwrite any asumptions on the state of PRODH. You would have to disable interrupts, looks for errors and zero.
The warnings are likely no problem in my case. I will be using inside one single interrupt. It will be for generating audio, so a failure will not exactly be life threateneing to most humans. Good to know though.
Warnings! What warning? Memory warnings?
I meant your list above.
...
PRODL/PRODH are global and not banked.
Interrupts can corrupt them.
Inline ASM can corrupt them.
...
etc
If you have an interrupt.. do not use PRODH. My advice. Use GCBASIC regular maths.
If I use it after the interrupt has triggered and before it triggers next time. What is it that may happen?
As there is no way of knowing when the maths was interrupted the W will be corrupted ( this is sort of a guaranteed ).
I find this is intriging. Sorry for being persistant.
If I am doing the multiplication inside the only interrupt, immediately storing the result. What may interrupt/corrupt it?
You mean.
If I use it within the interrupt handler . What is it that may happen?
It should be ok.
it might be worth noting that for the 18FxxQ84 the PRODx regs are saved as part of the hardware context