Files
2025-10-14 09:52:32 +09:00

300 lines
6.0 KiB
C

// --------------------------------------------------------------------------------
// @Title: t32server - DCC functions
// @Description: -
// @Author: KJM
// @Copyright: (C) 1989-2022 Lauterbach GmbH, licensed for use with TRACE32(R) only
// --------------------------------------------------------------------------------
// $Id: arm-dcc.c 18850 2022-01-26 18:41:29Z bschroefel $
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include "arm-dcc.h"
#define MIN(A,B) (( (A) < (B)) ? (A) : (B))
char serial_dcc = 0;
static int ttyJ = 0;
static int tty_count_out;
static char tty_buf_out[TTY_BUF_SIZE];
static int tty_sent = 0;
int armfamily; /* = 9 for arm7,9 and =11 for arm10,11, CORTEX */
int get_dcc_status(int arm)
{
int status = 0;
if (arm == 9)
asm volatile("MRC p14,0,%0,c0,c0": "=r" (status));
else if (arm == 11)
{
asm volatile("MRC p14,0,%0,c0,c1": "=r" (status));
status = ((status & 0x40000000) >> 30) + ((status & 0x20000000) >> 28);
}
return status;
}
int read_dcc_reg(int arm)
{
int data = -1;
if (arm == 9)
asm volatile("MRC p14,0,%0,c1,c0": "=r" (data));
else if (arm == 11)
asm volatile("MRC p14,0,%0,c0,c5": "=r" (data));
return data;
}
void write_dcc_reg(int arm, int data, int terminal)
{
if (!terminal)
data |= 0x0c000000;
if (arm == 9)
asm volatile("MCR p14,0,%0,c1,c0"::"r" (data));
else if (arm == 11)
asm volatile("MCR p14,0,%0,c0,c5"::"r" (data));
return;
}
int send_dcc(char *buf, int cnt, int timeout, int terminal)
{
int n, r, status;
int i=0;
int data = 0;
time_t startingTime;
r = cnt%3;
n = cnt/3;
while (i<n*3)
{
data = buf[i] | buf[i+1] << 8 | buf[i+2] << 16 | 0x02000000;
startingTime = time(NULL);
do {
status = get_dcc_status(armfamily);
if (((time(NULL)-startingTime)*2000) >= timeout) {
return i;
}
} while (status & 0x2);
write_dcc_reg(armfamily, data, terminal);
i+=3;
}
data = 0;
if (r!=0)
{
if (r==1)
{
data = buf[i];
}
else if(r==2)
{
data = buf[i] | buf[i+1] << 8 | 0x01000000;
}
startingTime = time(NULL);
do {
status = get_dcc_status(armfamily);
if (((time(NULL)-startingTime)*2000) >= timeout) {
return i;
}
} while (status & 0x2);
write_dcc_reg(armfamily, data, terminal);
}
return cnt;
}
/* this function is called when the terminal and run mode are multiplexed over DCC. */
void console_read()
{
int n;
int cnt;
if (tty_count_out-tty_sent > 0) {
n = MIN(TERMINAL_BLOCK_SIZE,tty_count_out-tty_sent);
cnt = send_dcc(tty_buf_out+tty_sent, n, 1000, 1);
tty_sent+=cnt;
return;
}
tty_sent = 0;
tty_count_out = read(ttyJ, tty_buf_out, 2000);
lseek(ttyJ, 0, SEEK_SET);
if (tty_count_out) {
n = MIN(TERMINAL_BLOCK_SIZE,tty_count_out-tty_sent);
cnt = send_dcc(tty_buf_out+tty_sent, n, 1000, 1);
tty_sent+=cnt;
}
}
int read_dcc(char *buf, int timeout)
{
int status, channel;
int data, len, i;
time_t startingTime;
startingTime = time(NULL);
do {
status = get_dcc_status(armfamily);
if (((time(NULL)-startingTime)*2000) >= timeout)
{
return -1;
}
if (!(status & 0x1) && serial_dcc) /* if terminal packet, store in buffer */
console_read();
} while (!(status & 0x1));
data = read_dcc_reg(armfamily);
len = ((data >> 24) & 0x3) + 1;
if (len > 3) {
return -1;
}
for(i=0; i<len; i++)
buf[i] = (data >> (i*8));
channel = (data >> 24) & 0xfc;
if (channel == 0) {
write(ttyJ, buf, len);
return -1;
}
return data;
}
int init_dcc_console()
{
char tmp[5];
int id;
ttyJ = open("/proc/ttyJf", O_RDWR, 0);
if (ttyJ < 0) {
printf("error redirecting serial console\n");
return -1;
}
printf("redirecting serial dcc console..\n");
sprintf(tmp, "T32");
id = getpid();
tmp[3] = (id >> 8) & 0xff;
tmp[4] = id & 0xff;
write(ttyJ, tmp, 5);
return 0;
}
int send_dcc_fast(int data1, int data2, int data3, int len)
{
int status;
time_t startingTime = time(NULL);
do {
status = get_dcc_status(armfamily);
if (((time(NULL)-startingTime)*2000) >= 100)
return -1;
} while (!(status & 0x1) && (status & 0x2));
if (!(status & 0x2))
{
write_dcc_reg(armfamily, data1, 0);
if (len == 1)
{
return 0;
}
startingTime = time(NULL);
do {
status = get_dcc_status(armfamily);
if (((time(NULL)-startingTime)*2000) >= 100)
return -1;
} while (status & 0x2);
write_dcc_reg(armfamily, data2, 0);
if (len == 2)
return 0;
startingTime = time(NULL);
do {
status = get_dcc_status(armfamily);
if (((time(NULL)-startingTime)*2000) >= 100)
return -1;
} while (status & 0x2);
write_dcc_reg(armfamily, data3, 0);
return 0;
}
return -1;
}
void get_arm_version()
{
int count = 0;;
FILE * fd;
char buf[500];
char *res, *ptr;
fd = fopen("/proc/cpuinfo", "r");
if (fd < 0) {
printf("error identifying arm version, assuming it is arm 7/9\n");
armfamily = 9;
return;
}
while (1) {
res = fgets(buf, sizeof buf - 1, fd);
if (res == NULL)
break;
if (count == 0)
printf("%s", buf);
count++;
if (strstr(buf, "Processor") || strstr(buf, "processor") || strstr(buf, "PROCESSOR")) {
if (strstr(buf, "CORTEX") || strstr(buf, "cortex")) {
armfamily = 11;
goto done;
}
ptr = strstr(buf, "ARM");
if (ptr) {
ptr += 3;
if (*ptr == '9' || *ptr == '7') {
armfamily = 9;
goto done;
} else if (ptr[0] == '1' && ptr[1] == '1') {
armfamily = 11;
goto done;
}
}
ptr = strstr(buf, "Feroceon");
if (ptr) {
armfamily = 9;
goto done;
}
continue;
}
if (strstr(buf, "architecture")) {
ptr = strchr(buf, ':');
if (ptr)
ptr+=2;
else
continue;
if (*ptr == '5') {
armfamily = 9;
} else {
armfamily = 11;
}
goto done;
}
if (strstr(buf, "CPU part") || strstr(buf, "cpu part")) {
if (strstr(buf, "0x9") || strstr(buf, "0x7")) {
armfamily = 9;
} else {
armfamily = 11;
}
}
}
printf("error identifying arm version, assuming it is arm 7/9\n");
armfamily = 9;
return;
done:
fclose(fd);
}