Patchwork sparc32 fix carry flag handling (Solaris bootblk fix)

login
register
mail settings
Submitter Artyom Tarasenko
Date Nov. 3, 2009, 11:58 p.m.
Message ID <fb8d4f70911031558p6acadde8ubb372c4bc6ba82f4@mail.gmail.com>
Download mbox | patch
Permalink /patch/37540/
State New
Headers show

Comments

Artyom Tarasenko - Nov. 3, 2009, 11:58 p.m.
The page 108 of the SPARC Version 8 Architecture Manual describes
that addcc and addxcc shall compute carry flag the same way.
The page 110 claims the same about subcc and subxcc instructions.
This patch fixes carry computation in corner cases and removes redundant code.
The most visible effect of the patch is enabling Solaris boot when using OBP.

Signed-off-by: Artyom Tarasenko <atar4qemu@gmail.com>
---
     return ret;
 }

@@ -931,21 +935,6 @@ static inline uint32_t get_V_add_icc(target_ulong
dst, target_ulong src1,
     return ret;
 }

-static uint32_t compute_all_add(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_add_icc(CC_DST, CC_SRC);
-    ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_add(void)
-{
-    return get_C_add_icc(CC_DST, CC_SRC);
-}
-
 #ifdef TARGET_SPARC64
 static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong
src1)
 {
@@ -982,24 +971,19 @@ static uint32_t compute_C_add_xcc(void)
 }
 #endif

-static uint32_t compute_all_addx(void)
+static uint32_t compute_all_add(void)
 {
     uint32_t ret;

     ret = get_NZ_icc(CC_DST);
-    ret |= get_C_add_icc(CC_DST - CC_SRC2, CC_SRC);
-    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    ret |= get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
     ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
     return ret;
 }

-static uint32_t compute_C_addx(void)
+static uint32_t compute_C_add(void)
 {
-    uint32_t ret;
-
-    ret = get_C_add_icc(CC_DST - CC_SRC2, CC_SRC);
-    ret |= get_C_add_icc(CC_DST, CC_SRC);
-    return ret;
+    return get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
 }

 #ifdef TARGET_SPARC64
@@ -1038,7 +1022,7 @@ static uint32_t compute_all_tadd(void)
     uint32_t ret;

     ret = get_NZ_icc(CC_DST);
-    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    ret |= get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
     ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
     ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
     return ret;
@@ -1046,7 +1030,7 @@ static uint32_t compute_all_tadd(void)

 static uint32_t compute_C_tadd(void)
 {
-    return get_C_add_icc(CC_DST, CC_SRC);
+    return get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
 }

 static uint32_t compute_all_taddtv(void)
@@ -1054,21 +1038,25 @@ static uint32_t compute_all_taddtv(void)
     uint32_t ret;

     ret = get_NZ_icc(CC_DST);
-    ret |= get_C_add_icc(CC_DST, CC_SRC);
+    ret |= get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
     return ret;
 }

 static uint32_t compute_C_taddtv(void)
 {
-    return get_C_add_icc(CC_DST, CC_SRC);
+    return get_C_add_icc(CC_DST, CC_SRC, CC_SRC2);
 }

-static inline uint32_t get_C_sub_icc(target_ulong src1, target_ulong
src2)
+/* carry = (~src1[31] & src2[31]) | ( dst[31]  & (~src1[31] |
src2[31])) */
+static inline uint32_t get_C_sub_icc(target_ulong dst, target_ulong
src1,
+                                     target_ulong src2)
 {
     uint32_t ret = 0;

-    if ((src1 & 0xffffffffULL) < (src2 & 0xffffffffULL))
-        ret |= PSR_CARRY;
+    if((( ~(src1 & (1ULL << 31))) & (src2 & (1ULL << 31)))
+       | ((dst & (1ULL << 31)) & (( ~(src1 & (1ULL << 31)))
+                                         | (src2 & (1ULL << 31)))))
+       ret  |=PSR_CARRY;
     return ret;
 }

@@ -1082,20 +1070,6 @@ static inline uint32_t
get_V_sub_icc(target_ulong dst, target_ulong src1,
     return ret;
 }

-static uint32_t compute_all_sub(void)
-{
-    uint32_t ret;
-
-    ret = get_NZ_icc(CC_DST);
-    ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
-    ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
-    return ret;
-}
-
-static uint32_t compute_C_sub(void)
-{
-    return get_C_sub_icc(CC_SRC, CC_SRC2);
-}

 #ifdef TARGET_SPARC64
 static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong
