qemu-sparc queue

-----BEGIN PGP SIGNATURE-----
 
 iQFSBAABCgA8FiEEzGIauY6CIA2RXMnEW8LFb64PMh8FAmE4oxgeHG1hcmsuY2F2
 ZS1heWxhbmRAaWxhbmRlLmNvLnVrAAoJEFvCxW+uDzIfZlsIAJg7WX26r0G0fTSI
 BnmY/Je968rQcLyCNhpUYRaQAeFzCAIBV/nkcVtiDkFMeFCM3rgn/21sbwgRi/K+
 8rRaVT02qcXrUnYniaJcVg51r0aEoMwrt7/GU5utpt21tKIL09ZM5OjFeYHYMFVB
 D98rzf1b83rbEp+jiwwuFfVC9blaqokNdHHEJUCWgQEurgZD5iJ6NsqeSdtPppr4
 2ujH93lTwyijY/oq7pL5zVGmDsnXYBPz/34ox8XF0OCRBLfil10q1jcQOoJBuql4
 GZpe885793xUD/8i1LF3KKsXbz7LbjRij7tFKhvgoeGJRNuuVrP8kNVVyaa6no86
 b+UskgA=
 =M7sK
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/mcayland/tags/qemu-sparc-20210908' into staging

qemu-sparc queue

# gpg: Signature made Wed 08 Sep 2021 12:48:40 BST
# gpg:                using RSA key CC621AB98E82200D915CC9C45BC2C56FAE0F321F
# gpg:                issuer "mark.cave-ayland@ilande.co.uk"
# gpg: Good signature from "Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>" [full]
# Primary key fingerprint: CC62 1AB9 8E82 200D 915C  C9C4 5BC2 C56F AE0F 321F

* remotes/mcayland/tags/qemu-sparc-20210908:
  escc: fix STATUS_SYNC bit in R_STATUS register
  escc: re-use escc_reset_chn() for soft reset
  escc: remove register changes from escc_reset_chn()
  escc: implement hard reset as described in the datasheet
  escc: implement soft reset as described in the datasheet
  escc: introduce escc_hard_reset_chn() for hardware reset
  escc: introduce escc_soft_reset_chn() for software reset
  escc: reset register values to zero in escc_reset()
  escc: checkpatch fixes
  sun4m: fix setting CPU id when more than one CPU is present
  tcg: Drop gen_io_end()
  target/sparc: Drop use of gen_io_end()

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-09-09 16:01:26 +01:00
commit 500f1f3e81
6 changed files with 202 additions and 120 deletions

View File

@ -92,6 +92,3 @@ When the translator is handling an instruction of this kind:
}
* it must end the TB immediately after this instruction
Note that some older front-ends call a "gen_io_end()" function:
this is obsolete and should not be used.

View File

