diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-09-09 16:01:26 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-09-09 16:01:26 +0100 |
commit | 500f1f3e81ad112e28b7c979136847e32dad83b6 (patch) | |
tree | 1cc3274fb14d97bf3d979467181ab200508ee628 | |
parent | bd662023e683850c085e98c8ff8297142c2dd9f2 (diff) | |
parent | 15a2a1a4d1eecc74a87e1552f5cc4e3668375715 (diff) | |
download | qemu-500f1f3e81ad112e28b7c979136847e32dad83b6.zip qemu-500f1f3e81ad112e28b7c979136847e32dad83b6.tar.gz qemu-500f1f3e81ad112e28b7c979136847e32dad83b6.tar.bz2 |
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>
-rw-r--r-- | docs/devel/tcg-icount.rst | 3 | ||||
-rw-r--r-- | hw/char/escc.c | 263 | ||||
-rw-r--r-- | hw/char/trace-events | 2 | ||||
-rw-r--r-- | hw/sparc/sun4m.c | 2 | ||||
-rw-r--r-- | include/exec/gen-icount.h | 27 | ||||
-rw-r--r-- | target/sparc/translate.c | 25 |
6 files changed, 202 insertions, 120 deletions
diff --git a/docs/devel/tcg-icount.rst b/docs/devel/tcg-icount.rst index 8d67b6c..50c8e8d 100644 --- a/docs/devel/tcg-icount.rst +++ b/docs/devel/tcg-icount.rst @@ -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. diff --git a/hw/char/escc.c b/hw/char/escc.c index 52e7978..0fce4f6 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -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); diff --git a/hw/char/trace-events b/hw/char/trace-events index 1436fb4..b774832 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -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" diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 42e1398..7f3a7c0 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -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; } diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index 467529d..610cba5 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -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); diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 11de5a4..bb70ba1 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -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; |