Omnimaga

Calculator Community => TI Calculators => ASM => Topic started by: the_mad_joob on June 27, 2014, 12:39:06 am

Title: 8X+ > flash writing question
Post by: the_mad_joob on June 27, 2014, 12:39:06 am
Welcome...

Alright, i'm about to code a few routines that will write to archive space.
Of course, i'm gonna have to follow what is written on that page : http://wikiti.brandonw.net/index.php?title=83Plus:OS:Raw_Flash_Commands (http://wikiti.brandonw.net/index.php?title=83Plus:OS:Raw_Flash_Commands)
Still, there is a part of the code that i don't understand :
Code: [Select]
ld a,b
xor (hl)
bit 7,a
jr z,programdone
bit 5,(hl)
jr z,programwaitloop
Why using XOR (HL) and checking bit 7 of A where a CP (HL) would be faster ?
Also, i really have no idea what is the point of checking bit 5 of (HL).

Any clarification greatly appreciated =]
Title: Re: 8X+ > flash writing question
Post by: chickendude on June 28, 2014, 10:43:37 am
...or simply leaving out the bit 7,a. I'm also not sure what the following "bit 5, (hl)" is for. Have you tried seeing if it works without it? You're just waiting for the byte to update so i can't imagine what you'd need it for.
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on June 28, 2014, 12:03:48 pm
No, haven't tried yet any attempt to write.
You know, that's the kind of thing you want to understand before trying on real hardware =P
I don't really believe it, but i could potentially imagine that the flash chip behaves differently when he hasn't totally finished accepting a write attempt (depending on the used op code).
Title: Re: 8X+ > flash writing question
Post by: calc84maniac on June 28, 2014, 12:11:35 pm
While a flash write is in progress, when you read a byte from flash, you get a status byte rather than actual data. Bit 7 is guaranteed to be the opposite of the data being written, and conversely, when it succeeds, bit 7 is guaranteed to match the data that was written. Bit 5 of the status byte gets set when there is an error, which can be either a timeout or trying to write a 1 over a 0. Bit 5 should be checked only when you already know bit 7 doesn't match, of course.
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on June 28, 2014, 06:28:19 pm
While a flash write is in progress, when you read a byte from flash, you get a status byte rather than actual data. Bit 7 is guaranteed to be the opposite of the data being written, and conversely, when it succeeds, bit 7 is guaranteed to match the data that was written. Bit 5 of the status byte gets set when there is an error, which can be either a timeout or trying to write a 1 over a 0. Bit 5 should be checked only when you already know bit 7 doesn't match, of course.
Fat thx for the explanation =]
Anyway, whether reading returns a status byte or the actual data, i still think a simple LD A,(HL) \ CP B or LD A,B \ CP (HL) would be more appropriate (faster & lighter).
Am i wrong ?
Also, other question : What can cause a timeout ?
Thx again for your time...
Title: Re: 8X+ > flash writing question
Post by: chickendude on June 28, 2014, 10:20:41 pm
I think the "trick" here is that bit 7 will always be the opposite of the byte you're trying to write (here in b), so if bit 7 of b is 1, bit 7 of (hl) will be 0 (so XORing the two will always give you 1). If it's finished, then you'll get the same bit that's in b, so XORing them will give you 0 (so z will be set). I don't really know how all of it works, that's just what i got from calc84's message.

EDIT: And (hl) doesn't really return the value of (hl) but rather a status byte, so i think you could read from anywhere in flash (like "ld a,($4000) \ xor b") and it would return the same thing until the thing finishes. Also, if you just cp (hl) there's a chance that the status byte has the same value as the byte you're trying to write.
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on June 28, 2014, 11:39:10 pm
I think the "trick" here is that bit 7 will always be the opposite of the byte you're trying to write (here in b), so if bit 7 of b is 1, bit 7 of (hl) will be 0 (so XORing the two will always give you 1). If it's finished, then you'll get the same bit that's in b, so XORing them will give you 0 (so z will be set). I don't really know how all of it works, that's just what i got from calc84's message.

