Message ID | 161700376169.1135890.8707223959310729949.stgit@pasha-ThinkPad-X280 (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | target/openrisc: fix icount handling for timer instructions | expand |
Hi Pavel, Thanks for the patch. On Mon, Mar 29, 2021 at 10:42:41AM +0300, Pavel Dovgalyuk wrote: > This patch adds icount handling to mfspr/mtspr instructions > that may deal with hardware timers. > > Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru> > --- > target/openrisc/translate.c | 15 +++++++++++++++ > 1 file changed, 15 insertions(+) > > diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c > index c6dce879f1..a9c81f8bd5 100644 > --- a/target/openrisc/translate.c > +++ b/target/openrisc/translate.c > @@ -884,6 +884,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) > gen_illegal_exception(dc); > } else { > TCGv spr = tcg_temp_new(); > + > + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { > + gen_io_start(); > + if (dc->delayed_branch) { > + tcg_gen_mov_tl(cpu_pc, jmp_pc); > + tcg_gen_discard_tl(jmp_pc); > + } else { > + tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); > + } > + dc->base.is_jmp = DISAS_EXIT; > + } I don't know alot about how the icount works. But I read this document to help understand this patch. https://qemu.readthedocs.io/en/latest/devel/tcg-icount.html Could you explain why we need to exit the tb on mfspr? This may just be reading a timer value, but I am not sure why we need it? > tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); > gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); > tcg_temp_free(spr); > @@ -898,6 +910,9 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) > } else { > TCGv spr; > > + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { > + gen_io_start(); > + } Here and above, why do we need to call gen_io_start()? This seems to need to be called before io operations. This may all be OK, but could you help explain the theory of operation? Also, have you tested this? -Stafford
On 31.03.2021 01:05, Stafford Horne wrote: > Hi Pavel, > > Thanks for the patch. > > On Mon, Mar 29, 2021 at 10:42:41AM +0300, Pavel Dovgalyuk wrote: >> This patch adds icount handling to mfspr/mtspr instructions >> that may deal with hardware timers. >> >> Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru> >> --- >> target/openrisc/translate.c | 15 +++++++++++++++ >> 1 file changed, 15 insertions(+) >> >> diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c >> index c6dce879f1..a9c81f8bd5 100644 >> --- a/target/openrisc/translate.c >> +++ b/target/openrisc/translate.c >> @@ -884,6 +884,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) >> gen_illegal_exception(dc); >> } else { >> TCGv spr = tcg_temp_new(); >> + >> + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { >> + gen_io_start(); >> + if (dc->delayed_branch) { >> + tcg_gen_mov_tl(cpu_pc, jmp_pc); >> + tcg_gen_discard_tl(jmp_pc); >> + } else { >> + tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); >> + } >> + dc->base.is_jmp = DISAS_EXIT; >> + } > > I don't know alot about how the icount works. But I read this document to help > understand this patch. > > https://qemu.readthedocs.io/en/latest/devel/tcg-icount.html > > Could you explain why we need to exit the tb on mfspr? This may just be reading > a timer value, but I am not sure why we need it? Because virtual clock in icount mode is correct only at the end of the block. Allowing virtual clock reads in other places will make execution non-deterministic, because icount is updated to the value, which it gets after the block ends. > >> tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); >> gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); >> tcg_temp_free(spr); >> @@ -898,6 +910,9 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) >> } else { >> TCGv spr; >> >> + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { >> + gen_io_start(); >> + } > > Here and above, why do we need to call gen_io_start()? This seems to need to be > called before io operations. gen_io_start allows reading icount for the instruction. It is needed to prevent invalid reads in the middle of the block. > > This may all be OK, but could you help explain the theory of operation? Also, > have you tested this? I have record/replay tests for openrisc, but I can't submit them without this patch, because they will fail. Pavel Dovgalyuk
On Wed, Mar 31, 2021 at 10:27:21AM +0300, Pavel Dovgalyuk wrote: > On 31.03.2021 01:05, Stafford Horne wrote: > > Hi Pavel, > > > > Thanks for the patch. > > > > On Mon, Mar 29, 2021 at 10:42:41AM +0300, Pavel Dovgalyuk wrote: > > > This patch adds icount handling to mfspr/mtspr instructions > > > that may deal with hardware timers. > > > > > > Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru> > > > --- > > > target/openrisc/translate.c | 15 +++++++++++++++ > > > 1 file changed, 15 insertions(+) > > > > > > diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c > > > index c6dce879f1..a9c81f8bd5 100644 > > > --- a/target/openrisc/translate.c > > > +++ b/target/openrisc/translate.c > > > @@ -884,6 +884,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) > > > gen_illegal_exception(dc); > > > } else { > > > TCGv spr = tcg_temp_new(); > > > + > > > + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { > > > + gen_io_start(); > > > + if (dc->delayed_branch) { > > > + tcg_gen_mov_tl(cpu_pc, jmp_pc); > > > + tcg_gen_discard_tl(jmp_pc); > > > + } else { > > > + tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); > > > + } > > > + dc->base.is_jmp = DISAS_EXIT; > > > + } > > > > I don't know alot about how the icount works. But I read this document to help > > understand this patch. > > > > https://qemu.readthedocs.io/en/latest/devel/tcg-icount.html > > > > Could you explain why we need to exit the tb on mfspr? This may just be reading > > a timer value, but I am not sure why we need it? > > Because virtual clock in icount mode is correct only at the end of the > block. > Allowing virtual clock reads in other places will make execution > non-deterministic, because icount is updated to the value, which it gets > after the block ends. OK, got it. > > > > > tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); > > > gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); > > > tcg_temp_free(spr); > > > @@ -898,6 +910,9 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) > > > } else { > > > TCGv spr; > > > + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { > > > + gen_io_start(); > > > + } > > > > Here and above, why do we need to call gen_io_start()? This seems to need to be > > called before io operations. > > gen_io_start allows reading icount for the instruction. > It is needed to prevent invalid reads in the middle of the block. > > > > > This may all be OK, but could you help explain the theory of operation? Also, > > have you tested this? > > I have record/replay tests for openrisc, but I can't submit them without > this patch, because they will fail. OK. Acked-by: Stafford Horne <shorne@gmail.com> I am not currently maintaining an openrisc queue, but I could start one. Do you have another way to submit this upstream? -Stafford
CC'ed Paolo. On 31.03.2021 15:33, Stafford Horne wrote: > On Wed, Mar 31, 2021 at 10:27:21AM +0300, Pavel Dovgalyuk wrote: >> On 31.03.2021 01:05, Stafford Horne wrote: >>> Hi Pavel, >>> >>> Thanks for the patch. >>> >>> On Mon, Mar 29, 2021 at 10:42:41AM +0300, Pavel Dovgalyuk wrote: >>>> This patch adds icount handling to mfspr/mtspr instructions >>>> that may deal with hardware timers. >>>> >>>> Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru> >>>> --- >>>> target/openrisc/translate.c | 15 +++++++++++++++ >>>> 1 file changed, 15 insertions(+) >>>> >>>> diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c >>>> index c6dce879f1..a9c81f8bd5 100644 >>>> --- a/target/openrisc/translate.c >>>> +++ b/target/openrisc/translate.c >>>> @@ -884,6 +884,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) >>>> gen_illegal_exception(dc); >>>> } else { >>>> TCGv spr = tcg_temp_new(); >>>> + >>>> + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { >>>> + gen_io_start(); >>>> + if (dc->delayed_branch) { >>>> + tcg_gen_mov_tl(cpu_pc, jmp_pc); >>>> + tcg_gen_discard_tl(jmp_pc); >>>> + } else { >>>> + tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); >>>> + } >>>> + dc->base.is_jmp = DISAS_EXIT; >>>> + } >>> >>> I don't know alot about how the icount works. But I read this document to help >>> understand this patch. >>> >>> https://qemu.readthedocs.io/en/latest/devel/tcg-icount.html >>> >>> Could you explain why we need to exit the tb on mfspr? This may just be reading >>> a timer value, but I am not sure why we need it? >> >> Because virtual clock in icount mode is correct only at the end of the >> block. >> Allowing virtual clock reads in other places will make execution >> non-deterministic, because icount is updated to the value, which it gets >> after the block ends. > > OK, got it. > >>> >>>> tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); >>>> gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); >>>> tcg_temp_free(spr); >>>> @@ -898,6 +910,9 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) >>>> } else { >>>> TCGv spr; >>>> + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { >>>> + gen_io_start(); >>>> + } >>> >>> Here and above, why do we need to call gen_io_start()? This seems to need to be >>> called before io operations. >> >> gen_io_start allows reading icount for the instruction. >> It is needed to prevent invalid reads in the middle of the block. >> >>> >>> This may all be OK, but could you help explain the theory of operation? Also, >>> have you tested this? >> >> I have record/replay tests for openrisc, but I can't submit them without >> this patch, because they will fail. > > OK. > > Acked-by: Stafford Horne <shorne@gmail.com> > > I am not currently maintaining an openrisc queue, but I could start one. Do you > have another way to submit this upstream? Paolo, can you queue this one? Pavel Dovgalyuk
On 31/03/21 14:48, Pavel Dovgalyuk wrote: >> Acked-by: Stafford Horne <shorne@gmail.com> >> >> I am not currently maintaining an openrisc queue, but I could start >> one. Do you >> have another way to submit this upstream? > > Paolo, can you queue this one? Sure, done. Paolo
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index c6dce879f1..a9c81f8bd5 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -884,6 +884,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) gen_illegal_exception(dc); } else { TCGv spr = tcg_temp_new(); + + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + if (dc->delayed_branch) { + tcg_gen_mov_tl(cpu_pc, jmp_pc); + tcg_gen_discard_tl(jmp_pc); + } else { + tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); + } + dc->base.is_jmp = DISAS_EXIT; + } + tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); tcg_temp_free(spr); @@ -898,6 +910,9 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) } else { TCGv spr; + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } /* For SR, we will need to exit the TB to recognize the new * exception state. For NPC, in theory this counts as a branch * (although the SPR only exists for use by an ICE). Save all
This patch adds icount handling to mfspr/mtspr instructions that may deal with hardware timers. Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru> --- target/openrisc/translate.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)