|
@@ -27,13 +27,6 @@
|
|
#include "sh7750_regs.h"
|
|
#include "sh7750_regs.h"
|
|
#include "sh7750_regnames.h"
|
|
#include "sh7750_regnames.h"
|
|
|
|
|
|
-typedef struct {
|
|
|
|
- uint8_t data[16];
|
|
|
|
- uint8_t length; /* Number of characters in the FIFO */
|
|
|
|
- uint8_t write_idx; /* Index of first character to write */
|
|
|
|
- uint8_t read_idx; /* Index of first character to read */
|
|
|
|
-} fifo;
|
|
|
|
-
|
|
|
|
#define NB_DEVICES 4
|
|
#define NB_DEVICES 4
|
|
|
|
|
|
typedef struct SH7750State {
|
|
typedef struct SH7750State {
|
|
@@ -43,27 +36,6 @@ typedef struct SH7750State {
|
|
uint32_t periph_freq;
|
|
uint32_t periph_freq;
|
|
/* SDRAM controller */
|
|
/* SDRAM controller */
|
|
uint16_t rfcr;
|
|
uint16_t rfcr;
|
|
- /* First serial port */
|
|
|
|
- CharDriverState *serial1;
|
|
|
|
- uint8_t scscr1;
|
|
|
|
- uint8_t scsmr1;
|
|
|
|
- uint8_t scbrr1;
|
|
|
|
- uint8_t scssr1;
|
|
|
|
- uint8_t scssr1_read;
|
|
|
|
- uint8_t sctsr1;
|
|
|
|
- uint8_t sctsr1_loaded;
|
|
|
|
- uint8_t sctdr1;
|
|
|
|
- uint8_t scrdr1;
|
|
|
|
- /* Second serial port */
|
|
|
|
- CharDriverState *serial2;
|
|
|
|
- uint16_t sclsr2;
|
|
|
|
- uint16_t scscr2;
|
|
|
|
- uint16_t scfcr2;
|
|
|
|
- uint16_t scfsr2;
|
|
|
|
- uint16_t scsmr2;
|
|
|
|
- uint8_t scbrr2;
|
|
|
|
- fifo serial2_receive_fifo;
|
|
|
|
- fifo serial2_transmit_fifo;
|
|
|
|
/* IO ports */
|
|
/* IO ports */
|
|
uint16_t gpioic;
|
|
uint16_t gpioic;
|
|
uint32_t pctra;
|
|
uint32_t pctra;
|
|
@@ -84,263 +56,6 @@ typedef struct SH7750State {
|
|
|
|
|
|
} SH7750State;
|
|
} SH7750State;
|
|
|
|
|
|
-/**********************************************************************
|
|
|
|
- First serial port
|
|
|
|
-**********************************************************************/
|
|
|
|
-
|
|
|
|
-static int serial1_can_receive(void *opaque)
|
|
|
|
-{
|
|
|
|
- SH7750State *s = opaque;
|
|
|
|
-
|
|
|
|
- return s->scscr1 & SH7750_SCSCR_RE;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void serial1_receive_char(SH7750State * s, uint8_t c)
|
|
|
|
-{
|
|
|
|
- if (s->scssr1 & SH7750_SCSSR1_RDRF) {
|
|
|
|
- s->scssr1 |= SH7750_SCSSR1_ORER;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- s->scrdr1 = c;
|
|
|
|
- s->scssr1 |= SH7750_SCSSR1_RDRF;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void serial1_receive(void *opaque, const uint8_t * buf, int size)
|
|
|
|
-{
|
|
|
|
- SH7750State *s = opaque;
|
|
|
|
- int i;
|
|
|
|
-
|
|
|
|
- for (i = 0; i < size; i++) {
|
|
|
|
- serial1_receive_char(s, buf[i]);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void serial1_event(void *opaque, int event)
|
|
|
|
-{
|
|
|
|
- assert(0);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void serial1_maybe_send(SH7750State * s)
|
|
|
|
-{
|
|
|
|
- uint8_t c;
|
|
|
|
-
|
|
|
|
- if (s->scssr1 & SH7750_SCSSR1_TDRE)
|
|
|
|
- return;
|
|
|
|
- c = s->sctdr1;
|
|
|
|
- s->scssr1 |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND;
|
|
|
|
- if (s->scscr1 & SH7750_SCSCR_TIE) {
|
|
|
|
- fprintf(stderr, "interrupts for serial port 1 not implemented\n");
|
|
|
|
- assert(0);
|
|
|
|
- }
|
|
|
|
- /* XXXXX Check for errors in write */
|
|
|
|
- qemu_chr_write(s->serial1, &c, 1);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void serial1_change_scssr1(SH7750State * s, uint8_t mem_value)
|
|
|
|
-{
|
|
|
|
- uint8_t new_flags;
|
|
|
|
-
|
|
|
|
- /* If transmit disable, TDRE and TEND stays up */
|
|
|
|
- if ((s->scscr1 & SH7750_SCSCR_TE) == 0) {
|
|
|
|
- mem_value |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Only clear bits which have been read before and do not set any bit
|
|
|
|
- in the flags */
|
|
|
|
- new_flags = s->scssr1 & ~s->scssr1_read; /* Preserve unread flags */
|
|
|
|
- new_flags &= mem_value | ~s->scssr1_read; /* Clear read flags */
|
|
|
|
-
|
|
|
|
- s->scssr1 = (new_flags & 0xf8) | (mem_value & 1);
|
|
|
|
- s->scssr1_read &= mem_value;
|
|
|
|
-
|
|
|
|
- /* If TDRE has been cleared, TEND will also be cleared */
|
|
|
|
- if ((s->scssr1 & SH7750_SCSSR1_TDRE) == 0) {
|
|
|
|
- s->scssr1 &= ~SH7750_SCSSR1_TEND;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Check for transmission to start */
|
|
|
|
- serial1_maybe_send(s);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void serial1_update_parameters(SH7750State * s)
|
|
|
|
-{
|
|
|
|
- QEMUSerialSetParams ssp;
|
|
|
|
-
|
|
|
|
- if (s->scsmr1 & SH7750_SCSMR_CHR_7)
|
|
|
|
- ssp.data_bits = 7;
|
|
|
|
- else
|
|
|
|
- ssp.data_bits = 8;
|
|
|
|
- if (s->scsmr1 & SH7750_SCSMR_PE) {
|
|
|
|
- if (s->scsmr1 & SH7750_SCSMR_PM_ODD)
|
|
|
|
- ssp.parity = 'O';
|
|
|
|
- else
|
|
|
|
- ssp.parity = 'E';
|
|
|
|
- } else
|
|
|
|
- ssp.parity = 'N';
|
|
|
|
- if (s->scsmr1 & SH7750_SCSMR_STOP_2)
|
|
|
|
- ssp.stop_bits = 2;
|
|
|
|
- else
|
|
|
|
- ssp.stop_bits = 1;
|
|
|
|
- fprintf(stderr, "SCSMR1=%04x SCBRR1=%02x\n", s->scsmr1, s->scbrr1);
|
|
|
|
- ssp.speed = s->periph_freq /
|
|
|
|
- (32 * s->scbrr1 * (1 << (2 * (s->scsmr1 & 3)))) - 1;
|
|
|
|
- fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n",
|
|
|
|
- ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed);
|
|
|
|
- qemu_chr_ioctl(s->serial1, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void scscr1_changed(SH7750State * s)
|
|
|
|
-{
|
|
|
|
- if (s->scscr1 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) {
|
|
|
|
- if (!s->serial1) {
|
|
|
|
- fprintf(stderr, "serial port 1 not bound to anything\n");
|
|
|
|
- assert(0);
|
|
|
|
- }
|
|
|
|
- serial1_update_parameters(s);
|
|
|
|
- }
|
|
|
|
- if ((s->scscr1 & SH7750_SCSCR_RE) == 0) {
|
|
|
|
- s->scssr1 |= SH7750_SCSSR1_TDRE;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void init_serial1(SH7750State * s, int serial_nb)
|
|
|
|
-{
|
|
|
|
- CharDriverState *chr;
|
|
|
|
-
|
|
|
|
- s->scssr1 = 0x84;
|
|
|
|
- chr = serial_hds[serial_nb];
|
|
|
|
- if (!chr) {
|
|
|
|
- fprintf(stderr,
|
|
|
|
- "no serial port associated to SH7750 first serial port\n");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- s->serial1 = chr;
|
|
|
|
- qemu_chr_add_handlers(chr, serial1_can_receive,
|
|
|
|
- serial1_receive, serial1_event, s);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**********************************************************************
|
|
|
|
- Second serial port
|
|
|
|
-**********************************************************************/
|
|
|
|
-
|
|
|
|
-static int serial2_can_receive(void *opaque)
|
|
|
|
-{
|
|
|
|
- SH7750State *s = opaque;
|
|
|
|
- static uint8_t max_fifo_size[] = { 15, 1, 4, 6, 8, 10, 12, 14 };
|
|
|
|
-
|
|
|
|
- return s->serial2_receive_fifo.length <
|
|
|
|
- max_fifo_size[(s->scfcr2 >> 9) & 7];
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void serial2_adjust_receive_flags(SH7750State * s)
|
|
|
|
-{
|
|
|
|
- static uint8_t max_fifo_size[] = { 1, 4, 8, 14 };
|
|
|
|
-
|
|
|
|
- /* XXXXX Add interrupt generation */
|
|
|
|
- if (s->serial2_receive_fifo.length >=
|
|
|
|
- max_fifo_size[(s->scfcr2 >> 7) & 3]) {
|
|
|
|
- s->scfsr2 |= SH7750_SCFSR2_RDF;
|
|
|
|
- s->scfsr2 &= ~SH7750_SCFSR2_DR;
|
|
|
|
- } else {
|
|
|
|
- s->scfsr2 &= ~SH7750_SCFSR2_RDF;
|
|
|
|
- if (s->serial2_receive_fifo.length > 0)
|
|
|
|
- s->scfsr2 |= SH7750_SCFSR2_DR;
|
|
|
|
- else
|
|
|
|
- s->scfsr2 &= ~SH7750_SCFSR2_DR;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void serial2_append_char(SH7750State * s, uint8_t c)
|
|
|
|
-{
|
|
|
|
- if (s->serial2_receive_fifo.length == 16) {
|
|
|
|
- /* Overflow */
|
|
|
|
- s->sclsr2 |= SH7750_SCLSR2_ORER;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- s->serial2_receive_fifo.data[s->serial2_receive_fifo.write_idx++] = c;
|
|
|
|
- s->serial2_receive_fifo.length++;
|
|
|
|
- serial2_adjust_receive_flags(s);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void serial2_receive(void *opaque, const uint8_t * buf, int size)
|
|
|
|
-{
|
|
|
|
- SH7750State *s = opaque;
|
|
|
|
- int i;
|
|
|
|
-
|
|
|
|
- for (i = 0; i < size; i++)
|
|
|
|
- serial2_append_char(s, buf[i]);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void serial2_event(void *opaque, int event)
|
|
|
|
-{
|
|
|
|
- /* XXXXX */
|
|
|
|
- assert(0);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void serial2_update_parameters(SH7750State * s)
|
|
|
|
-{
|
|
|
|
- QEMUSerialSetParams ssp;
|
|
|
|
-
|
|
|
|
- if (s->scsmr2 & SH7750_SCSMR_CHR_7)
|
|
|
|
- ssp.data_bits = 7;
|
|
|
|
- else
|
|
|
|
- ssp.data_bits = 8;
|
|
|
|
- if (s->scsmr2 & SH7750_SCSMR_PE) {
|
|
|
|
- if (s->scsmr2 & SH7750_SCSMR_PM_ODD)
|
|
|
|
- ssp.parity = 'O';
|
|
|
|
- else
|
|
|
|
- ssp.parity = 'E';
|
|
|
|
- } else
|
|
|
|
- ssp.parity = 'N';
|
|
|
|
- if (s->scsmr2 & SH7750_SCSMR_STOP_2)
|
|
|
|
- ssp.stop_bits = 2;
|
|
|
|
- else
|
|
|
|
- ssp.stop_bits = 1;
|
|
|
|
- fprintf(stderr, "SCSMR2=%04x SCBRR2=%02x\n", s->scsmr2, s->scbrr2);
|
|
|
|
- ssp.speed = s->periph_freq /
|
|
|
|
- (32 * s->scbrr2 * (1 << (2 * (s->scsmr2 & 3)))) - 1;
|
|
|
|
- fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n",
|
|
|
|
- ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed);
|
|
|
|
- qemu_chr_ioctl(s->serial2, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void scscr2_changed(SH7750State * s)
|
|
|
|
-{
|
|
|
|
- if (s->scscr2 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) {
|
|
|
|
- if (!s->serial2) {
|
|
|
|
- fprintf(stderr, "serial port 2 not bound to anything\n");
|
|
|
|
- assert(0);
|
|
|
|
- }
|
|
|
|
- serial2_update_parameters(s);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void init_serial2(SH7750State * s, int serial_nb)
|
|
|
|
-{
|
|
|
|
- CharDriverState *chr;
|
|
|
|
-
|
|
|
|
- s->scfsr2 = 0x0060;
|
|
|
|
-
|
|
|
|
- chr = serial_hds[serial_nb];
|
|
|
|
- if (!chr) {
|
|
|
|
- fprintf(stderr,
|
|
|
|
- "no serial port associated to SH7750 second serial port\n");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- s->serial2 = chr;
|
|
|
|
- qemu_chr_add_handlers(chr, serial2_can_receive,
|
|
|
|
- serial2_receive, serial1_event, s);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void init_serial_ports(SH7750State * s)
|
|
|
|
-{
|
|
|
|
- init_serial1(s, 0);
|
|
|
|
- init_serial2(s, 1);
|
|
|
|
-}
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
/**********************************************************************
|
|
I/O ports
|
|
I/O ports
|
|
@@ -472,17 +187,7 @@ static void ignore_access(const char *kind, target_phys_addr_t addr)
|
|
|
|
|
|
static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr)
|
|
static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr)
|
|
{
|
|
{
|
|
- SH7750State *s = opaque;
|
|
|
|
- uint8_t r;
|
|
|
|
-
|
|
|
|
switch (addr) {
|
|
switch (addr) {
|
|
- case SH7750_SCSSR1_A7:
|
|
|
|
- r = s->scssr1;
|
|
|
|
- s->scssr1_read |= r;
|
|
|
|
- return s->scssr1;
|
|
|
|
- case SH7750_SCRDR1_A7:
|
|
|
|
- s->scssr1 &= ~SH7750_SCSSR1_RDRF;
|
|
|
|
- return s->scrdr1;
|
|
|
|
default:
|
|
default:
|
|
error_access("byte read", addr);
|
|
error_access("byte read", addr);
|
|
assert(0);
|
|
assert(0);
|
|
@@ -492,20 +197,12 @@ static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr)
|
|
static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr)
|
|
static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr)
|
|
{
|
|
{
|
|
SH7750State *s = opaque;
|
|
SH7750State *s = opaque;
|
|
- uint16_t r;
|
|
|
|
|
|
|
|
switch (addr) {
|
|
switch (addr) {
|
|
case SH7750_RFCR_A7:
|
|
case SH7750_RFCR_A7:
|
|
fprintf(stderr,
|
|
fprintf(stderr,
|
|
"Read access to refresh count register, incrementing\n");
|
|
"Read access to refresh count register, incrementing\n");
|
|
return s->rfcr++;
|
|
return s->rfcr++;
|
|
- case SH7750_SCLSR2_A7:
|
|
|
|
- /* Read and clear overflow bit */
|
|
|
|
- r = s->sclsr2;
|
|
|
|
- s->sclsr2 = 0;
|
|
|
|
- return r;
|
|
|
|
- case SH7750_SCSFR2_A7:
|
|
|
|
- return s->scfsr2;
|
|
|
|
case SH7750_PDTRA_A7:
|
|
case SH7750_PDTRA_A7:
|
|
return porta_lines(s);
|
|
return porta_lines(s);
|
|
case SH7750_PDTRB_A7:
|
|
case SH7750_PDTRB_A7:
|
|
@@ -554,34 +251,12 @@ static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr)
|
|
static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr,
|
|
static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr,
|
|
uint32_t mem_value)
|
|
uint32_t mem_value)
|
|
{
|
|
{
|
|
- SH7750State *s = opaque;
|
|
|
|
-
|
|
|
|
switch (addr) {
|
|
switch (addr) {
|
|
/* PRECHARGE ? XXXXX */
|
|
/* PRECHARGE ? XXXXX */
|
|
case SH7750_PRECHARGE0_A7:
|
|
case SH7750_PRECHARGE0_A7:
|
|
case SH7750_PRECHARGE1_A7:
|
|
case SH7750_PRECHARGE1_A7:
|
|
ignore_access("byte write", addr);
|
|
ignore_access("byte write", addr);
|
|
return;
|
|
return;
|
|
- case SH7750_SCBRR2_A7:
|
|
|
|
- s->scbrr2 = mem_value;
|
|
|
|
- return;
|
|
|
|
- case SH7750_SCSCR1_A7:
|
|
|
|
- s->scscr1 = mem_value;
|
|
|
|
- scscr1_changed(s);
|
|
|
|
- return;
|
|
|
|
- case SH7750_SCSMR1_A7:
|
|
|
|
- s->scsmr1 = mem_value;
|
|
|
|
- return;
|
|
|
|
- case SH7750_SCBRR1_A7:
|
|
|
|
- s->scbrr1 = mem_value;
|
|
|
|
- return;
|
|
|
|
- case SH7750_SCTDR1_A7:
|
|
|
|
- s->scssr1 &= ~SH7750_SCSSR1_TEND;
|
|
|
|
- s->sctdr1 = mem_value;
|
|
|
|
- return;
|
|
|
|
- case SH7750_SCSSR1_A7:
|
|
|
|
- serial1_change_scssr1(s, mem_value);
|
|
|
|
- return;
|
|
|
|
default:
|
|
default:
|
|
error_access("byte write", addr);
|
|
error_access("byte write", addr);
|
|
assert(0);
|
|
assert(0);
|
|
@@ -596,8 +271,6 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr,
|
|
|
|
|
|
switch (addr) {
|
|
switch (addr) {
|
|
/* SDRAM controller */
|
|
/* SDRAM controller */
|
|
- case SH7750_SCBRR1_A7:
|
|
|
|
- case SH7750_SCBRR2_A7:
|
|
|
|
case SH7750_BCR2_A7:
|
|
case SH7750_BCR2_A7:
|
|
case SH7750_BCR3_A7:
|
|
case SH7750_BCR3_A7:
|
|
case SH7750_RTCOR_A7:
|
|
case SH7750_RTCOR_A7:
|
|
@@ -620,19 +293,6 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr,
|
|
fprintf(stderr, "Write access to refresh count register\n");
|
|
fprintf(stderr, "Write access to refresh count register\n");
|
|
s->rfcr = mem_value;
|
|
s->rfcr = mem_value;
|
|
return;
|
|
return;
|
|
- case SH7750_SCLSR2_A7:
|
|
|
|
- s->sclsr2 = mem_value;
|
|
|
|
- return;
|
|
|
|
- case SH7750_SCSCR2_A7:
|
|
|
|
- s->scscr2 = mem_value;
|
|
|
|
- scscr2_changed(s);
|
|
|
|
- return;
|
|
|
|
- case SH7750_SCFCR2_A7:
|
|
|
|
- s->scfcr2 = mem_value;
|
|
|
|
- return;
|
|
|
|
- case SH7750_SCSMR2_A7:
|
|
|
|
- s->scsmr2 = mem_value;
|
|
|
|
- return;
|
|
|
|
case SH7750_GPIOIC_A7:
|
|
case SH7750_GPIOIC_A7:
|
|
s->gpioic = mem_value;
|
|
s->gpioic = mem_value;
|
|
if (mem_value != 0) {
|
|
if (mem_value != 0) {
|
|
@@ -734,7 +394,10 @@ SH7750State *sh7750_init(CPUSH4State * cpu)
|
|
sh7750_mem_read,
|
|
sh7750_mem_read,
|
|
sh7750_mem_write, s);
|
|
sh7750_mem_write, s);
|
|
cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory);
|
|
cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory);
|
|
- init_serial_ports(s);
|
|
|
|
|
|
+
|
|
|
|
+ sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0]);
|
|
|
|
+ sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF,
|
|
|
|
+ s->periph_freq, serial_hds[1]);
|
|
|
|
|
|
tmu012_init(0x1fd80000,
|
|
tmu012_init(0x1fd80000,
|
|
TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK,
|
|
TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK,
|