EDIT: And (hl) doesn't really return the value of (hl) but rather a status byte, so i think you could read from anywhere in flash (like "ld a,($4000) \ xor b") and it would return the same thing until the thing finishes. Also, if you just cp (hl) there's a chance that the status byte has the same value as the byte you're trying to write.
That is how i understood it, too.
2 cases :
1) writing complete, reading will return the effective byte at the address, therefore all bits will match between the write & the read.
2) writing incomplete, reading will return a status byte which bit 7 is the opposite of bit 7 of the byte you asked to write (ugly sentence, i know XD).
The thing is, that if bit 7 of the status byte is "guaranteed" to be the opposite, then i don't see how there is a chance to have a match when comparing the 2 bytes.
I mean, comparing byte %1XXXXXXX and byte %0XXXXXXX can never set the zero flag, so why wasting some cycles with that slow BIT instruction ?

Sorry again to bother you with that guyz, but that's important, cause such code can be iterated a lot when writing to flash and highly deserves to be speed-optimized.
Title: Re: 8X+ > flash writing question
Post by: calc84maniac on June 28, 2014, 11:59:34 pm
I think the "trick" here is that bit 7 will always be the opposite of the byte you're trying to write (here in b), so if bit 7 of b is 1, bit 7 of (hl) will be 0 (so XORing the two will always give you 1). If it's finished, then you'll get the same bit that's in b, so XORing them will give you 0 (so z will be set). I don't really know how all of it works, that's just what i got from calc84's message.

EDIT: And (hl) doesn't really return the value of (hl) but rather a status byte, so i think you could read from anywhere in flash (like "ld a,($4000) \ xor b") and it would return the same thing until the thing finishes. Also, if you just cp (hl) there's a chance that the status byte has the same value as the byte you're trying to write.
That is how i understood it, too.
2 cases :
1) writing complete, reading will return the effective byte at the address, therefore all bits will match between the write & the read.
2) writing incomplete, reading will return a status byte which bit 7 is the opposite of bit 7 of the byte you asked to write (ugly sentence, i know XD ).
The thing is, that if bit 7 of the status byte is "guaranteed" to be the opposite, then i don't see how there is a chance to have a match when comparing the 2 bytes.
I mean, comparing byte %1XXXXXXX and byte %0XXXXXXX can never set the zero flag, so why wasting some cycles with that slow BIT instruction ?

Sorry again to bother you with that guyz, but that's important, cause such code can be iterated a lot when writing to flash and highly deserves to be speed-optimized.
According to the documentation, due to some sort of timing/synchronization issue, the first time you get a match in bit 7, the rest of the data is not guaranteed to be correct (it says to read again to get the actual data). But really, the BIT instruction is indeed superfluous; I usually check the sign flag after the XOR instead of doing a BIT followed by checking the zero flag.

Edit: Oh yeah, you also asked what could cause a timeout. Well, I think it just happens if enough time passes without the write succeeding, due to some sort of hardware failure. This prevents it from ever getting stuck in an infinite wait loop.
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on June 29, 2014, 12:57:23 am
Hmm, i find that "rest of the data is not guarenteed to be correct" pretty scary.
Looks to me like when the chip changes the read byte from "status" to "data", it doesn't update the bits all at once (theory).
Then, checking all the bits would be even more safe...

Thx for the data about timeout, too.
Maybe batteries becoming low in the middle of a writing procedure could also cause a timeout (another theory)...
Title: Re: 8X+ > flash writing question
Post by: DrDnar on June 30, 2014, 04:15:49 pm
Writing and erasing flash requires pulsing the flash memory with high voltages. Older flash chips had a 12-20 V pin to supply the high voltage directly, but today's chips instead use a device known as a charge pump to multiply the supply voltage into the correct voltage. Charge pumps work by charging capacitors, so some time is required between when you request a write or erase and when the voltage is available. When you request a write or erase, the chip enters a status mode, in which reads return a status instead of real data, so that you know when the operation has completed.

