Advice on 16-bit calculation

Go To Last Post
21 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello Experts!

I am looking for an advice/some opinions on this issue. I have a design with an Atmega16 that has 100 programs with 8 bytes of parameters each, placed in the SRAM. So the table is looking like this:

PrgPage_0: .byte prgPageSize  ; (first byte is adr 0x60)
PrgPage_1: .byte prgPageSize  ; (first byte is adr 0x68)
.......(goes to PrgPage_99) 

The machine is (/will soon be) controlled by MIDI program change 00-99. So program change 1 should load the contents in address 0x68 in the SRAM and so on. Now the calculation is easy I just multiply the MIDI prg. change number with 8 and add it to address 0x60.

Now comes the real question:

As I am using quite a lot of the poor 1KB SRAM I would like to save the stack as much as possible to prevent a stack-crash, so I wondered if I use some lookup tables placed in the FLASH-RAM instead of the 'mul' calculations I could maybe save the stack(?)

My Idea is like this:

The tables:


CalcRamH:

.db	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  
.db	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  
.db	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
.db	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
.db	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
.db	0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02
.db	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02
.db	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02
.db	0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
.db	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03	
	
CalcRamL:	

.db	0x60, 0x68, 0x70, 0x78, 0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8 
.db	0xb0, 0xb8, 0xc0, 0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8 
.db	0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48
.db	0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x80, 0x88, 0x90, 0x98
.db	0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, 0xd8, 0xe0, 0xe8
.db	0xf0, 0xf8, 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38
.db	0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x80, 0x88
.db	0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, 0xd8
.db	0xe0, 0xe8, 0xf0, 0xf8, 0x00, 0x08, 0x10, 0x18, 0x20, 0x28
.db	0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78

The calculation code something like this (tmp1 is holding the program change number):

	; calc RAM-address
	clr tmp2
	ldi ZH,HIGH(calcRamH)
	ldi ZL, LOW(calcRamH)
	add ZL, tmp1
	adc ZH, tmp2 ; 0+carry
	lpm
	mov XH, r0
	ldi ZH,HIGH(calcRamL)
	ldi ZL, LOW(calcRamL)
	add ZL, tmp1
	adc ZH, tmp2 ; 0+carry
	lpm
	mov XL, r0
	
	ldi YH,HIGH(PrgPage_0)
	ldi YL, LOW(PrgPage_0)
   add YH:XH
   adc YL:XL
        ; ...and more of, something like that..

Q1: Does this look like a good or bad idea? / Do I really save the stack this way?

Q2: (only if so): Is this the way to load/add the registers, or is there a more elegant way to do it?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

WHY???

Why do you store your preset "programs" in RAM?
Why on Earth your "calculations" would require any stack space?

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MBedder wrote:
WHY???

Why do you store your preset "programs" in RAM?

When the machine starts it loads the entire table from an external EEPROM. That is to minimize the time and potential errors of loading from the external EEPROM all the time.

Quote:

Why on Earth your "calculations" would require any stack space?

Hmm, I just had the impression that a multiply with 16 bit result would require some stack-use. If I'm wrong the problem is easily solved..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1) Where are these multiplies that you are concerned about? I see no MUL in your code fragments.

2) Is that the extent of your tables, as shown? Why in the world are you using an external EEPROM? Use internal EEPROM, or place directly into flash.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
1) Where are these multiplies that you are concerned about? I see no MUL in your code fragments.

No, I replaced them temporarily. It's about multiplying a program change number (0-99) with another byte to get a 16-bit address. As said before I had the impression that the 'mul' function was using the stack for intermediate calculations. I can understand that it is not?

Quote:

2) Is that the extent of your tables, as shown? Why in the world are you using an external EEPROM? Use internal EEPROM, or place directly into flash.

Lee

Well, the internal EEPROM is only 512Bytes that is 288 bytes to small, as the table is 100 pages of 8 bytes.

The FLASH could have been an option. I didn't know about the option of storing data on the fly in the FLASH RAM at the time I made the design.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You don't seem to need altering the "program parameters" on the fly, so you can just store your "program" tables in an internal Flash (BTW please do not call it "FLASH RAM" - flash is flash, RAM is RAM).

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MBedder wrote:
You don't seem to need altering the "program parameters" on the fly, so you can just store your "program" tables in an internal Flash....

