riscv-openocd/contrib/libdcc/dcc_stdio.c

150 lines
3.8 KiB
C

/***************************************************************************
* Copyright (C) 2008 by Dominic Rath *
* Dominic.Rath@gmx.de *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "dcc_stdio.h"
#if defined(__ARM_ARCH_7M__)
/* we use the cortex_m3 DCRDR reg to simulate a arm7_9 dcc channel
* DCRDR[7:0] is used by target for status
* DCRDR[15:8] is used by target for write buffer
* DCRDR[23:16] is used for by host for status
* DCRDR[31:24] is used for by host for write buffer */
#define DCRDR_WRSTS *((volatile u8*)0xE000EDF8)
#define DCRDR_WRDAT *((volatile u8*)0xE000EDF9)
#define BUSY 1
void dbg_write(u32 dcc_data)
{
int len = 4;
while (len--)
{
/* wait for data ready */
while (DCRDR_WRSTS & BUSY);
/* write our data */
DCRDR_WRDAT = (u8)(dcc_data & 0xff);
/* set write flag - tell host there is data */
DCRDR_WRSTS = BUSY;
dcc_data >>= 8;
}
}
#elif defined(__ARM_ARCH_4T__) || defined(__ARM_ARCH_5TE__)
void dbg_write(u32 dcc_data)
{
u32 dcc_status;
do {
asm volatile("mrc p14, 0, %0, c0, c0" : "=r" (dcc_status));
} while (dcc_status & 0x2);
asm volatile("mcr p14, 0, %0, c1, c0" : : "r" (dcc_data));
}
#else
#error unsupported target
#endif
void dbg_write_u32(u32 *val, u32 len)
{
dbg_write(0x01 | 0x0400 | ((len & 0xffff) << 16));
while (len > 0)
{
dbg_write(*val);
val++;
len--;
}
}
void dbg_write_u16(u16 *val, u32 len)
{
u32 dcc_data;
dbg_write(0x01 | 0x0200 | ((len & 0xffff) << 16));
while (len > 0)
{
dcc_data = val[0] | (val[1] << 8)
| ((len > 1) ? (val[2] | (val[3] << 8)) << 16 : 0x00);
dbg_write(dcc_data);
val += 2;
len -= 2;
}
}
void dbg_write_u8(u8 *val, u32 len)
{
u32 dcc_data;
dbg_write(0x01 | 0x0100 | ((len & 0xffff) << 16));
while (len > 0)
{
dcc_data = val[0]
| ((len > 1) ? val[1] << 8 : 0x00)
| ((len > 2) ? val[2] << 16 : 0x00)
| ((len > 3) ? val[3] << 24 : 0x00);
dbg_write(dcc_data);
val += 2;
len -= 2;
}
}
void dbg_write_str(u8 *msg)
{
int len;
u32 dcc_data;
for (len = 0; msg[len] && (len < 65536); len++);
dbg_write(0x01 | ((len & 0xffff) << 16));
while (len > 0)
{
dcc_data = msg[0]
| ((len > 1) ? msg[1] << 8 : 0x00)
| ((len > 2) ? msg[2] << 16 : 0x00)
| ((len > 3) ? msg[3] << 24 : 0x00);
dbg_write(dcc_data);
msg += 4;
len -= 4;
}
}
void dbg_write_char(u8 msg)
{
dbg_write(0x02 | ((msg & 0xff) << 16));
}