@ -86,12 +86,15 @@
#define W_INTR 1
#define INTR_INTALL 0x01
#define INTR_TXINT 0x02
#define INTR_PAR_SPEC 0x04
#define INTR_RXMODEMSK 0x18
#define INTR_RXINT1ST 0x08
#define INTR_RXINTALL 0x10
#define INTR_WTRQ_TXRX 0x20
#define W_IVEC 2
#define W_RXCTRL 3
#define RXCTRL_RXEN 0x01
#define RXCTRL_HUNT 0x10
#define W_TXCTRL1 4
#define TXCTRL1_PAREN 0x01
#define TXCTRL1_PAREV 0x02
@ -105,6 +108,7 @@
#define TXCTRL1_CLK64X 0xc0
#define TXCTRL1_CLKMSK 0xc0
#define W_TXCTRL2 5
#define TXCTRL2_TXCRC 0x01
#define TXCTRL2_TXEN 0x08
#define TXCTRL2_BITMSK 0x60
#define TXCTRL2_5BITS 0x00
@ -115,18 +119,27 @@
#define W_SYNC2 7
#define W_TXBUF 8
#define W_MINTR 9
#define MINTR_VIS 0x01
#define MINTR_NV 0x02
#define MINTR_STATUSHI 0x10
#define MINTR_SOFTIACK 0x20
#define MINTR_RST_MASK 0xc0
#define MINTR_RST_B 0x40
#define MINTR_RST_A 0x80
#define MINTR_RST_ALL 0xc0
#define W_MISC1 10
#define MISC1_ENC_MASK 0x60
#define W_CLOCK 11
#define CLOCK_TRXC 0x08
#define W_BRGLO 12
#define W_BRGHI 13
#define W_MISC2 14
#define MISC2_PLLDIS 0x30
#define MISC2_BRG_EN 0x01
#define MISC2_BRG_SRC 0x02
#define MISC2_LCL_LOOP 0x10
#define MISC2_PLLCMD0 0x20
#define MISC2_PLLCMD1 0x40
#define MISC2_PLLCMD2 0x80
#define W_EXTINT 15
#define EXTINT_DCD 0x08
#define EXTINT_SYNCINT 0x10
@ -170,6 +183,7 @@
#define R_RXBUF 8
#define R_RXCTRL 9
#define R_MISC 10
#define MISC_2CLKMISS 0x40
#define R_MISC1 11
#define R_BRGLO 12
#define R_BRGHI 13
@ -230,20 +244,23 @@ static uint32_t get_queue(void *opaque)
q->count--;
}
trace_escc_get_queue(CHN_C(s), val);
if (q->count > 0)
if (q->count > 0) {
serial_receive_byte(s, 0);
}
return val;
}
static int escc_update_irq_chn(ESCCChannelState *s)
{
if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
// tx ints enabled, pending
((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
s->rxint == 1) || // rx ints enabled, pending
((s->wregs[W_EXTINT] & EXTINT_BRKINT) &&
(s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p
/* tx ints enabled, pending */
((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
s->rxint == 1) ||
/* rx ints enabled, pending */
((s->wregs[W_EXTINT] & EXTINT_BRKINT) &&
(s->rregs[R_STATUS] & STATUS_BRK)))) {
/* break int e&p */
return 1;
}
return 0;
@ -262,26 +279,7 @@ static void escc_update_irq(ESCCChannelState *s)
static void escc_reset_chn(ESCCChannelState *s)
{
int i;
s->reg = 0;
for (i = 0; i < ESCC_SERIAL_REGS; i++) {
s->rregs[i] = 0;
s->wregs[i] = 0;
}
s->wregs[W_TXCTRL1] = TXCTRL1_1STOP; // 1X divisor, 1 stop bit, no parity
s->wregs[W_MINTR] = MINTR_RST_ALL;
s->wregs[W_CLOCK] = CLOCK_TRXC; // Synch mode tx clock = TRxC
s->wregs[W_MISC2] = MISC2_PLLDIS; // PLL disabled
s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT |
EXTINT_TXUNDRN | EXTINT_BRKINT; // Enable most interrupts
if (s->disabled)
s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC |
STATUS_CTS | STATUS_TXUNDRN;
else
s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN;
s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT;
s->rx = s->tx = 0;
s->rxint = s->txint = 0;
s->rxint_under_svc = s->txint_under_svc = 0;
@ -289,32 +287,99 @@ static void escc_reset_chn(ESCCChannelState *s)
clear_queue(s);
}
static void escc_soft_reset_chn(ESCCChannelState *s)
{
escc_reset_chn(s);
s->wregs[W_CMD] = 0;
s->wregs[W_INTR] &= INTR_PAR_SPEC | INTR_WTRQ_TXRX;
s->wregs[W_RXCTRL] &= ~RXCTRL_RXEN;
/* 1 stop bit */
s->wregs[W_TXCTRL1] |= TXCTRL1_1STOP;
s->wregs[W_TXCTRL2] &= TXCTRL2_TXCRC | TXCTRL2_8BITS;
s->wregs[W_MINTR] &= ~MINTR_SOFTIACK;
s->wregs[W_MISC1] &= MISC1_ENC_MASK;
/* PLL disabled */
s->wregs[W_MISC2] &= MISC2_BRG_EN | MISC2_BRG_SRC |
MISC2_PLLCMD1 | MISC2_PLLCMD2;
s->wregs[W_MISC2] |= MISC2_PLLCMD0;
/* Enable most interrupts */
s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT |
EXTINT_TXUNDRN | EXTINT_BRKINT;
s->rregs[R_STATUS] &= STATUS_DCD | STATUS_SYNC | STATUS_CTS | STATUS_BRK;
s->rregs[R_STATUS] |= STATUS_TXEMPTY | STATUS_TXUNDRN;
if (s->disabled) {
s->rregs[R_STATUS] |= STATUS_DCD | STATUS_SYNC | STATUS_CTS;
}
s->rregs[R_SPEC] &= SPEC_ALLSENT;
s->rregs[R_SPEC] |= SPEC_BITS8;
s->rregs[R_INTR] = 0;
s->rregs[R_MISC] &= MISC_2CLKMISS;
}
static void escc_hard_reset_chn(ESCCChannelState *s)
{
escc_soft_reset_chn(s);
/*
* Hard reset is almost identical to soft reset above, except that the
* values of WR9 (W_MINTR), WR10 (W_MISC1), WR11 (W_CLOCK) and WR14
* (W_MISC2) have extra bits forced to 0/1
*/
s->wregs[W_MINTR] &= MINTR_VIS | MINTR_NV;
s->wregs[W_MINTR] |= MINTR_RST_B | MINTR_RST_A;
s->wregs[W_MISC1] = 0;
s->wregs[W_CLOCK] = CLOCK_TRXC;
s->wregs[W_MISC2] &= MISC2_PLLCMD1 | MISC2_PLLCMD2;
s->wregs[W_MISC2] |= MISC2_LCL_LOOP | MISC2_PLLCMD0;
}
static void escc_reset(DeviceState *d)
{
ESCCState *s = ESCC(d);
int i, j;
escc_reset_chn(&s->chn[0]);
escc_reset_chn(&s->chn[1]);
for (i = 0; i < 2; i++) {
ESCCChannelState *cs = &s->chn[i];
/*
* According to the ESCC datasheet "Miscellaneous Questions" section
* on page 384, the values of the ESCC registers are not guaranteed on
* power-on until an explicit hardware or software reset has been
* issued. For now we zero the registers so that a device reset always
* returns the emulated device to a fixed state.
*/
for (j = 0; j < ESCC_SERIAL_REGS; j++) {
cs->rregs[j] = 0;
cs->wregs[j] = 0;
}
escc_reset_chn(cs);
}
}
static inline void set_rxint(ESCCChannelState *s)
{
s->rxint = 1;
/* XXX: missing daisy chainnig: escc_chn_b rx should have a lower priority
than chn_a rx/tx/special_condition service*/
/*
* XXX: missing daisy chaining: escc_chn_b rx should have a lower priority
* than chn_a rx/tx/special_condition service
*/
s->rxint_under_svc = 1;
if (s->chn == escc_chn_a) {
s->rregs[R_INTR] |= INTR_RXINTA;
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
if (s->wregs[W_MINTR] & MINTR_STATUSHI) {
s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
else
} else {
s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
}
} else {
s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
if (s->wregs[W_MINTR] & MINTR_STATUSHI) {
s->rregs[R_IVEC] = IVEC_HIRXINTB;
else
} else {
s->rregs[R_IVEC] = IVEC_LORXINTB;
}
}
escc_update_irq(s);
}
@ -328,17 +393,18 @@ static inline void set_txint(ESCCChannelState *s)
if (s->wregs[W_INTR] & INTR_TXINT) {
s->rregs[R_INTR] |= INTR_TXINTA;
}
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
if (s->wregs[W_MINTR] & MINTR_STATUSHI) {
s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
else
} else {
s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
}
} else {
s->rregs[R_IVEC] = IVEC_TXINTB;
if (s->wregs[W_INTR] & INTR_TXINT) {
s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
}
}
escc_update_irq(s);
escc_update_irq(s);
}
}
@ -347,20 +413,23 @@ static inline void clr_rxint(ESCCChannelState *s)
s->rxint = 0;
s->rxint_under_svc = 0;
if (s->chn == escc_chn_a) {
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
if (s->wregs[W_MINTR] & MINTR_STATUSHI) {
s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
else
} else {
s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
}
s->rregs[R_INTR] &= ~INTR_RXINTA;
} else {
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
if (s->wregs[W_MINTR] & MINTR_STATUSHI) {
s->rregs[R_IVEC] = IVEC_HINOINT;
else
} else {
s->rregs[R_IVEC] = IVEC_LONOINT;
}
s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB;
}
if (s->txint)
if (s->txint) {
set_txint(s);
}
escc_update_irq(s);
}
@ -369,21 +438,24 @@ static inline void clr_txint(ESCCChannelState *s)
s->txint = 0;
s->txint_under_svc = 0;
if (s->chn == escc_chn_a) {
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
if (s->wregs[W_MINTR] & MINTR_STATUSHI) {
s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
else
} else {
s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
}
s->rregs[R_INTR] &= ~INTR_TXINTA;
} else {
s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
if (s->wregs[W_MINTR] & MINTR_STATUSHI) {
s->rregs[R_IVEC] = IVEC_HINOINT;
else
} else {
s->rregs[R_IVEC] = IVEC_LONOINT;
}
s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
}
if (s->rxint)
if (s->rxint) {
set_rxint(s);
}
escc_update_irq(s);
}
@ -392,21 +464,24 @@ static void escc_update_parameters(ESCCChannelState *s)
int speed, parity, data_bits, stop_bits;
QEMUSerialSetParams ssp;
if (!qemu_chr_fe_backend_connected(&s->chr) || s->type != escc_serial)
if (!qemu_chr_fe_backend_connected(&s->chr) || s->type != escc_serial) {
return;
}
if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV)
if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV) {
parity = 'E';
else
} else {
parity = 'O';
}
} else {
parity = 'N';
}
if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP)
if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP) {
stop_bits = 2;
else
} else {
stop_bits = 1;
}
switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) {
case TXCTRL2_5BITS:
data_bits = 5;
@ -487,7 +562,13 @@ static void escc_mem_write(void *opaque, hwaddr addr,
break;
}
break;
case W_INTR ... W_RXCTRL:
case W_RXCTRL:
s->wregs[s->reg] = val;
if (val & RXCTRL_HUNT) {
s->rregs[R_STATUS] |= STATUS_SYNC;
}
break;
case W_INTR ... W_IVEC:
case W_SYNC1 ... W_TXBUF:
case W_MISC1 ... W_CLOCK:
case W_MISC2 ... W_EXTINT:
@ -510,23 +591,28 @@ static void escc_mem_write(void *opaque, hwaddr addr,
default:
break;
case MINTR_RST_B:
escc_reset_chn(&serial->chn[0]);
trace_escc_soft_reset_chn(CHN_C(&serial->chn[0]));
escc_soft_reset_chn(&serial->chn[0]);
return;
case MINTR_RST_A:
escc_reset_chn(&serial->chn[1]);
trace_escc_soft_reset_chn(CHN_C(&serial->chn[1]));
escc_soft_reset_chn(&serial->chn[1]);
return;
case MINTR_RST_ALL:
escc_reset(DEVICE(serial));
trace_escc_hard_reset();
escc_hard_reset_chn(&serial->chn[0]);
escc_hard_reset_chn(&serial->chn[1]);
return;
}
break;
default:
break;
}
if (s->reg == 0)
if (s->reg == 0) {
s->reg = newreg;
else
} else {
s->reg = 0;
}
break;
case SERIAL_DATA:
trace_escc_mem_writeb_data(CHN_C(s), val);
@ -538,17 +624,19 @@ static void escc_mem_write(void *opaque, hwaddr addr,
s->txint = 0;
escc_update_irq(s);
s->tx = val;
if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { /* tx enabled */
if (qemu_chr_fe_backend_connected(&s->chr)) {
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
/*
* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks
*/
qemu_chr_fe_write_all(&s->chr, &s->tx, 1);
} else if (s->type == escc_kbd && !s->disabled) {
handle_kbd_command(s, val);
}
}
s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty
s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent
s->rregs[R_STATUS] |= STATUS_TXEMPTY; /* Tx buffer empty */
s->rregs[R_SPEC] |= SPEC_ALLSENT; /* All sent */
set_txint(s);
break;
default:
@ -606,12 +694,13 @@ static int serial_can_receive(void *opaque)
ESCCChannelState *s = opaque;
int ret;
if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled
|| ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV))
// char already available
if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) /* Rx not enabled */
|| ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV)) {
/* char already available */
ret = 0;
else
} else {
ret = 1;
}
return ret;
}
@ -638,12 +727,13 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size)
static void serial_event(void *opaque, QEMUChrEvent event)
{
ESCCChannelState *s = opaque;
if (event == CHR_EVENT_BREAK)
if (event == CHR_EVENT_BREAK) {
serial_receive_break(s);
}
}
static const VMStateDescription vmstate_escc_chn = {
.name ="escc_chn",
.name = "escc_chn",
.version_id = 2,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
@ -662,7 +752,7 @@ static const VMStateDescription vmstate_escc_chn = {
};
static const VMStateDescription vmstate_escc = {
.name ="escc",
.name = "escc",
.version_id = 2,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
@ -734,21 +824,21 @@ static QemuInputHandler sunkbd_handler = {
static void handle_kbd_command(ESCCChannelState *s, int val)
{
trace_escc_kbd_command(val);
if (s->led_mode) { // Ignore led byte
if (s->led_mode) { /* Ignore led byte */
s->led_mode = 0;
return;
}
switch (val) {
case 1: // Reset, return type code
case 1: /* Reset, return type code */
clear_queue(s);
put_queue(s, 0xff);
put_queue(s, 4); // Type 4
put_queue(s, 4); /* Type 4 */
put_queue(s, 0x7f);
break;
case 0xe: // Set leds
case 0xe: /* Set leds */
s->led_mode = 1;
break;
case 7: // Query layout
case 7: /* Query layout */
case 0xf:
clear_queue(s);
put_queue(s, 0xfe);
@ -768,34 +858,39 @@ static void sunmouse_event(void *opaque,
trace_escc_sunmouse_event(dx, dy, buttons_state);
ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
if (buttons_state & MOUSE_EVENT_LBUTTON)
if (buttons_state & MOUSE_EVENT_LBUTTON) {
ch ^= 0x4;
if (buttons_state & MOUSE_EVENT_MBUTTON)
}
if (buttons_state & MOUSE_EVENT_MBUTTON) {
ch ^= 0x2;
if (buttons_state & MOUSE_EVENT_RBUTTON)
}
if (buttons_state & MOUSE_EVENT_RBUTTON) {
ch ^= 0x1;
}
put_queue(s, ch);
ch = dx;
if (ch > 127)
if (ch > 127) {
ch = 127;
else if (ch < -127)
} else if (ch < -127) {
ch = -127;
}
put_queue(s, ch & 0xff);
ch = -dy;
if (ch > 127)
if (ch > 127) {
ch = 127;
else if (ch < -127)
} else if (ch < -127) {
ch = -127;
}
put_queue(s, ch & 0xff);
// MSC protocol specify two extra motion bytes
/* MSC protocol specifies two extra motion bytes */
put_queue(s, 0);
put_queue(s, 0);

View File

@ -36,6 +36,8 @@ grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" va
grlib_apbuart_readl_unknown(uint64_t addr) "addr 0x%"PRIx64
# escc.c
escc_hard_reset(void) "hard reset"
escc_soft_reset_chn(char channel) "soft reset channel %c"
escc_put_queue(char channel, int b) "channel %c put: 0x%02x"
escc_get_queue(char channel, int val) "channel %c get 0x%02x"
escc_update_irq(int irq) "IRQ = %d"

View File

@ -803,11 +803,11 @@ static void cpu_devinit(const char *cpu_type, unsigned int id,
cpu = SPARC_CPU(object_new(cpu_type));
env = &cpu->env;
cpu_sparc_set_id(env, id);
qemu_register_reset(sun4m_cpu_reset, cpu);
object_property_set_bool(OBJECT(cpu), "start-powered-off", id != 0,
&error_fatal);
qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal);
cpu_sparc_set_id(env, id);
*cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS);
env->prom_addr = prom_addr;
}

View File

@ -17,22 +17,6 @@ static inline void gen_io_start(void)
tcg_temp_free_i32(tmp);
}
/*
* cpu->can_do_io is cleared automatically at the beginning of
* each translation block. The cost is minimal and only paid
* for -icount, plus it would be very easy to forget doing it
* in the translator. Therefore, backends only need to call
* gen_io_start.
*/
static inline void gen_io_end(void)
{
TCGv_i32 tmp = tcg_const_i32(0);
tcg_gen_st_i32(tmp, cpu_env,
offsetof(ArchCPU, parent_obj.can_do_io) -
offsetof(ArchCPU, env));
tcg_temp_free_i32(tmp);
}
static inline void gen_tb_start(const TranslationBlock *tb)
{
TCGv_i32 count;
@ -64,7 +48,16 @@ static inline void gen_tb_start(const TranslationBlock *tb)
tcg_gen_st16_i32(count, cpu_env,
offsetof(ArchCPU, neg.icount_decr.u16.low) -
offsetof(ArchCPU, env));
gen_io_end();
/*
* cpu->can_do_io is cleared automatically here at the beginning of
* each translation block. The cost is minimal and only paid for
* -icount, plus it would be very easy to forget doing it in the
* translator. Doing it here means we don't need a gen_io_end() to
* go with gen_io_start().
*/
tcg_gen_st_i32(tcg_constant_i32(0), cpu_env,
offsetof(ArchCPU, parent_obj.can_do_io) -
offsetof(ArchCPU, env));
}
tcg_temp_free_i32(count);

View File

@ -3401,7 +3401,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
tcg_temp_free_i32(r_const);
gen_store_gpr(dc, rd, cpu_dst);
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
/* I/O operations in icount mode must end the TB */
dc->base.is_jmp = DISAS_EXIT;
}
}
break;
@ -3454,7 +3455,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
tcg_temp_free_i32(r_const);
gen_store_gpr(dc, rd, cpu_dst);
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
/* I/O operations in icount mode must end the TB */
dc->base.is_jmp = DISAS_EXIT;
}
}
break;
@ -3588,7 +3590,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
tcg_temp_free_ptr(r_tickptr);
tcg_temp_free_i32(r_const);
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
/* I/O operations in icount mode must end the TB */
dc->base.is_jmp = DISAS_EXIT;
}
}
break;
@ -4582,7 +4585,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
}
gen_helper_wrpstate(cpu_env, cpu_tmp0);
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
/* I/O ops in icount mode must end the TB */
dc->base.is_jmp = DISAS_EXIT;
}
dc->npc = DYNAMIC_PC;
break;
@ -4598,7 +4602,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
}
gen_helper_wrpil(cpu_env, cpu_tmp0);
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
/* I/O ops in icount mode must end the TB */
dc->base.is_jmp = DISAS_EXIT;
}
break;
case 9: // cwp
@ -4697,10 +4702,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
gen_helper_tick_set_limit(r_tickptr,
cpu_hstick_cmpr);
tcg_temp_free_ptr(r_tickptr);
if (tb_cflags(dc->base.tb) &
CF_USE_ICOUNT) {
gen_io_end();
}
/* End TB to handle timer interrupt */
dc->base.is_jmp = DISAS_EXIT;
}
@ -5327,9 +5328,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
gen_io_start();
}
gen_helper_done(cpu_env);
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
}
goto jmp_insn;
case 1:
if (!supervisor(dc))
@ -5340,9 +5338,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
gen_io_start();
}
gen_helper_retry(cpu_env);
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
}
goto jmp_insn;
default:
goto illegal_insn;