The PowerPC timebase register is made available to forth using the tbu@ and tbl@ words. The tbu@ word pushes the upper 32 bits of this register. The tbl@ word pushes the lower 32 bits of this register.
Signed-off-by: John Arbuckle programmingkidx@gmail.com --- arch/ppc/qemu/init.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index 5ce080c..d12084c 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -751,6 +751,22 @@ static void adler32(void) RET(s2 << 16 | s1); }
+/* reads the upper timebase register ( -- tbu ) */ +static void get_tbu(void) +{ + int time; + asm volatile("mftbu %0" : "=r"(time)); // load from TBU register + PUSH(time); +} + +/* reads the lower timebase register ( -- tbl ) */ +static void get_tbl(void) +{ + int time; + asm volatile("mftb %0" : "=r"(time)); // load from TBL register + PUSH(time); +} + void arch_of_init(void) { @@ -1022,4 +1038,8 @@ arch_of_init(void)
bind_func("platform-boot", boot); bind_func("(arch-go)", arch_go); + + /* Makes the timebase register accessible from forth */ + bind_func("tbu@", get_tbu); + bind_func("tbl@", get_tbl); }
On Wed, Dec 27, 2017 at 01:35:46PM -0500, John Arbuckle wrote:
+/* reads the lower timebase register ( -- tbl ) */ +static void get_tbl(void) +{
- int time;
- asm volatile("mftb %0" : "=r"(time)); // load from TBL register
- PUSH(time);
+}
This doesn't get TBL: on 64-bit implementations it gets all of TB. You'll have to mask out the high half if you want to get just TBL. Or, you could just use mftb (mfspr 268) on 64-bit systems, instead of the TBU dance that you need on 32-bit systems.
Segher
On Dec 27, 2017, at 1:48 PM, Segher Boessenkool segher@kernel.crashing.org wrote:
On Wed, Dec 27, 2017 at 01:35:46PM -0500, John Arbuckle wrote:
+/* reads the lower timebase register ( -- tbl ) */ +static void get_tbl(void) +{
- int time;
- asm volatile("mftb %0" : "=r"(time)); // load from TBL register
- PUSH(time);
+}
This doesn't get TBL: on 64-bit implementations it gets all of TB. You'll have to mask out the high half if you want to get just TBL. Or, you could just use mftb (mfspr 268) on 64-bit systems, instead of the TBU dance that you need on 32-bit systems.
Segher
I wasn't aware that OpenBIOS supported 64-bit PowerPC. What if I change the type of the time variable to uint32_t. This type can only hold a 32-bit value, would the following code work on 64-bit PowerPC?
/* reads the lower timebase register ( -- tbl ) */ static void get_tbl(void) { uint32_t time; asm volatile("mftb %0" : "=r"(time)); // load from TBL register PUSH(time); }
Also how would I test 64-bit PowerPC code in QEMU? If you could send the command-line needed that would help.
On Wed, 27 Dec 2017, Programmingkid wrote:
On Dec 27, 2017, at 1:48 PM, Segher Boessenkool segher@kernel.crashing.org wrote:
On Wed, Dec 27, 2017 at 01:35:46PM -0500, John Arbuckle wrote:
+/* reads the lower timebase register ( -- tbl ) */ +static void get_tbl(void) +{
- int time;
- asm volatile("mftb %0" : "=r"(time)); // load from TBL register
- PUSH(time);
+}
This doesn't get TBL: on 64-bit implementations it gets all of TB. You'll have to mask out the high half if you want to get just TBL. Or, you could just use mftb (mfspr 268) on 64-bit systems, instead of the TBU dance that you need on 32-bit systems.
Segher
I wasn't aware that OpenBIOS supported 64-bit PowerPC. What if I change the type of the time variable to uint32_t. This type can only hold a 32-bit value, would the following code work on 64-bit PowerPC?
I don't know if it works (depends on the compiler implementation) but it looks safer to explicitely mask the unneded bits in a new line between the asm and PUSH.
/* reads the lower timebase register ( -- tbl ) */ static void get_tbl(void) { uint32_t time; asm volatile("mftb %0" : "=r"(time)); // load from TBL register PUSH(time); }
Also how would I test 64-bit PowerPC code in QEMU? If you could send the command-line needed that would help.
Look in openbios/include/arch/ppc/processor.h (and this is probably a better place for these kind of helpers than qemu/init.c as these are PPC specific not QEMU specific). However then you'd also need a way in Forth to detect 64bit. Elsewhere in ppc/qemu CONFIG_PPC64 also seems to be used and you may be able to test this in Forth, I've seen lines like:
[IFDEF] CONFIG_PPC64 " yes" [ELSE] " no" [THEN]
but not sure if this works. It seems to be cleaner to implement the tb@ function in C that returns the whole TB value instead of tbl@ and tbu@ and export that to Forth so you don't need to handle arch differences such as 64bit in Forth.
Regards, BALATON Zoltan
On Dec 27, 2017, at 4:27 PM, BALATON Zoltan balaton@eik.bme.hu wrote:
On Wed, 27 Dec 2017, Programmingkid wrote:
On Dec 27, 2017, at 1:48 PM, Segher Boessenkool segher@kernel.crashing.org wrote:
On Wed, Dec 27, 2017 at 01:35:46PM -0500, John Arbuckle wrote:
+/* reads the lower timebase register ( -- tbl ) */ +static void get_tbl(void) +{
- int time;
- asm volatile("mftb %0" : "=r"(time)); // load from TBL register
- PUSH(time);
+}
This doesn't get TBL: on 64-bit implementations it gets all of TB. You'll have to mask out the high half if you want to get just TBL. Or, you could just use mftb (mfspr 268) on 64-bit systems, instead of the TBU dance that you need on 32-bit systems.
Segher
I wasn't aware that OpenBIOS supported 64-bit PowerPC. What if I change the type of the time variable to uint32_t. This type can only hold a 32-bit value, would the following code work on 64-bit PowerPC?
I don't know if it works (depends on the compiler implementation) but it looks safer to explicitely mask the unneded bits in a new line between the asm and PUSH.
/* reads the lower timebase register ( -- tbl ) */ static void get_tbl(void) { uint32_t time; asm volatile("mftb %0" : "=r"(time)); // load from TBL register PUSH(time); }
Also how would I test 64-bit PowerPC code in QEMU? If you could send the command-line needed that would help.
Look in openbios/include/arch/ppc/processor.h (and this is probably a better place for these kind of helpers than qemu/init.c as these are PPC specific not QEMU specific). However then you'd also need a way in Forth to detect 64bit. Elsewhere in ppc/qemu CONFIG_PPC64 also seems to be used and you may be able to test this in Forth, I've seen lines like:
[IFDEF] CONFIG_PPC64 " yes" [ELSE] " no" [THEN]
but not sure if this works. It seems to be cleaner to implement the tb@ function in C that returns the whole TB value instead of tbl@ and tbu@ and export that to Forth so you don't need to handle arch differences such as 64bit in Forth.
Regards, BALATON Zoltan
Ok I think this is what you want:
/* reads the lower timebase register ( -- tbl ) */ static void get_tbl(void) { uint32_t time; asm volatile("mftb %0" : "=r"(time)); // load from TBL register time = time & 0xffffffff; // Ensures the value is only 32-bit PUSH(time); }
I've tried to implement it the way I've suggested and came up with the patch below, but it does not seem to work. I think this is because the arithmetic in get-msec overflows and does not get the right values. Could it be it works in SLOF because that runs on 64bit? Or is something needed to tell Forth to use 64bit values on PPC32? Any ideas?
Regards, BALATON Zoltan
diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index b0c0cfc..4c8631a 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -793,6 +793,20 @@ static void adler32(void) RET(s2 << 16 | s1); }
+/* + * Get time base value from CPU + */ +static void tb_fetch(void) +{ + unsigned long tbl, tbu; + + do { + tbu = mftbu(); + tbl = mftb(); + } while (tbu != mftbu()); + DPUSH(((uint64_t)tbu << 32) | tbl); +} + void arch_of_init(void) { @@ -1062,7 +1076,9 @@ arch_of_init(void)
/* Implementation of adler32 word (required by OS 9, BootX) */ bind_func("(adler32)", adler32); - + + fword("fixup-tbfreq"); + bind_func("(tb@)", tb_fetch); bind_func("platform-boot", boot); bind_func("(arch-go)", arch_go); } diff --git a/arch/ppc/qemu/qemu.fs b/arch/ppc/qemu/qemu.fs index d683421..1e3e0cb 100644 --- a/arch/ppc/qemu/qemu.fs +++ b/arch/ppc/qemu/qemu.fs @@ -139,3 +139,34 @@ variable keyboard-phandle 0 keyboard-phandle ! 3drop 0 then ; + +\ ------------------------------------------------------------------------- +\ time base related words +\ ------------------------------------------------------------------------- + +1 value tb-frequency + +: fixup-tbfreq + " /cpus/@0" find-device + " timebase-frequency" active-package get-package-property IF + 2drop + ELSE + decode-int to tb-frequency 2drop + THEN + device-end +; + +: tb@ ( -- tbval) + " (tb@)" $find if + execute + 20 lshift swap ffffffff and or + else + 2drop 0 + then +; + +: get-msecs ( -- ms ) tb@ d# 1000 * tb-frequency / ; +: get-usecs ( -- us ) tb@ d# 1000000 * tb-frequency / ; + +: ms ( ms-to-wait -- ) get-msecs + BEGIN get-msecs over >= UNTIL drop ; +: us ( us-to-wait -- ) get-usecs + BEGIN get-usecs over >= UNTIL drop ; diff --git a/include/arch/ppc/processor.h b/include/arch/ppc/processor.h index bb03bb1..5e79ba8 100644 --- a/include/arch/ppc/processor.h +++ b/include/arch/ppc/processor.h @@ -462,6 +462,20 @@ static inline void slbmte(unsigned long rs, unsigned long rb) asm volatile("slbmte %0,%1 ; isync" :: "r" (rs), "r" (rb) : "memory"); }
+static inline unsigned long mftb(void) +{ + unsigned long val; + asm volatile("mftb %0" : "=r" (val)); + return val; +} + +static inline unsigned long mftbu(void) +{ + unsigned long val; + asm volatile("mftbu %0" : "=r" (val)); + return val; +} + #endif /* !__ASSEMBLER__ */
#endif /* _H_PROCESSOR */
On Dec 29, 2017, at 8:01 PM, BALATON Zoltan balaton@eik.bme.hu wrote:
I've tried to implement it the way I've suggested and came up with the patch below, but it does not seem to work. I think this is because the arithmetic in get-msec overflows and does not get the right values. Could it be it works in SLOF because that runs on 64bit? Or is something needed to tell Forth to use 64bit values on PPC32? Any ideas?
Regards, BALATON Zoltan
diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index b0c0cfc..4c8631a 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -793,6 +793,20 @@ static void adler32(void) RET(s2 << 16 | s1); }
+/*
- Get time base value from CPU
- */
+static void tb_fetch(void) +{
- unsigned long tbl, tbu;
I would change "unsigned long" to uint32_t.
- do {
tbu = mftbu();
tbl = mftb();
- } while (tbu != mftbu());
- DPUSH(((uint64_t)tbu << 32) | tbl);
I suspect this line is the problem. I had a lot of problems trying to do this exact bit operation. I gave up on it and instead did it another way. That patch was sent to the list.
+}
void arch_of_init(void) { @@ -1062,7 +1076,9 @@ arch_of_init(void)
/* Implementation of adler32 word (required by OS 9, BootX) */ bind_func("(adler32)", adler32);
- fword("fixup-tbfreq");
- bind_func("(tb@)", tb_fetch); bind_func("platform-boot", boot); bind_func("(arch-go)", arch_go);
} diff --git a/arch/ppc/qemu/qemu.fs b/arch/ppc/qemu/qemu.fs index d683421..1e3e0cb 100644 --- a/arch/ppc/qemu/qemu.fs +++ b/arch/ppc/qemu/qemu.fs @@ -139,3 +139,34 @@ variable keyboard-phandle 0 keyboard-phandle ! 3drop 0 then ;
+\ ------------------------------------------------------------------------- +\ time base related words +\ -------------------------------------------------------------------------
+1 value tb-frequency
+: fixup-tbfreq
- " /cpus/@0" find-device
- " timebase-frequency" active-package get-package-property IF
- 2drop
- ELSE
- decode-int to tb-frequency 2drop
- THEN
- device-end
+;
+: tb@ ( -- tbval)
- " (tb@)" $find if
- execute
- 20 lshift swap ffffffff and or
- else
- 2drop 0
- then
+;
+: get-msecs ( -- ms ) tb@ d# 1000 * tb-frequency / ; +: get-usecs ( -- us ) tb@ d# 1000000 * tb-frequency / ;
+: ms ( ms-to-wait -- ) get-msecs + BEGIN get-msecs over >= UNTIL drop ; +: us ( us-to-wait -- ) get-usecs + BEGIN get-usecs over >= UNTIL drop ; diff --git a/include/arch/ppc/processor.h b/include/arch/ppc/processor.h index bb03bb1..5e79ba8 100644 --- a/include/arch/ppc/processor.h +++ b/include/arch/ppc/processor.h @@ -462,6 +462,20 @@ static inline void slbmte(unsigned long rs, unsigned long rb) asm volatile("slbmte %0,%1 ; isync" :: "r" (rs), "r" (rb) : "memory"); }
I would replace all the "unsigned long" with uint32_t here.
+static inline unsigned long mftb(void) +{
- unsigned long val;
- asm volatile("mftb %0" : "=r" (val));
- return val;
+}
+static inline unsigned long mftbu(void) +{
- unsigned long val;
- asm volatile("mftbu %0" : "=r" (val));
- return val;
+}
#endif /* !__ASSEMBLER__ */
#endif /* _H_PROCESSOR */
On Dec 29, 2017, at 8:01 PM, BALATON Zoltan balaton@eik.bme.hu wrote:
I've tried to implement it the way I've suggested and came up with the patch below, but it does not seem to work. I think this is because the arithmetic in get-msec overflows and does not get the right values. Could it be it works in SLOF because that runs on 64bit? Or is something needed to tell Forth to use 64bit values on PPC32? Any ideas?
I continuously printed the tb@ word's value by using this program:
decimal begin tb@ . . cr again
The tbu value looks right. The tbl value is a problem. When it prints it sometimes prints as a negative value. We need a way to print the value as unsigned. I switch over to the monitor and type this command "info registers" to see the timebase registers value to verify their values. Only the tbu value looks right.
I also made this test program:
#include <stdio.h> #include <inttypes.h>
int main(int argc, const char * argv[]) {
uint64_t tbu, tbl; tbl = 4000000000; tbu = 1; printf("tbl = %" PRId64 "\n", tbl); printf("or'ed value: %" PRId64 "\n", (uint64_t)((tbu << 32) | tbl)); // should be 8,294,967,296
return 0; }
When I change the uint64_t type to uint32_t at the declaration of the variables, the printed value is wrong. So this is why I think switching over to uint64_t might help.
Hope this info helps.
On Fri, Dec 29, 2017 at 10:30:17PM -0500, Programmingkid wrote:
On Dec 29, 2017, at 8:01 PM, BALATON Zoltan balaton@eik.bme.hu wrote:
I've tried to implement it the way I've suggested and came up with the patch below, but it does not seem to work. I think this is because the arithmetic in get-msec overflows and does not get the right values. Could it be it works in SLOF because that runs on 64bit? Or is something needed to tell Forth to use 64bit values on PPC32? Any ideas?
I continuously printed the tb@ word's value by using this program:
decimal begin tb@ . . cr again
The tbu value looks right. The tbl value is a problem. When it prints it sometimes prints as a negative value.
You should use U. .
printf("or'ed value: %" PRId64 "\n", (uint64_t)((tbu << 32) | tbl)); // should be 8,294,967,296
And that should be (uint64_t)tbu << 32 (note where the cast is done).
Segher
On Dec 30, 2017, at 6:18 AM, Segher Boessenkool segher@kernel.crashing.org wrote:
On Fri, Dec 29, 2017 at 10:30:17PM -0500, Programmingkid wrote:
On Dec 29, 2017, at 8:01 PM, BALATON Zoltan balaton@eik.bme.hu wrote:
I've tried to implement it the way I've suggested and came up with the patch below, but it does not seem to work. I think this is because the arithmetic in get-msec overflows and does not get the right values. Could it be it works in SLOF because that runs on 64bit? Or is something needed to tell Forth to use 64bit values on PPC32? Any ideas?
I continuously printed the tb@ word's value by using this program:
decimal begin tb@ . . cr again
The tbu value looks right. The tbl value is a problem. When it prints it sometimes prints as a negative value.
You should use U. .
printf("or'ed value: %" PRId64 "\n", (uint64_t)((tbu << 32) | tbl)); // should be 8,294,967,296
And that should be (uint64_t)tbu << 32 (note where the cast is done).
Segher
Maybe not on topic, but 1000 ms and 1000000 us, return the correct time on SLOF.
I would think this is related to having the correct timebase, but maybe I misunderstand how these things work.
On Sat, Dec 30, 2017 at 02:01:41AM +0100, BALATON Zoltan wrote:
I've tried to implement it the way I've suggested and came up with the patch below, but it does not seem to work. I think this is because the arithmetic in get-msec overflows and does not get the right values. Could it be it works in SLOF because that runs on 64bit? Or is something needed to tell Forth to use 64bit values on PPC32? Any ideas?
+static void tb_fetch(void) +{
- unsigned long tbl, tbu;
- do {
tbu = mftbu();
tbl = mftb();
- } while (tbu != mftbu());
- DPUSH(((uint64_t)tbu << 32) | tbl);
+}
Whether the code here is correct or not, it is simpler to just write it as
PUSH(tbl); PUSH(tbu);
Segher
On Dec 27, 2017, at 1:35 PM, John Arbuckle programmingkidx@gmail.com wrote:
The PowerPC timebase register is made available to forth using the tbu@ and tbl@ words. The tbu@ word pushes the upper 32 bits of this register. The tbl@ word pushes the lower 32 bits of this register.
Signed-off-by: John Arbuckle programmingkidx@gmail.com
arch/ppc/qemu/init.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index 5ce080c..d12084c 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -751,6 +751,22 @@ static void adler32(void) RET(s2 << 16 | s1); }
+/* reads the upper timebase register ( -- tbu ) */ +static void get_tbu(void) +{
- int time;
- asm volatile("mftbu %0" : "=r"(time)); // load from TBU register
- PUSH(time);
+}
+/* reads the lower timebase register ( -- tbl ) */ +static void get_tbl(void) +{
- int time;
- asm volatile("mftb %0" : "=r"(time)); // load from TBL register
- PUSH(time);
+}
void arch_of_init(void) { @@ -1022,4 +1038,8 @@ arch_of_init(void)
bind_func("platform-boot", boot); bind_func("(arch-go)", arch_go);
- /* Makes the timebase register accessible from forth */
- bind_func("tbu@", get_tbu);
- bind_func("tbl@", get_tbl);
}
2.14.3 (Apple Git-98)
-- OpenBIOS http://openbios.org/ Mailinglist: http://lists.openbios.org/mailman/listinfo Free your System - May the Forth be with you
Ok, dumb question, how do I pull and apply this patch?
On Dec 28, 2017, at 2:51 AM, Jd Lyons lyons_dj@yahoo.com wrote:
On Dec 27, 2017, at 1:35 PM, John Arbuckle programmingkidx@gmail.com wrote:
The PowerPC timebase register is made available to forth using the tbu@ and tbl@ words. The tbu@ word pushes the upper 32 bits of this register. The tbl@ word pushes the lower 32 bits of this register.
Signed-off-by: John Arbuckle programmingkidx@gmail.com
arch/ppc/qemu/init.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index 5ce080c..d12084c 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -751,6 +751,22 @@ static void adler32(void) RET(s2 << 16 | s1); }
+/* reads the upper timebase register ( -- tbu ) */ +static void get_tbu(void) +{
- int time;
- asm volatile("mftbu %0" : "=r"(time)); // load from TBU register
- PUSH(time);
+}
+/* reads the lower timebase register ( -- tbl ) */ +static void get_tbl(void) +{
- int time;
- asm volatile("mftb %0" : "=r"(time)); // load from TBL register
- PUSH(time);
+}
void arch_of_init(void) { @@ -1022,4 +1038,8 @@ arch_of_init(void)
bind_func("platform-boot", boot); bind_func("(arch-go)", arch_go);
- /* Makes the timebase register accessible from forth */
- bind_func("tbu@", get_tbu);
- bind_func("tbl@", get_tbl);
}
2.14.3 (Apple Git-98)
-- OpenBIOS http://openbios.org/ Mailinglist: http://lists.openbios.org/mailman/listinfo Free your System - May the Forth be with you
Ok, dumb question, how do I pull and apply this patch?
I would save the patch email to disk. Then use this command from inside the OpenBIOS folder: patch -p0 <path>/tb.patch
On Thu, Dec 28, 2017 at 02:51:20AM -0500, Jd Lyons wrote:
Ok, dumb question, how do I pull and apply this patch?
Save the email to a file, and then
git am that-file
and that is all :-)
Segher