src2)
@@ -1133,24 +1107,19 @@ static uint32_t compute_C_sub_xcc(void)
 }
 #endif

-static uint32_t compute_all_subx(void)
+static uint32_t compute_all_sub(void)
 {
     uint32_t ret;

     ret = get_NZ_icc(CC_DST);
-    ret |= get_C_sub_icc(CC_DST - CC_SRC2, CC_SRC);
-    ret |= get_C_sub_icc(CC_DST, CC_SRC2);
+    ret |= get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
     ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
     return ret;
 }

-static uint32_t compute_C_subx(void)
+static uint32_t compute_C_sub(void)
 {
-    uint32_t ret;
-
-    ret = get_C_sub_icc(CC_DST - CC_SRC2, CC_SRC);
-    ret |= get_C_sub_icc(CC_DST, CC_SRC2);
-    return ret;
+    return get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
 }

 #ifdef TARGET_SPARC64
@@ -1180,7 +1149,7 @@ static uint32_t compute_all_tsub(void)
     uint32_t ret;

     ret = get_NZ_icc(CC_DST);
-    ret |= get_C_sub_icc(CC_DST, CC_SRC);
+    ret |= get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
     ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
     ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
     return ret;
@@ -1188,7 +1157,7 @@ static uint32_t compute_all_tsub(void)

 static uint32_t compute_C_tsub(void)
 {
-    return get_C_sub_icc(CC_DST, CC_SRC);
+    return get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
 }

 static uint32_t compute_all_tsubtv(void)
@@ -1196,13 +1165,13 @@ static uint32_t compute_all_tsubtv(void)
     uint32_t ret;

     ret = get_NZ_icc(CC_DST);
-    ret |= get_C_sub_icc(CC_DST, CC_SRC);
+    ret |= get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
     return ret;
 }

 static uint32_t compute_C_tsubtv(void)
 {
-    return get_C_sub_icc(CC_DST, CC_SRC);
+    return get_C_sub_icc(CC_DST, CC_SRC, CC_SRC2);
 }

 static uint32_t compute_all_logic(void)