I have to be able to store data on the fly. All the parameters are user editable and the changes have to be there after restart. That's why I'm not just using a lookup table.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The MUL operation does NOT use the stack in any way. It would tell you in the "AVR Instruction Set" document, if it did. It is done in 2 clock cycles, so there is no time to get anything in and out of the stack, anyway.

You are lucky, this time, because the Mega16 has the MUL instruction. Some do not.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey thanks a lot Jim for the very clear answer. That was exactly what I was looking for! I guess I had mixed up some AVR documents describing multiplication..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, there are ways to write to the flash. But let's skip that for now, as this seems to be an early AVR app for you.

First, if 1k of storage is important to your app, why did you pick an AVR model that is starves in your important criterion? Surely the system design is less expensive and much simpler if you don't have the extra external chip.

Second, can the 8 bytes x 100 be packed somehow? Are all bits of all parameters used?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Btw, any AVR's except the most ancient ones can load the result of LPM into any register of your choice.
Like

    lpm   xl,z   ;load LPM byte into XL
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Now the calculation is easy I just multiply the MIDI prg. change number with 8
Multiplying by 8 is just num<<3. No stack usage whatsoever.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
Quote:
Now the calculation is easy I just multiply the MIDI prg. change number with 8
Multiplying by 8 is just num<<3. No stack usage whatsoever.

Not exactly, cause the result is 16-bit..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

IIRC the MIDI prg change is 2 bytes.
The first byte select MIDI CHANNEL 1-16 (0xC0-0xCF)
The second byte select MIDI PGM 1-255 (0x00-0xFF).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lennart wrote:
IIRC the MIDI prg change is 2 bytes.
The first byte select MIDI CHANNEL 1-16 (0xC0-0xCF)
The second byte select MIDI PGM 1-255 (0x00-0xFF).

No, MIDI program change goes from 0x00-0x7f (127). What's your point?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

if num is a 16 bit variable, shifting left by three bits is multiplying by 8. Again, no stack usage. In assembler, six instructions and two registers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
No, MIDI program change goes from 0x00-0x7f (127). What's your point?
You're quite right, it was a decade since I've played with MIDI.
I could not see where 16 bit result was involved in prg change, but never mind.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lennart wrote:
Quote:
No, MIDI program change goes from 0x00-0x7f (127). What's your point?
You're quite right, it was a decade since I've played with MIDI.
I could not see where 16 bit result was involved in prg change, but never mind.

I suppose indexing the table in ram address.

You can left-shift any bit number. Even C compiler can do it so it must be possible in ASM too. Just take a look about shifting the bits through carry to next register.

But hardware multiplier will do just the same in 2 cycles, you can't do that by shifting bits.
[/code]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jepael wrote:
Lennart wrote:
Quote:
No, MIDI program change goes from 0x00-0x7f (127). What's your point?
You're quite right, it was a decade since I've played with MIDI.
I could not see where 16 bit result was involved in prg change, but never mind.

I suppose indexing the table in ram address.

You can left-shift any bit number. Even C compiler can do it so it must be possible in ASM too. Just take a look about shifting the bits through carry to next register.

But hardware multiplier will do just the same in 2 cycles, you can't do that by shifting bits.
[/code]

Precisely. Of cause it is possible to check the carry for each shift anyway but now thanks to Jim I am wiser now and uses the 'mul' function :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
But hardware multiplier will do just the same in 2 cycles, you can't do that by shifting bits.
But you have to get the number to multiply by into a register (1 cycle) then get the 16 bit result from R0:R1 (1 cycle), making it realistically 4 cycles. The shifting could be done in 6 cycles. And the original question was how to reduce stack space, not how to increase speed. But in this case, since we know that the maximum value of the number is 15, then you could do this (where A contains the channel #):

swap A
lsr A

This is 2 cycles, 2 words and only 1 register.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
But in this case, since we know that the maximum value of the number is 15, then you could do this (where A contains the channel #):

swap A
lsr A

This is 2 cycles, 2 words and only 1 register.

I'm not quite sure what you mean. This is about calculating a 16-bit address with a program change number from 0-99. Not just Checking the MIDI channel.