Each time a flash cell is pulsed with high voltage, it is also damaged a little, causing the flash memory to wear out over time. In heavily used flash chips, multiple pulses may be required for a write or erase to take effect, so the operation may take longer. A write or erase may fail if the flash cell is worn out. In these circumstances, some bits are likely to have the correct value, while others won't. If the batteries are low during a flash operation, charging the charge pump will take longer, and it is possible the voltage will stay depressed for so long that the flash chip gets confused and stops working right. In other words, low batteries may cause the calculator to crash outright.

The datasheet indicates that if there's an error, the chip does not immediately return to read mode. Instead, you have to issue a reset command before it will enter read mode. If you simply do CP (HL) until Z is set, you will hang if there's an error writing.

Checking the sign flag is a possible optimization, with the downside that the code is no longer relocatable.

The BIT 7, A thing and jump instead of RET Z also add a delay between when bit 7 is correct and we start trying to fetch opcodes from flash again; TI and I essentially make an assumption that the flash chip won't return garbage for the other bits for more than a few clock cycles. In reality, the warning calc84 mentioned most likely only applies to CPUs that can fetch one byte per clock cycle, so a read on the very next clock cycle should be correct. The Z80 can't do another read on the very next clock cycle, so RET Z should be fine.
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on July 01, 2014, 11:31:25 am
Thx a lot for all that in-depth infos DrD =]
Just a question, what you mean by "the code is no longer relocatable" ?

Also, i have another question now.
I was thinking of optimizing the 4 bus cycles part, using registers as much as possible.
As a result, the commands may be sent faster, maybe too fast.
Is a delay needed between the unlocks, write command, and data sending ?
Title: Re: 8X+ > flash writing question
Post by: chickendude on July 01, 2014, 01:28:32 pm
Because you'd have to change the jr to a jp, which uses an absolute address rather than a relative one.

And thanks calc84 and DrDnar for the explanations.
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on July 02, 2014, 01:43:24 am
Oh, of course...
Thx chickendude =]
Title: Re: 8X+ > flash writing question
Post by: Streetwalrus on July 02, 2014, 08:14:56 am
So um... With all these low level questions, are you making an OS or something ? :P
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on July 02, 2014, 12:06:11 pm
Yo Streety =]
Something between an OS and a shell...
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on July 03, 2014, 09:44:57 pm
I took a look at the datasheet, to understand things better.
Also, while i was thinking of a way to optimize the code, i found something worth mentionning (still in the wikiti code example).
First, let me put it there again :
Code: [Select]
   ld a,b
   xor (hl)
   bit 7,a
   jr z,programdone
   bit 5,(hl) !!!
   jr z,programwaitloop
As you can see, the code actually does 2 separate readings (XOR (HL) & BIT 5,(HL)).
The thing is, that if the chip happens to switch from "status" to "data" mode right before the second reading, bit 5 of actual data will be tested, potentially leading to an unwanted abort instruction.
To avoid that, i guess there is no other choice but to read only once, save the reading into a register, to be sure that you read bits 7 & 5 from the same byte.
Am i right about that potential breach ?

#####

As i said earlier, i decided to optimize the code in favor of fast & successful writings.
Here is what i intend to use :
Code: [Select]
;b = byte
;de = address

   ld hl,$0AAA
   ld (hl),l

   ld hl,$0555
   ld (hl),l

   ld a,$A0
   ld ($0AAA),a

   ld a,b
   ld (de),a

read

   ld a,(de)

   cp b ; yep, cp the fastest option for fast & successful writings (using xor directly would add 4 cycles for the backup)
   ret z

   ld c,a ; backup, to be sure to read bit 5 of the same byte later

   xor b
   ret p

   bit 5,c
   jp z,read

   ld a,$F0
   ld ($0000),a

   scf

   ret

