target/avr: Add instruction translation - Bit and Bit-test Instructions
This includes: - LSR, ROR - ASR - SWAP - SBI, CBI - BST, BLD - BSET, BCLR Signed-off-by: Michael Rolnik <mrolnik@gmail.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Aleksandar Markovic <aleksandar.m.mail@gmail.com> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> Reviewed-by: Aleksandar Markovic <aleksandar.m.mail@gmail.com> Signed-off-by: Thomas Huth <huth@tuxfamily.org> Message-Id: <20200705140315.260514-15-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
This commit is contained in:
parent
9732b024f7
commit
5718cef05a
@ -163,3 +163,17 @@ XCH 1001 001 rd:5 0100
|
||||
LAC 1001 001 rd:5 0110
|
||||
LAS 1001 001 rd:5 0101
|
||||
LAT 1001 001 rd:5 0111
|
||||
|
||||
#
|
||||
# Bit and Bit-test Instructions
|
||||
#
|
||||
LSR 1001 010 rd:5 0110
|
||||
ROR 1001 010 rd:5 0111
|
||||
ASR 1001 010 rd:5 0101
|
||||
SWAP 1001 010 rd:5 0010
|
||||
SBI 1001 1010 reg:5 bit:3
|
||||
CBI 1001 1000 reg:5 bit:3
|
||||
BST 1111 101 rd:5 0 bit:3
|
||||
BLD 1111 100 rd:5 0 bit:3
|
||||
BSET 1001 0100 0 bit:3 1000
|
||||
BCLR 1001 0100 1 bit:3 1000
|
||||
|
@ -2493,3 +2493,250 @@ static bool trans_LAT(DisasContext *ctx, arg_LAT *a)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bit and Bit-test Instructions
|
||||
*/
|
||||
static void gen_rshift_ZNVSf(TCGv R)
|
||||
{
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
|
||||
tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
|
||||
tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf);
|
||||
tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
|
||||
}
|
||||
|
||||
/*
|
||||
* Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is
|
||||
* loaded into the C Flag of the SREG. This operation effectively divides an
|
||||
* unsigned value by two. The C Flag can be used to round the result.
|
||||
*/
|
||||
static bool trans_LSR(DisasContext *ctx, arg_LSR *a)
|
||||
{
|
||||
TCGv Rd = cpu_r[a->rd];
|
||||
|
||||
tcg_gen_andi_tl(cpu_Cf, Rd, 1);
|
||||
tcg_gen_shri_tl(Rd, Rd, 1);
|
||||
|
||||
/* update status register */
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, Rd, 0); /* Zf = Rd == 0 */
|
||||
tcg_gen_movi_tl(cpu_Nf, 0);
|
||||
tcg_gen_mov_tl(cpu_Vf, cpu_Cf);
|
||||
tcg_gen_mov_tl(cpu_Sf, cpu_Vf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shifts all bits in Rd one place to the right. The C Flag is shifted into
|
||||
* bit 7 of Rd. Bit 0 is shifted into the C Flag. This operation, combined
|
||||
* with ASR, effectively divides multi-byte signed values by two. Combined with
|
||||
* LSR it effectively divides multi-byte unsigned values by two. The Carry Flag
|
||||
* can be used to round the result.
|
||||
*/
|
||||
static bool trans_ROR(DisasContext *ctx, arg_ROR *a)
|
||||
{
|
||||
TCGv Rd = cpu_r[a->rd];
|
||||
TCGv t0 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_shli_tl(t0, cpu_Cf, 7);
|
||||
|
||||
/* update status register */
|
||||
tcg_gen_andi_tl(cpu_Cf, Rd, 1);
|
||||
|
||||
/* update output register */
|
||||
tcg_gen_shri_tl(Rd, Rd, 1);
|
||||
tcg_gen_or_tl(Rd, Rd, t0);
|
||||
|
||||
/* update status register */
|
||||
gen_rshift_ZNVSf(Rd);
|
||||
|
||||
tcg_temp_free_i32(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0
|
||||
* is loaded into the C Flag of the SREG. This operation effectively divides a
|
||||
* signed value by two without changing its sign. The Carry Flag can be used to
|
||||
* round the result.
|
||||
*/
|
||||
static bool trans_ASR(DisasContext *ctx, arg_ASR *a)
|
||||
{
|
||||
TCGv Rd = cpu_r[a->rd];
|
||||
TCGv t0 = tcg_temp_new_i32();
|
||||
|
||||
/* update status register */
|
||||
tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf = Rd(0) */
|
||||
|
||||
/* update output register */
|
||||
tcg_gen_andi_tl(t0, Rd, 0x80); /* Rd = (Rd & 0x80) | (Rd >> 1) */
|
||||
tcg_gen_shri_tl(Rd, Rd, 1);
|
||||
tcg_gen_or_tl(Rd, Rd, t0);
|
||||
|
||||
/* update status register */
|
||||
gen_rshift_ZNVSf(Rd);
|
||||
|
||||
tcg_temp_free_i32(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Swaps high and low nibbles in a register.
|
||||
*/
|
||||
static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a)
|
||||
{
|
||||
TCGv Rd = cpu_r[a->rd];
|
||||
TCGv t0 = tcg_temp_new_i32();
|
||||
TCGv t1 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_andi_tl(t0, Rd, 0x0f);
|
||||
tcg_gen_shli_tl(t0, t0, 4);
|
||||
tcg_gen_andi_tl(t1, Rd, 0xf0);
|
||||
tcg_gen_shri_tl(t1, t1, 4);
|
||||
tcg_gen_or_tl(Rd, t0, t1);
|
||||
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets a specified bit in an I/O Register. This instruction operates on
|
||||
* the lower 32 I/O Registers -- addresses 0-31.
|
||||
*/
|
||||
static bool trans_SBI(DisasContext *ctx, arg_SBI *a)
|
||||
{
|
||||
TCGv data = tcg_temp_new_i32();
|
||||
TCGv port = tcg_const_i32(a->reg);
|
||||
|
||||
gen_helper_inb(data, cpu_env, port);
|
||||
tcg_gen_ori_tl(data, data, 1 << a->bit);
|
||||
gen_helper_outb(cpu_env, port, data);
|
||||
|
||||
tcg_temp_free_i32(port);
|
||||
tcg_temp_free_i32(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clears a specified bit in an I/O Register. This instruction operates on
|
||||
* the lower 32 I/O Registers -- addresses 0-31.
|
||||
*/
|
||||
static bool trans_CBI(DisasContext *ctx, arg_CBI *a)
|
||||
{
|
||||
TCGv data = tcg_temp_new_i32();
|
||||
TCGv port = tcg_const_i32(a->reg);
|
||||
|
||||
gen_helper_inb(data, cpu_env, port);
|
||||
tcg_gen_andi_tl(data, data, ~(1 << a->bit));
|
||||
gen_helper_outb(cpu_env, port, data);
|
||||
|
||||
tcg_temp_free_i32(data);
|
||||
tcg_temp_free_i32(port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores bit b from Rd to the T Flag in SREG (Status Register).
|
||||
*/
|
||||
static bool trans_BST(DisasContext *ctx, arg_BST *a)
|
||||
{
|
||||
TCGv Rd = cpu_r[a->rd];
|
||||
|
||||
tcg_gen_andi_tl(cpu_Tf, Rd, 1 << a->bit);
|
||||
tcg_gen_shri_tl(cpu_Tf, cpu_Tf, a->bit);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies the T Flag in the SREG (Status Register) to bit b in register Rd.
|
||||
*/
|
||||
static bool trans_BLD(DisasContext *ctx, arg_BLD *a)
|
||||
{
|
||||
TCGv Rd = cpu_r[a->rd];
|
||||
TCGv t1 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_andi_tl(Rd, Rd, ~(1u << a->bit)); /* clear bit */
|
||||
tcg_gen_shli_tl(t1, cpu_Tf, a->bit); /* create mask */
|
||||
tcg_gen_or_tl(Rd, Rd, t1);
|
||||
|
||||
tcg_temp_free_i32(t1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets a single Flag or bit in SREG.
|
||||
*/
|
||||
static bool trans_BSET(DisasContext *ctx, arg_BSET *a)
|
||||
{
|
||||
switch (a->bit) {
|
||||
case 0x00:
|
||||
tcg_gen_movi_tl(cpu_Cf, 0x01);
|
||||
break;
|
||||
case 0x01:
|
||||
tcg_gen_movi_tl(cpu_Zf, 0x01);
|
||||
break;
|
||||
case 0x02:
|
||||
tcg_gen_movi_tl(cpu_Nf, 0x01);
|
||||
break;
|
||||
case 0x03:
|
||||
tcg_gen_movi_tl(cpu_Vf, 0x01);
|
||||
break;
|
||||
case 0x04:
|
||||
tcg_gen_movi_tl(cpu_Sf, 0x01);
|
||||
break;
|
||||
case 0x05:
|
||||
tcg_gen_movi_tl(cpu_Hf, 0x01);
|
||||
break;
|
||||
case 0x06:
|
||||
tcg_gen_movi_tl(cpu_Tf, 0x01);
|
||||
break;
|
||||
case 0x07:
|
||||
tcg_gen_movi_tl(cpu_If, 0x01);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clears a single Flag in SREG.
|
||||
*/
|
||||
static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a)
|
||||
{
|
||||
switch (a->bit) {
|
||||
case 0x00:
|
||||
tcg_gen_movi_tl(cpu_Cf, 0x00);
|
||||
break;
|
||||
case 0x01:
|
||||
tcg_gen_movi_tl(cpu_Zf, 0x00);
|
||||
break;
|
||||
case 0x02:
|
||||
tcg_gen_movi_tl(cpu_Nf, 0x00);
|
||||
break;
|
||||
case 0x03:
|
||||
tcg_gen_movi_tl(cpu_Vf, 0x00);
|
||||
break;
|
||||
case 0x04:
|
||||
tcg_gen_movi_tl(cpu_Sf, 0x00);
|
||||
break;
|
||||
case 0x05:
|
||||
tcg_gen_movi_tl(cpu_Hf, 0x00);
|
||||
break;
|
||||
case 0x06:
|
||||
tcg_gen_movi_tl(cpu_Tf, 0x00);
|
||||
break;
|
||||
case 0x07:
|
||||
tcg_gen_movi_tl(cpu_If, 0x00);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user