@@ -1232,11 +1201,11 @@ static const CCTable icc_table[CC_OP_NB] = {
     [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
     [CC_OP_DIV] = { compute_all_div, compute_C_div },
     [CC_OP_ADD] = { compute_all_add, compute_C_add },
-    [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
+    [CC_OP_ADDX] = { compute_all_add, compute_C_add },
     [CC_OP_TADD] = { compute_all_tadd, compute_C_tadd },
     [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_taddtv },
     [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
-    [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
+    [CC_OP_SUBX] = { compute_all_sub, compute_C_sub },
     [CC_OP_TSUB] = { compute_all_tsub, compute_C_tsub },
     [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_tsubtv },
     [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
Blue Swirl - Nov. 4, 2009, 7:44 p.m.
On Wed, Nov 4, 2009 at 1:58 AM, Artyom Tarasenko
<atar4qemu@googlemail.com> wrote:
> The page 108 of the SPARC Version 8 Architecture Manual describes
> that addcc and addxcc shall compute carry flag the same way.
> The page 110 claims the same about subcc and subxcc instructions.
> This patch fixes carry computation in corner cases and removes redundant code.
> The most visible effect of the patch is enabling Solaris boot when using OBP.

Thanks, applied.

Could you describe the steps how to boot Solaris with OBP? I'm sure
there are a lot of people who'd like to test if their favorite Sparc
Solaris programs work on QEMU.
Artyom Tarasenko - Nov. 5, 2009, 8:48 p.m.
2009/11/4 Blue Swirl <blauwirbel@gmail.com>:
> On Wed, Nov 4, 2009 at 1:58 AM, Artyom Tarasenko
> <atar4qemu@googlemail.com> wrote:
>> The page 108 of the SPARC Version 8 Architecture Manual describes
>> that addcc and addxcc shall compute carry flag the same way.
>> The page 110 claims the same about subcc and subxcc instructions.
>> This patch fixes carry computation in corner cases and removes redundant code.
>> The most visible effect of the patch is enabling Solaris boot when using OBP.
>
> Thanks, applied.
>
> Could you describe the steps how to boot Solaris with OBP? I'm sure
> there are a lot of people who'd like to test if their favorite Sparc
> Solaris programs work on QEMU.

Gonna do it, but need to clean up first. Currently it's still not
possible with vanilla qemu.
I have some more and less ugly hacks but not all of them are
necessary. Need to sort out which are still needed.

Artyom
Artyom Tarasenko - Nov. 13, 2009, 2:28 p.m.
>> Could you describe the steps how to boot Solaris with OBP? I'm sure
>> there are a lot of people who'd like to test if their favorite Sparc
>> Solaris programs work on QEMU.

Gathered things for which I currently have hacks here:
http://tyom.blogspot.com/2009/11/things-missing-in-vanilla-qemu.html

Actually for OBP itself it's just two (SS-5) or three (SS-20) things:

- Floppy. Instead of fixing it, I broke it completely, so OBP doesn't
try to initialize it and hang. Actually it maybe not the fdc itself,
but the irq handling. There are OBP tests which may help to understand
what is currently going wrong. I didn't need it, does the fdc actually
work under linux/netbsd/OpenBIOS?

- [SparcStation-5] 0x6e000000 AFX. OBP tries to access it and fails
with "unassigned address exception". Is only present in the SS-5's
TCX. The required address space is just one byte long. IMHO makes no
sense to create a special stub device for it. Can we push it into the
TCX?
- [SparcStation-20] 0xef8010000 DBRI, 0x9000X00X FCode SIMMs.
"unassigned address exception".

AFX, DBRI and FCode SIMMs can be implemented as stubs. Yet better
would be if SBUS probing would do a proper fault. This devices seem to
be optional.
Blue Swirl - Nov. 13, 2009, 9:01 p.m.
On Fri, Nov 13, 2009 at 4:28 PM, Artyom Tarasenko
<atar4qemu@googlemail.com> wrote:
>>> Could you describe the steps how to boot Solaris with OBP? I'm sure
>>> there are a lot of people who'd like to test if their favorite Sparc
>>> Solaris programs work on QEMU.
>
> Gathered things for which I currently have hacks here:
> http://tyom.blogspot.com/2009/11/things-missing-in-vanilla-qemu.html
>
> Actually for OBP itself it's just two (SS-5) or three (SS-20) things:
>
> - Floppy. Instead of fixing it, I broke it completely, so OBP doesn't
> try to initialize it and hang. Actually it maybe not the fdc itself,
> but the irq handling. There are OBP tests which may help to understand
> what is currently going wrong. I didn't need it, does the fdc actually
> work under linux/netbsd/OpenBIOS?

Not at least Linux, IIRC Linux floppy driver is broken. FDC is wired a
bit differently from PC setup. We don't need it, but getting OBP just
to accept it would be nice.

> - [SparcStation-5] 0x6e000000 AFX. OBP tries to access it and fails
> with "unassigned address exception". Is only present in the SS-5's
> TCX. The required address space is just one byte long. IMHO makes no
> sense to create a special stub device for it. Can we push it into the
> TCX?

I'd put it to sun4m.c, there is similar device (idreg) already.

> - [SparcStation-20] 0xef8010000 DBRI, 0x9000X00X FCode SIMMs.
> "unassigned address exception".
>
> AFX, DBRI and FCode SIMMs can be implemented as stubs. Yet better
> would be if SBUS probing would do a proper fault. This devices seem to
> be optional.
>

DBRI audio could be useful, even though cs4231 does not work.
Artyom Tarasenko - Dec. 10, 2009, 6:27 p.m.
2009/11/13 Blue Swirl <blauwirbel@gmail.com>:
> On Fri, Nov 13, 2009 at 4:28 PM, Artyom Tarasenko
> <atar4qemu@googlemail.com> wrote:
>>>> Could you describe the steps how to boot Solaris with OBP? I'm sure
>>>> there are a lot of people who'd like to test if their favorite Sparc
>>>> Solaris programs work on QEMU.
>>
>> Gathered things for which I currently have hacks here:
>> http://tyom.blogspot.com/2009/11/things-missing-in-vanilla-qemu.html
>>
>> Actually for OBP itself it's just two (SS-5) or three (SS-20) things:
>>
>> - Floppy. Instead of fixing it, I broke it completely, so OBP doesn't
>> try to initialize it and hang. Actually it maybe not the fdc itself,
>> but the irq handling. There are OBP tests which may help to understand
>> what is currently going wrong. I didn't need it, does the fdc actually
>> work under linux/netbsd/OpenBIOS?
>
> Not at least Linux, IIRC Linux floppy driver is broken. FDC is wired a
> bit differently from PC setup. We don't need it, but getting OBP just
> to accept it would be nice.
>
>> - [SparcStation-5] 0x6e000000 AFX. OBP tries to access it and fails
>> with "unassigned address exception". Is only present in the SS-5's
>> TCX. The required address space is just one byte long. IMHO makes no
>> sense to create a special stub device for it. Can we push it into the
>> TCX?
>
> I'd put it to sun4m.c, there is similar device (idreg) already.

Ok, I made one patch for fdc.c (it turned out that for SS5-only fix, a
very small change is needed), and a small afx patch for sun4m.c .
Shall I post them marked "for 0.12" or shall we do it in 0.13 ?
Blue Swirl - Dec. 12, 2009, 9:07 a.m.
On Thu, Dec 10, 2009 at 8:27 PM, Artyom Tarasenko
<atar4qemu@googlemail.com> wrote:
> 2009/11/13 Blue Swirl <blauwirbel@gmail.com>:
>> On Fri, Nov 13, 2009 at 4:28 PM, Artyom Tarasenko
>> <atar4qemu@googlemail.com> wrote:
>>>>> Could you describe the steps how to boot Solaris with OBP? I'm sure
>>>>> there are a lot of people who'd like to test if their favorite Sparc
>>>>> Solaris programs work on QEMU.
>>>
>>> Gathered things for which I currently have hacks here:
>>> http://tyom.blogspot.com/2009/11/things-missing-in-vanilla-qemu.html
>>>
>>> Actually for OBP itself it's just two (SS-5) or three (SS-20) things:
>>>
>>> - Floppy. Instead of fixing it, I broke it completely, so OBP doesn't
>>> try to initialize it and hang. Actually it maybe not the fdc itself,
>>> but the irq handling. There are OBP tests which may help to understand
>>> what is currently going wrong. I didn't need it, does the fdc actually
>>> work under linux/netbsd/OpenBIOS?
>>
>> Not at least Linux, IIRC Linux floppy driver is broken. FDC is wired a
>> bit differently from PC setup. We don't need it, but getting OBP just
>> to accept it would be nice.
>>
>>> - [SparcStation-5] 0x6e000000 AFX. OBP tries to access it and fails
>>> with "unassigned address exception". Is only present in the SS-5's
>>> TCX. The required address space is just one byte long. IMHO makes no
>>> sense to create a special stub device for it. Can we push it into the
>>> TCX?
>>
>> I'd put it to sun4m.c, there is similar device (idreg) already.
>
> Ok, I made one patch for fdc.c (it turned out that for SS5-only fix, a
> very small change is needed), and a small afx patch for sun4m.c .
> Shall I post them marked "for 0.12" or shall we do it in 0.13 ?

Depends on the patches.
Artyom Tarasenko - Dec. 16, 2009, 4:41 p.m.
2009/11/4 Blue Swirl <blauwirbel@gmail.com>:
> On Wed, Nov 4, 2009 at 1:58 AM, Artyom Tarasenko
> <atar4qemu@googlemail.com> wrote:
>> The page 108 of the SPARC Version 8 Architecture Manual describes
>> that addcc and addxcc shall compute carry flag the same way.
>> The page 110 claims the same about subcc and subxcc instructions.
>> This patch fixes carry computation in corner cases and removes redundant code.
>> The most visible effect of the patch is enabling Solaris boot when using OBP.
>
> Thanks, applied.
>
> Could you describe the steps how to boot Solaris with OBP? I'm sure
> there are a lot of people who'd like to test if their favorite Sparc
> Solaris programs work on QEMU.

I gathered a little how-to here:
http://tyom.blogspot.com/2009/12/solaris-under-qemu-how-to.html

If the patches will made it into 0.12, I think it's worth to mention
OBP and kadb boot support as a new feature. What do you think?

Actually the shell-boot is also pretty close. We just need to fix the
NF-bit handling in MMU. I'm experimenting with a real SS-20 to
understand how it is supposed to work. (the MCC manual doesn't
describe it clear enough, as you have pointed out before).

Patch

diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index a1ada8b..818c5f5 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -912,12 +912,16 @@  static uint32_t compute_C_div(void)
     return 0;
 }

-static inline uint32_t get_C_add_icc(target_ulong dst, target_ulong
src1)
+/* carry = (src1[31] & src2[31]) | ( ~dst[31] & (src1[31] |
src2[31])) */
+static inline uint32_t get_C_add_icc(target_ulong dst, target_ulong
src1,
+                                     target_ulong src2)
 {
     uint32_t ret = 0;

-    if ((dst & 0xffffffffULL) < (src1 & 0xffffffffULL))
-        ret |= PSR_CARRY;
+    if (((src1 & (1ULL << 31)) & (src2 & (1ULL << 31)))
+        | ((~(dst & (1ULL << 31)))
+           & ((src1 & (1ULL << 31)) | (src2 & (1ULL << 31)))) )
+        ret  |=PSR_CARRY;