URL
https://opencores.org/ocsvn/altor32/altor32/trunk
Subversion Repositories altor32
Compare Revisions
- This comparison shows the changes necessary to convert path
/altor32/trunk
- from Rev 42 to Rev 43
- ↔ Reverse comparison
Rev 42 → Rev 43
/sw/gdb_stub/gdb_hw.h
0,0 → 1,12
#ifndef __GDB_HW_H__ |
#define __GDB_HW_H__ |
|
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
void gdb_putchar(char c); |
void gdb_putstr(const char *str); |
int gdb_getchar(void); |
void gdb_flush_cache(void); |
|
#endif |
/sw/gdb_stub/mem_map.h
0,0 → 1,49
#ifndef __MEM_MAP_H__ |
#define __MEM_MAP_H__ |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define IO_BASE 0x12000000 |
|
//----------------------------------------------------------------- |
// Macros: |
//----------------------------------------------------------------- |
#define REG8 (volatile unsigned char*) |
#define REG16 (volatile unsigned short*) |
#define REG32 (volatile unsigned int*) |
|
//----------------------------------------------------------------- |
// Peripheral Base Addresses |
//----------------------------------------------------------------- |
#define UART_BASE (IO_BASE + 0x000) |
#define TIMER_BASE (IO_BASE + 0x100) |
#define INTR_BASE (IO_BASE + 0x200) |
|
//----------------------------------------------------------------- |
// Interrupts |
//----------------------------------------------------------------- |
#define IRQ_UART_RX 0 |
#define IRQ_TIMER_SYSTICK 1 |
#define IRQ_TIMER_HIRES 2 |
#define IRQ_EXT_INT0 8 |
|
//----------------------------------------------------------------- |
// Peripheral Registers |
//----------------------------------------------------------------- |
|
// UART |
#define UART_USR (*(REG32 (UART_BASE + 0x4))) |
#define UART_UDR (*(REG32 (UART_BASE + 0x8))) |
|
// TIMER |
#define TIMER_VAL (*(REG32 (TIMER_BASE + 0x0))) |
#define SYS_CLK_COUNT (*(REG32 (TIMER_BASE + 0x4))) |
|
// IRQ |
#define IRQ_MASK (*(REG32 (INTR_BASE + 0x00))) |
#define IRQ_MASK_SET (*(REG32 (INTR_BASE + 0x00))) |
#define IRQ_MASK_CLR (*(REG32 (INTR_BASE + 0x04))) |
#define IRQ_STATUS (*(REG32 (INTR_BASE + 0x08))) |
|
#endif |
/sw/gdb_stub/gdb.h
0,0 → 1,10
#ifndef __GDB_H__ |
#define __GDB_H__ |
|
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
void gdb_main(void); |
unsigned int* gdb_exception(unsigned int *registers, unsigned int reason); |
|
#endif |
/sw/gdb_stub/boot.S
0,0 → 1,123
.nodelay |
|
#include "exception.inc" |
|
#------------------------------------------------------------- |
# VECTOR 0x100 - Reset |
#------------------------------------------------------------- |
.org 0x100 |
vector_reset: |
|
# Setup SP (R1) |
l.movhi r4,hi(_sp); |
l.ori r1,r4,lo(_sp); |
|
# R4 = _bss_start |
l.movhi r4,hi(_bss_start); |
l.ori r4,r4,lo(_bss_start); |
|
# R5 = _bss_end |
l.movhi r5,hi(_bss_end); |
l.ori r5,r5,lo(_bss_end); |
|
BSS_CLEAR: |
l.sw 0x0(r4),r0 # Write 0x00 to mem[r4] |
l.sfleu r4,r5 # SR[F] = (r4 < r5) |
l.addi r4, r4, 4 # r4 += 4 |
l.bf BSS_CLEAR # If SR[F] == 0, jump to BSS_CLEAR |
l.nop |
|
# Jump to debug agent |
l.j gdb_main |
l.nop |
|
.size vector_reset, .-vector_reset |
|
#------------------------------------------------------------- |
# VECTOR 0x200 - Fault / Illegal Instruction |
#------------------------------------------------------------- |
.org 0x200 |
vector_fault: |
|
# Save context |
asm_save_context |
|
# Arg 2 = Fault |
l.addi r4, r0, 1 |
|
l.j handle_exception |
l.nop |
|
.size vector_fault, .-vector_fault |
|
#------------------------------------------------------------- |
# VECTOR 0x300 - External Interrupt |
#------------------------------------------------------------- |
.org 0x300 |
vector_extint: |
|
# Save context |
asm_save_context |
|
# Arg 2 = Ext Int |
l.addi r4, r0, 2 |
|
l.j handle_exception |
l.nop |
|
.size vector_extint, .-vector_extint |
|
#------------------------------------------------------------- |
# VECTOR 0x400 - Syscall |
#------------------------------------------------------------- |
.org 0x400 |
vector_syscall: |
|
# Save context |
asm_save_context |
|
# Arg 2 = Syscall |
l.addi r4, r0, 3 |
|
l.j handle_exception |
l.nop |
|
.size vector_syscall, .-vector_syscall |
|
#------------------------------------------------------------- |
# VECTOR 0x600 - Trap |
#------------------------------------------------------------- |
.org 0x600 |
vector_trap: |
|
# Save context |
asm_save_context |
|
# Arg 2 = Trap |
l.addi r4, r0, 4 |
|
# Fall through... |
|
.size vector_trap, .-vector_trap |
|
#------------------------------------------------------------- |
# handle_exception: Common exception handling code |
#------------------------------------------------------------- |
handle_exception: |
|
# Copy stack pointer to arg1 |
l.add r3, r0, r1 |
|
# Jump to debug handler |
l.movhi r10,hi(gdb_exception); |
l.ori r10,r10,lo(gdb_exception); |
l.jalr r10 |
l.nop |
|
# Return value is stack pointer |
l.add r1, r0, r11 |
|
# Restore context |
asm_load_context |
|
.size handle_exception, .-handle_exception |
/sw/gdb_stub/exception.inc
0,0 → 1,157
#------------------------------------------------------------- |
# Context Stack Frame - 140 bytes / 35 words |
#------------------------------------------------------------- |
# 0: R0 |
# 4: R1 (SP) |
# 8: R2 |
# 12: R3 (ARG0) |
# 16: R4 |
# 20: R5 |
# 24: R6 |
# 28: R7 |
# 32: R8 |
# 36: R9 (LR) |
# 40: R10 |
# 44: R11 |
# 48: R12 |
# 52: R13 |
# 56: R14 |
# 60: R15 |
# 64: R16 |
# 68: R17 |
# 72: R18 |
# 76: R19 |
# 80: R20 |
# 84: R21 |
# 88: R22 |
# 92: R23 |
# 96: R24 |
# 100: R25 |
# 104: R26 |
# 108: R27 |
# 112: R28 |
# 116: R29 |
# 120: R30 |
# 124: R31 |
# 128: X |
# 132: EPC |
# 136: ESR |
#------------------------------------------------------------- |
|
#------------------------------------------------------------- |
# asm_save_context: |
#------------------------------------------------------------- |
.macro asm_save_context |
|
l.nop |
l.nop |
|
# Adjust SP (frame size is 140 + allow for 128 uncommitted in-use stack) |
l.addi r1, r1, -268 |
|
# Save register file to stack |
l.sw 124(r1), r31 |
l.sw 120(r1), r30 |
l.sw 116(r1), r29 |
l.sw 112(r1), r28 |
l.sw 108(r1), r27 |
l.sw 104(r1), r26 |
l.sw 100(r1), r25 |
l.sw 96(r1), r24 |
l.sw 92(r1), r23 |
l.sw 88(r1), r22 |
l.sw 84(r1), r21 |
l.sw 80(r1), r20 |
l.sw 76(r1), r19 |
l.sw 72(r1), r18 |
l.sw 68(r1), r17 |
l.sw 64(r1), r16 |
l.sw 60(r1), r15 |
l.sw 56(r1), r14 |
l.sw 52(r1), r13 |
l.sw 48(r1), r12 |
l.sw 44(r1), r11 |
l.sw 40(r1), r10 |
l.sw 36(r1), r9 |
l.sw 32(r1), r8 |
l.sw 28(r1), r7 |
l.sw 24(r1), r6 |
l.sw 20(r1), r5 |
l.sw 16(r1), r4 |
l.sw 12(r1), r3 |
l.sw 8(r1), r2 |
l.sw 0(r1), r0 |
|
# R10 = EPC |
l.mfspr r10, r0, 32 |
l.sw 132(r1), r10 |
|
# R10 = ESR |
l.mfspr r10, r0, 64 |
l.sw 136(r1), r10 |
|
# Stack pointer (R1) |
l.or r10, r0, r1 |
l.addi r10, r10, +268 |
l.sw 4(r1), r10 |
|
.endm |
|
#------------------------------------------------------------- |
# asm_load_context: |
#------------------------------------------------------------- |
.macro asm_load_context |
|
# Restore EPC (PC of non-exception code) |
l.lwz r10, 132(r1) |
|
# EPC = R10 |
l.mtspr r0,r10,32 |
|
# Restore ESR (SR of non-exception code) |
l.lwz r10, 136(r1) |
|
# ESR = R10 |
l.mtspr r0,r10,64 |
|
# Restore register set |
# r1/r1 already set |
l.lwz r2, 8(r1) |
l.lwz r3, 12(r1) |
l.lwz r4, 16(r1) |
l.lwz r5, 20(r1) |
l.lwz r6, 24(r1) |
l.lwz r7, 28(r1) |
l.lwz r8, 32(r1) |
l.lwz r9, 36(r1) |
l.lwz r10, 40(r1) |
l.lwz r11, 44(r1) |
l.lwz r12, 48(r1) |
l.lwz r13, 52(r1) |
l.lwz r14, 56(r1) |
l.lwz r15, 60(r1) |
l.lwz r16, 64(r1) |
l.lwz r17, 68(r1) |
l.lwz r18, 72(r1) |
l.lwz r19, 76(r1) |
l.lwz r20, 80(r1) |
l.lwz r21, 84(r1) |
l.lwz r22, 88(r1) |
l.lwz r23, 92(r1) |
l.lwz r24, 96(r1) |
l.lwz r25,100(r1) |
l.lwz r26,104(r1) |
l.lwz r27,108(r1) |
l.lwz r28,112(r1) |
l.lwz r29,116(r1) |
l.lwz r30,120(r1) |
l.lwz r31,124(r1) |
|
# Adjust SP past register set |
l.addi r1, r1, +268 |
|
# Return from interrupt (to restore PC & SR) |
l.rfe |
l.nop |
|
.endm |
/sw/gdb_stub/linker_script
0,0 → 1,53
GROUP("libgcc.a") |
|
MEMORY |
{ |
sram (rwx) : ORIGIN = 0x10000000, LENGTH = 8K |
} |
|
SECTIONS |
{ |
.text : |
{ |
_text_start = .; |
*(.text .text.*) /* remaining code */ |
*(.rodata) /* read-only data (constants) */ |
*(.rodata*) |
*(.rdata*) |
. = ALIGN(4); |
_text_end = .; |
} > sram |
|
.data : |
{ |
. = ALIGN(4); |
_data_start = .; |
|
*(.got.plt) *(.got) |
*(.shdata) |
*(.data .data.* .gnu.linkonce.d.*) |
. = ALIGN(16); |
. = ALIGN (8); |
*(.ram) |
*(.eh_frame) |
. = ALIGN (8); |
_edata = .; |
_data_end = .; |
} > sram |
|
.bss : |
{ |
. = ALIGN(4); |
_bss_start = . ; |
|
*(.bss*) |
*(COMMON) |
|
/* Allocate room for stack */ |
. = ALIGN(8) ; |
. += 1024 ; |
_sp = . - 16; |
|
_bss_end = .; |
} > sram |
} |
/sw/gdb_stub/gdb_hw.c
0,0 → 1,136
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source 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 Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include "mem_map.h" |
#include "gdb_hw.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define UART_RX_AVAIL (1<<0) |
#define UART_TX_AVAIL (1<<1) |
#define UART_RX_FULL (1<<2) |
#define UART_TX_BUSY (1<<3) |
#define UART_RX_ERROR (1<<4) |
|
// SR Register |
#define SPR_SR (17) |
#define SPR_SR_ICACHE_FLUSH (1 << 17) |
#define SPR_SR_DCACHE_FLUSH (1 << 18) |
|
#define MAX_RX_BUF 128 |
static char _rx_buf[MAX_RX_BUF]; |
static int _rx_head; |
static int _rx_tail; |
|
//----------------------------------------------------------------- |
// mfspr: Read from SPR |
//----------------------------------------------------------------- |
static inline unsigned long mfspr(unsigned long spr) |
{ |
unsigned long value; |
asm volatile ("l.mfspr\t\t%0,%1,0" : "=r" (value) : "r" (spr)); |
return value; |
} |
//----------------------------------------------------------------- |
// mtspr: Write to SPR |
//----------------------------------------------------------------- |
static inline void mtspr(unsigned long spr, unsigned long value) |
{ |
asm volatile ("l.mtspr\t\t%0,%1,0": : "r" (spr), "r" (value)); |
} |
//----------------------------------------------------------------- |
// gdb_pollrx: |
//----------------------------------------------------------------- |
void gdb_pollrx (void) |
{ |
if (UART_USR & UART_RX_AVAIL) |
{ |
_rx_buf[_rx_tail] = UART_UDR; |
|
if (++_rx_tail == MAX_RX_BUF) |
_rx_tail = 0; |
} |
} |
//----------------------------------------------------------------- |
// gdb_putchar: |
//----------------------------------------------------------------- |
void gdb_putchar (char c) |
{ |
UART_UDR = c; |
while (UART_USR & UART_TX_BUSY) |
gdb_pollrx(); |
} |
//------------------------------------------------------------- |
// gdb_putstr: |
//------------------------------------------------------------- |
void gdb_putstr(const char *str) |
{ |
while (*str) |
gdb_putchar(*str++); |
} |
//----------------------------------------------------------------- |
// gdb_getchar: |
//----------------------------------------------------------------- |
int gdb_getchar (void) |
{ |
int ch = -1; |
|
do |
{ |
gdb_pollrx(); |
|
if (_rx_head != _rx_tail) |
{ |
ch = _rx_buf[_rx_head]; |
|
if (++_rx_head == MAX_RX_BUF) |
_rx_head = 0; |
|
break; |
} |
} |
while (1); |
|
return ch; |
} |
//----------------------------------------------------------------- |
// gdb_flush_cache: |
//----------------------------------------------------------------- |
void gdb_flush_cache(void) |
{ |
mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_ICACHE_FLUSH | SPR_SR_DCACHE_FLUSH); |
} |
/sw/gdb_stub/gdb.c
0,0 → 1,554
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source 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 Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include "gdb_hw.h" |
#include "gdb.h" |
|
//----------------------------------------------------------------- |
// Defines |
//----------------------------------------------------------------- |
// Rx / Tx buffer max size |
#define MAX_BUF_SIZE 512 |
|
// OR1K exception reasons |
#define OR32_EXC_RESET 0 |
#define OR32_EXC_FAULT 1 |
#define OR32_EXC_INT 2 |
#define OR32_EXC_SYSCALL 3 |
#define OR32_EXC_BREAKPOINT 4 |
#define OR32_EXC_BUS_ERROR 6 |
|
#define OR32_SR_STEP 19 |
#define OR32_SR_DBGEN 20 |
|
#define GDB_SIGHUP 1 |
#define GDB_SIGINT 2 |
#define GDB_SIGTRAP 5 |
#define GDB_SIGSEGV 11 |
|
#define REG_SP 1 |
#define REG_ARG0 3 |
#define REG_ARG1 4 |
#define REG_PC 33 |
#define REG_SR 34 |
#define REG_NUM 35 |
|
//----------------------------------------------------------------- |
// Locals |
//----------------------------------------------------------------- |
static char _inbuffer[MAX_BUF_SIZE]; |
static char _outbuffer[MAX_BUF_SIZE]; |
static int _initial_trap; |
static const char _hex_char[] = "0123456789abcdef"; |
|
static unsigned int * (*syscall_handler)(unsigned int *registers); |
static unsigned int * (*irq_handler)(unsigned int *registers); |
|
//----------------------------------------------------------------- |
// gdb_atoi_hex: Convert from hex character to integer |
//----------------------------------------------------------------- |
static int gdb_atoi_hex(char ch) |
{ |
if (ch >= 'a' && ch <= 'f') |
return ch - 'a' + 10; |
else if (ch >= '0' && ch <= '9') |
return ch - '0'; |
else if (ch >= 'A' && ch <= 'F') |
return ch - 'A' + 10; |
return -1; |
} |
//----------------------------------------------------------------- |
// gdb_strcpy: String copy (avoid using any library functions) |
//----------------------------------------------------------------- |
static void gdb_strcpy(char *buf, const char *s) |
{ |
while (*s) |
*buf++ = *s++; |
*buf = 0; |
} |
//----------------------------------------------------------------- |
// gdb_mem2hex: Convert block of memory to ASCII |
//----------------------------------------------------------------- |
static char *gdb_mem2hex(unsigned char *mem, char *target, int count) |
{ |
while (count) |
{ |
*target++ = _hex_char[((*mem) >> 4) & 0xf]; |
*target++ = _hex_char[((*mem) >> 0) & 0xf]; |
mem++; |
count--; |
} |
|
*target = 0; |
return target; |
} |
//----------------------------------------------------------------- |
// gdb_hex2mem: Convert ASCII hex string to binary |
//----------------------------------------------------------------- |
static char *gdb_hex2mem(char *src, unsigned char *mem, int count) |
{ |
unsigned char ch; |
|
while (count) |
{ |
ch = gdb_atoi_hex(*src++) << 4; |
ch |= gdb_atoi_hex(*src++) << 0; |
|
*mem++ = ch; |
count--; |
} |
|
return (char *)mem; |
} |
//----------------------------------------------------------------- |
// gdb_gethexword: Convert ASCII hex word to integer |
//----------------------------------------------------------------- |
static int gdb_gethexword(char **s, unsigned int *val) |
{ |
int count = 0; |
|
*val = 0; |
|
while (**s) |
{ |
int hexval = gdb_atoi_hex(**s); |
if (hexval < 0) |
break; |
|
(*s)++; |
count++; |
|
*val = (*val << 4) | (hexval & 0xF); |
} |
|
return count; |
} |
//----------------------------------------------------------------- |
// gdb_send: Send GDB formatted packet ($buffer#checksum) |
//----------------------------------------------------------------- |
static void gdb_send(char *buffer) |
{ |
unsigned char checksum; |
int index; |
|
do |
{ |
checksum = 0; |
index = 0; |
|
// Start of packet |
gdb_putchar ('$'); |
|
// Payload (if any) |
while (buffer[index] != 0) |
{ |
gdb_putchar(buffer[index]); |
checksum += (unsigned char)buffer[index++]; |
} |
|
// Checksum |
gdb_putchar('#'); |
gdb_putchar(_hex_char[(checksum >> 4) & 0xF]); |
gdb_putchar(_hex_char[(checksum >> 0) & 0xF]); |
} |
while (gdb_getchar () != '+'); |
} |
//----------------------------------------------------------------- |
// gdb_recv: Wait for valid GDB packet ($cmd#checksum). |
// 'cmd' is returned |
//----------------------------------------------------------------- |
static char * gdb_recv(void) |
{ |
int found_start = 0; |
unsigned char checksum; |
unsigned char csum_rx; |
int index; |
char ch; |
|
while (1) |
{ |
ch = gdb_getchar(); |
|
// Start of packet indicator? |
if (ch == '$') |
{ |
found_start = 1; |
checksum = 0; |
csum_rx = 0; |
index = 0; |
} |
// Already received start of packet |
else if (found_start) |
{ |
// Found start of checksum |
if (ch == '#') |
break; |
|
if (index < (MAX_BUF_SIZE-1)) |
_inbuffer[index++] = ch; |
|
checksum = checksum + ch; |
} |
} |
_inbuffer[index++] = 0; |
|
// If command received without overflowing buffer |
if (index < MAX_BUF_SIZE) |
{ |
// Extract / wait for checksum |
ch = gdb_getchar(); |
csum_rx = gdb_atoi_hex (ch) << 4; |
ch = gdb_getchar (); |
csum_rx += gdb_atoi_hex (ch); |
|
// Valid checksum |
if (checksum == csum_rx) |
{ |
// Sequence number? |
if (_inbuffer[2] == ':') |
{ |
gdb_putchar('+'); |
gdb_putchar (_inbuffer[0]); |
gdb_putchar (_inbuffer[1]); |
|
return &_inbuffer[3]; |
} |
else |
{ |
// Simple Ack |
gdb_putchar('+'); |
|
return &_inbuffer[0]; |
} |
} |
else |
{ |
_inbuffer[0] = 0; |
|
return &_inbuffer[0]; |
} |
} |
else |
{ |
_inbuffer[0] = 0; |
|
return &_inbuffer[0]; |
} |
} |
//----------------------------------------------------------------- |
// gdb_exception |
//----------------------------------------------------------------- |
unsigned int * gdb_exception(unsigned int *registers, unsigned int reason) |
{ |
int sig_val; |
unsigned int len; |
unsigned int val; |
unsigned int regnum; |
char *str; |
char *ptr; |
int flush_caches = 0; |
|
switch (reason) |
{ |
case OR32_EXC_INT: |
sig_val = GDB_SIGINT; |
break; |
case OR32_EXC_BREAKPOINT: |
sig_val = GDB_SIGTRAP; |
break; |
case OR32_EXC_FAULT: |
sig_val = GDB_SIGSEGV; |
break; |
default: |
sig_val = GDB_SIGHUP; |
break; |
} |
|
// Exception due external interrupt |
if (reason == OR32_EXC_INT) |
{ |
if (irq_handler) |
return irq_handler(registers); |
} |
// Exception due to syscall instruction |
else if (reason == OR32_EXC_SYSCALL) |
{ |
// Get l.sys opcode |
unsigned int opcode = *((unsigned int*)(registers[REG_PC] - 4)); |
unsigned int sys_num = opcode & 0xFFFF; |
|
ptr = _outbuffer; |
switch (sys_num) |
{ |
//--------------------------------------------------- |
// l.sys 1 -> putchar(r3) |
//--------------------------------------------------- |
case 1: |
*ptr++ = 'O'; |
*ptr++ = _hex_char[(registers[REG_ARG0] >> 4) & 0xf]; |
*ptr++ = _hex_char[registers[REG_ARG0] & 0xf]; |
*ptr++ = 0; |
gdb_send (_outbuffer); |
|
return registers; |
//--------------------------------------------------- |
// l.sys 2 -> putstr(r3) |
//--------------------------------------------------- |
case 2: |
// Pointer to string |
str = (char*)registers[REG_ARG0]; |
len = 0; |
|
*ptr++ = 'O'; |
while (*str && (len < ((sizeof(_outbuffer)-2)/2))) |
{ |
*ptr++ = _hex_char[((*str) >> 4) & 0xf]; |
*ptr++ = _hex_char[((*str) >> 0) & 0xf]; |
str++; |
} |
*ptr++ = 0; |
gdb_send (_outbuffer); |
|
return registers; |
//--------------------------------------------------- |
// l.sys 3 -> exit(r3) |
//--------------------------------------------------- |
case 3: |
*ptr++ = 'W'; |
*ptr++ = _hex_char[(registers[REG_ARG0] >> 4) & 0xf]; |
*ptr++ = _hex_char[registers[REG_ARG0] & 0xf]; |
*ptr++ = 0; |
gdb_send (_outbuffer); |
|
// Remain in GDB stub... |
break; |
//--------------------------------------------------- |
// l.sys 4 -> set syscall_handler = r3 |
//--------------------------------------------------- |
case 4: |
syscall_handler = (void*)registers[REG_ARG0]; |
return registers; |
//--------------------------------------------------- |
// l.sys 5 -> set irq_handler = r3 |
//--------------------------------------------------- |
case 5: |
irq_handler = (void*)registers[REG_ARG0]; |
return registers; |
//--------------------------------------------------- |
// Default: User syscall |
//--------------------------------------------------- |
default: |
if (syscall_handler) |
return syscall_handler(registers); |
// Not supported |
else |
{ |
registers[REG_ARG0] = 0; |
return registers; |
} |
} |
} |
|
// Make sure debug enabled on return to user program |
registers[REG_SR] |= (1 << OR32_SR_DBGEN); |
|
// Send status response (signal type, PC & SP) |
if (!_initial_trap) |
{ |
ptr = _outbuffer; |
*ptr++ = 'T'; |
*ptr++ = _hex_char[(sig_val >> 4) & 0xf]; |
*ptr++ = _hex_char[sig_val & 0xf]; |
*ptr++ = _hex_char[(REG_PC >> 4) & 0xf]; |
*ptr++ = _hex_char[REG_PC & 0xf]; |
*ptr++ = ':'; |
ptr = gdb_mem2hex ((unsigned char *)®isters[REG_PC], ptr, 4); |
*ptr++ = ';'; |
*ptr++ = _hex_char[(REG_SP >> 4) & 0xf]; |
*ptr++ = _hex_char[REG_SP & 0xf]; |
*ptr++ = ':'; |
ptr = gdb_mem2hex ((unsigned char *)®isters[REG_SP], ptr, 4); |
*ptr++ = ';'; |
*ptr++ = 0; |
gdb_send (_outbuffer); |
} |
// Initial trap (jump to GDB stub) |
else |
{ |
sig_val = GDB_SIGHUP; |
_initial_trap = 0; |
} |
|
while (1) |
{ |
// Wait for request from GDB |
ptr = gdb_recv(); |
|
_outbuffer[0] = 0; |
switch (*ptr++) |
{ |
//--------------------------------------------------- |
// ? - Return signal value |
//--------------------------------------------------- |
case '?': |
_outbuffer[0] = 'S'; |
_outbuffer[1] = _hex_char[sig_val >> 4]; |
_outbuffer[2] = _hex_char[sig_val & 0xf]; |
_outbuffer[3] = 0; |
break; |
//--------------------------------------------------- |
// g - Return all registers |
//--------------------------------------------------- |
case 'g': |
ptr = gdb_mem2hex ((unsigned char *)registers, _outbuffer, REG_NUM * 4); |
break; |
//--------------------------------------------------- |
// G - Set all registers |
//--------------------------------------------------- |
case 'G': |
gdb_hex2mem (ptr, (unsigned char *)registers, REG_NUM * 4); |
gdb_strcpy (_outbuffer, "OK"); |
|
// Make sure debug enabled on return to user program |
registers[REG_SR] |= (1 << OR32_SR_DBGEN); |
break; |
//--------------------------------------------------- |
// p - Return a single register |
//--------------------------------------------------- |
case 'p': |
if (gdb_gethexword (&ptr, &val) && (val < REG_NUM)) |
ptr = gdb_mem2hex ((unsigned char *)®isters[val], _outbuffer, 4); |
else |
gdb_strcpy (_outbuffer, "E22"); |
break; |
//--------------------------------------------------- |
// P - Set a single register |
//--------------------------------------------------- |
case 'P': |
// Get register number |
if (gdb_gethexword (&ptr, ®num) && (*ptr++ == '=') && (regnum < REG_NUM)) |
{ |
// Get value to set register to |
gdb_gethexword(&ptr, &val); |
registers[regnum] = val; |
|
// If SR, make sure debug enabled on return to user program |
if (regnum == REG_SR) |
registers[regnum] |= (1 << OR32_SR_DBGEN); |
|
gdb_strcpy (_outbuffer, "OK"); |
} |
else |
gdb_strcpy (_outbuffer, "E22"); |
break; |
//--------------------------------------------------- |
// m - Read a block of memory |
//--------------------------------------------------- |
case 'm': |
if (gdb_gethexword (&ptr, &val) && (*ptr++ == ',') && |
gdb_gethexword (&ptr, &len) && (len < ((sizeof(_outbuffer)-1)/2))) |
{ |
if (!gdb_mem2hex((unsigned char *)val, _outbuffer, len)) |
gdb_strcpy (_outbuffer, "E14"); |
} |
else |
gdb_strcpy (_outbuffer,"E22"); |
break; |
//--------------------------------------------------- |
// M - Write a block of memory |
//--------------------------------------------------- |
case 'M': |
if (gdb_gethexword (&ptr, &val) && (*ptr++ == ',') && |
gdb_gethexword (&ptr, &len) && (*ptr++ == ':')) |
{ |
if (gdb_hex2mem(ptr, (unsigned char *)val, len)) |
gdb_strcpy (_outbuffer, "OK"); |
else |
gdb_strcpy (_outbuffer, "E14"); |
|
flush_caches = 1; |
} |
else |
gdb_strcpy (_outbuffer, "E22"); |
break; |
//--------------------------------------------------- |
// c - Continue from address (or last PC) |
//--------------------------------------------------- |
case 'c': |
// Optional PC |
if (gdb_gethexword (&ptr, &val)) |
registers[REG_PC] = val; |
|
if (flush_caches) |
gdb_flush_cache(); |
|
return registers; |
//--------------------------------------------------- |
// s - Step from address (or last PC) |
//--------------------------------------------------- |
case 's': |
// Optional PC |
if (gdb_gethexword (&ptr, &val)) |
registers[REG_PC] = val; |
|
// Set step in ESR and make sure debug is enabled |
registers[REG_SR] |= (1 << OR32_SR_STEP); |
registers[REG_SR] |= (1 << OR32_SR_DBGEN); |
|
if (flush_caches) |
gdb_flush_cache(); |
|
return registers; |
} |
|
// Send response to GDB host |
gdb_send (_outbuffer); |
} |
} |
//----------------------------------------------------------------- |
// gdb_main |
//----------------------------------------------------------------- |
void gdb_main(void) |
{ |
gdb_putstr("\r\nGDB Debug Agent\r\n"); |
|
// Jump to debugger |
_initial_trap = 1; |
asm volatile ("l.trap 0"); |
|
while (1) |
; |
} |
/sw/gdb_stub/makefile
0,0 → 1,73
############################################################################### |
# Configuration |
############################################################################### |
# Target |
TARGET ?= gdb_stub |
|
# Memory Layout |
MEMBASE ?= 0x10000000 |
MEMSIZE ?= 12384 |
MEMNAME ?= sram |
|
############################################################################### |
# Files |
############################################################################### |
INCLUDE_DIRS ?= |
OBJ = boot.o |
OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) |
OBJ+= $(OBJS) |
|
############################################################################### |
## Makefile |
############################################################################### |
|
# Tools |
OR1K_TCHAIN ?= or1k-elf |
CC = $(OR1K_TCHAIN)-gcc $(CFLAGS) |
AS = $(OR1K_TCHAIN)-as |
LD = $(OR1K_TCHAIN)-ld |
OBJDUMP = $(OR1K_TCHAIN)-objdump |
OBJCOPY = $(OR1K_TCHAIN)-objcopy |
|
# Options |
CFLAGS ?= |
CFLAGS += -Ttext $(MEMBASE) -Os -g -Wall |
CFLAGS += -msoft-div -msoft-float -msoft-mul -mno-ror -mno-cmov -mno-sext |
CFLAGS += -nostartfiles -nodefaultlibs -nostdlib -lgcc -L . |
ASFLAGS = |
LDFLAGS = |
|
LDSCRIPT= linker_script |
CFLAGS += -mno-delay -D__OR1K_NODELAY__ -D__OR1K__ |
ASFLAGS+= -mno-delay -Wa,--defsym,__OR1K_NODELAY__=1 |
CFLAGS += -T$(LDSCRIPT) |
SIMARGS += -n |
|
CFLAGS += -I. $(INCLUDE_DIRS) |
|
############################################################################### |
# Rules |
############################################################################### |
all: $(TARGET).elf lst bin |
|
clean: |
-rm $(OBJ) *.map *.lst *.hex *.txt *.elf $(TARGET).bin |
|
%.o : %.s |
$(CC) -c $(ASFLAGS) $< -o $@ |
|
%.o : %.c |
$(CC) -c $(CFLAGS) $< -o $@ |
|
$(TARGET).elf: $(OBJ) $(LDSCRIPT) makefile |
$(CC) $(LDFLAGS) $(LIBS) $(OBJ) -o $@ |
|
lst: $(TARGET).lst |
|
%.lst: $(TARGET).elf |
$(OBJDUMP) -h -d -S $< > $@ |
|
bin: $(TARGET).bin |
|
%.bin: %.elf |
$(OBJCOPY) -O binary $< $@ |