;cf = 0 (success) | 1 (failure)
Thx in advance for letting me know if something is wrong or if you think it could be optimized more...
Title: Re: 8X+ > flash writing question
Post by: chickendude on July 04, 2014, 05:05:45 am
I think in the majority of cases jr z will be faster than jp z, i'm not sure but i would assume that you wouldn't come across an error very often. When jr doesn't take the jump, it's both faster and smaller than jp (i'm talking about after the bit 5,c).

EDIT: Disregard what i said, i just looked at the code a bit more closely and realize that bit 5 would be set not reset if there was an error  :-X
Title: Re: 8X+ > flash writing question
Post by: DrDnar on July 05, 2014, 03:11:48 pm
The thing is, that if the chip happens to switch from "status" to "data" mode right before the second reading, bit 5 of actual data will be tested, potentially leading to an unwanted abort instruction.
Am i right about that potential breach ?
That can happen, and in fact probably happens a lot, but it's not a problem unless your routine also returns an error status. Issuing the reset command in read mode does nothing, so there's no reason to go out of your way to prevent that.
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on July 05, 2014, 03:23:24 pm
That can happen, and in fact probably happens a lot, but it's not a problem unless your routine also returns an error status. Issuing the reset command in read mode does nothing, so there's no reason to go out of your way to prevent that.
Interesting...
But yes, my code will have to specify if an error occured.
Thx for your time, again =]
Title: Re: 8X+ > flash writing question
Post by: DrDnar on July 05, 2014, 03:58:10 pm
Yes, my code will specify if an error occured.
Thx for your time, again =]
In that case, have the error handler check the data to see if it's actually different, which will be slightly faster.
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on July 05, 2014, 04:08:49 pm
In that case, have the error handler check the data to see if it's actually different, which will be slightly faster.
Good to know.
Is the error handler system-dependant ?
Cause if yes, my project will be totally free from the TI-OS.
I guess i would have to use IM 2 or something to be able to do that...
Title: Re: 8X+ > flash writing question
Post by: DrDnar on July 05, 2014, 05:14:00 pm
Is the error handler system-dependant ?
No, I mean, in your flash write routine, when you see an error, double check if the data is in fact different than what was intended to be written, and only report an error if it's different. This will save you from the logic of retaining the status read value in a register.
Title: Re: 8X+ > flash writing question
Post by: aeTIos on July 05, 2014, 08:10:51 pm
Yo Streety =]
Something between an OS and a shell...
That sounds interesting. You have my attention.
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on July 06, 2014, 04:44:16 am
No, I mean, in your flash write routine, when you see an error, double check if the data is in fact different than what was intended to be written, and only report an error if it's different. This will save you from the logic of retaining the status read value in a register.
Oh, my bad (thought you were talking about using the OS error handler).
I think i'll use that then :
Code: [Select]
;c = byte
;de = address

   ld hl,$0AAA
   ld (hl),l

   ld hl,$0555
   ld (hl),l

   ld a,$A0
   ld ($0AAA),a

   ex de,hl
   ld (hl),c

check

   ld a,c

   xor (hl)
   ret p

   bit 5,(hl)
   jp z,check

   ld a,c

   xor (hl)
   ret p

   ld a,$F0
   ld ($0000),a

   scf

   ret

;cf = 0 (success) | 1 (failure)

That sounds interesting. You have my attention.
I honestly don't know if that project will see the light, but i'll do my best =]

EDIT :

DrDnar, You said earlier that the calc would probably crash if batteries are low during a flash operation.
Isn't DQ5 (bit 5) supposed to handle that ?
Anyway, i already intended to check the batteries before starting any operation, but i guess it would be hard to detect batteries becoming low enough right in the middle of an operation...
Title: Re: 8X+ > flash writing question
Post by: Streetwalrus on July 06, 2014, 06:44:16 am
Yo Streety =]
Something between an OS and a shell...
That sounds interesting. You have my attention.
^ That. :P
Title: Re: 8X+ > flash writing question
Post by: the_mad_joob on August 22, 2014, 05:13:12 pm
It's me, again.
So, does anybody know how i am supposed to handle batteries becoming low in the middle of a writing operation ?
I mean, is it necessary to check them before every single write attempt ?
If yes, that would slow down large writings quite a lot...