- refactored libsys into common
git-svn-id: http://moon:8086/svn/mips@198 a8ebac50-d88d-4704-bea3-6648445a41b3
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
# environment vaiables read:
|
||||
# BOARD = {ml402, denano, sim}
|
||||
# TLB = {no, yes}
|
||||
# ENDIANESS = {eb, el}
|
||||
# DEBUGGER = {gdb, mips, rom}
|
||||
|
||||
BOARD ?= ml402
|
||||
WITH_TLB ?= n
|
||||
ENDIANESS ?= eb
|
||||
DEBUGGER ?= mips
|
||||
|
||||
include $(MIPS_HOME)/make/mips_lib.mk
|
||||
|
||||
OBJS-ml402=$(addprefix $(BUILD_DIR)/, libsys.o xcpt.o syscalls.o cop0.o irq.o $(DBG_OBJ) console.o uart.o board.o gpio.o mips_ps2.o mips_gfx.o screen.o debugger.o)
|
||||
OBJS-denano=$(addprefix $(BUILD_DIR)/, libsys.o xcpt.o syscalls.o cop0.o irq.o $(DBG_OBJ) console.o uart.o board.o gpio.o debugger.o)
|
||||
OBJS-sim=$(addprefix $(BUILD_DIR)/, libsys.o xcpt.o syscalls.o cop0.o irq.o console.o uart.o board.o gpio.o)
|
||||
|
||||
all: $(BUILD_DIR) $(BUILD_DIR)/libsys.a
|
||||
|
||||
$(BUILD_DIR)/%.o : %.c
|
||||
$(CC) $(CFLAGS) -G 0 -c -o $@ $<
|
||||
|
||||
$(BUILD_DIR)/%.o : %.S
|
||||
$(CC) $(CFLAGS) -G 0 -c -o $@ $<
|
||||
|
||||
$(BUILD_DIR)/board.o : boards/$(BOARD)/board.c
|
||||
$(CC) $(CFLAGS) -G 0 -c -o $@ $<
|
||||
|
||||
$(BUILD_DIR)/debugger.o : boards/debugger.c
|
||||
$(CC) $(CFLAGS) -G 0 -c -o $@ $<
|
||||
|
||||
$(BUILD_DIR)/libsys.a: $(OBJS-$(BOARD))
|
||||
$(AR) -r $(BUILD_DIR)/libsys.a $(OBJS-$(BOARD))
|
||||
$(CC) $(CFLAGS) -G 0 -c -o $(BUILD_DIR)/startup.o asm/startup.S
|
||||
$(CC) $(CFLAGS) -G 0 -c -o $(BUILD_DIR)/kernel.o asm/kernel.S
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR)/*.a $(BUILD_DIR)/*.o > /dev/null
|
||||
|
||||
mrproper:
|
||||
rm -rf $(BUILD_DIR)
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
#include "regdef.h"
|
||||
#include "xcpt_asm.h"
|
||||
|
||||
.text
|
||||
.section .exc_vect, "ax"
|
||||
.align 2
|
||||
_xcpt_vector_tbl:
|
||||
j _xcpt_handler
|
||||
nop
|
||||
.text
|
||||
|
||||
LEAF(_xcpt_handler)
|
||||
.set noreorder
|
||||
.set noat
|
||||
/* Note: exceptions do not save and restore registers k0 and k1.
|
||||
* on entry, k1 = exception class.
|
||||
*/
|
||||
|
||||
/* allocate exception stack frame (on 8-byte boundary) */
|
||||
li k1, XCP_SIZE
|
||||
subu k1, sp, k1
|
||||
srl k1, 3 /* shift right/left -> alligned on boundary */
|
||||
sll k1, 3
|
||||
|
||||
/* save enough registers to get by */
|
||||
sw AT, XCP_AT(k1)
|
||||
sw v0, XCP_V0(k1)
|
||||
sw v1, XCP_V1(k1)
|
||||
sw a0, XCP_A0(k1)
|
||||
sw a1, XCP_A1(k1)
|
||||
sw a2, XCP_A2(k1)
|
||||
sw a3, XCP_A3(k1)
|
||||
sw sp, XCP_SP(k1)
|
||||
sw ra, XCP_RA(k1)
|
||||
|
||||
/* get coprocessor 0 exception state */
|
||||
mfc0 a0, CP0_CR
|
||||
mfc0 a1, CP0_SR
|
||||
mfc0 a2, CP0_BADDR
|
||||
mfc0 a3, CP0_EPC
|
||||
|
||||
/* we can safely use AT now */
|
||||
.set at
|
||||
|
||||
/* switch to using sp to point at exception frame */
|
||||
move sp, k1
|
||||
|
||||
/* nothing sensible to store for k0/k1, store zero */
|
||||
sw zero, XCP_K0(sp)
|
||||
sw zero, XCP_K1(sp)
|
||||
|
||||
/* we are now interruptible: dump all remaining state
|
||||
* into the exception stack frame.
|
||||
*/
|
||||
/* coprocessor exception state */
|
||||
sw a0, XCP_CR(sp)
|
||||
sw a1, XCP_SR(sp)
|
||||
sw a2, XCP_BADDR(sp)
|
||||
sw a3, XCP_EPC(sp)
|
||||
|
||||
/* mdhi and mdlo */
|
||||
mfhi v0
|
||||
mflo v1
|
||||
sw v0, XCP_MDHI(sp)
|
||||
sw v1, XCP_MDLO(sp)
|
||||
|
||||
/* Save all the other general registers.
|
||||
* We save zero, s0-s7 and s8 as well, as instruction emulators (e.g. FP
|
||||
* operations) and debuggers rely on all registers stored together in
|
||||
* well-defined structure.
|
||||
*/
|
||||
sw zero, XCP_ZERO(sp)
|
||||
sw t0, XCP_T0(sp)
|
||||
sw t1, XCP_T1(sp)
|
||||
sw t2, XCP_T2(sp)
|
||||
sw t3, XCP_T3(sp)
|
||||
sw t4, XCP_T4(sp)
|
||||
sw t5, XCP_T5(sp)
|
||||
sw t6, XCP_T6(sp)
|
||||
sw t7, XCP_T7(sp)
|
||||
sw s0, XCP_S0(sp)
|
||||
sw s1, XCP_S1(sp)
|
||||
sw s2, XCP_S2(sp)
|
||||
sw s3, XCP_S3(sp)
|
||||
sw s4, XCP_S4(sp)
|
||||
sw s5, XCP_S5(sp)
|
||||
sw s6, XCP_S6(sp)
|
||||
sw s7, XCP_S7(sp)
|
||||
sw t8, XCP_T8(sp)
|
||||
sw t9, XCP_T9(sp)
|
||||
sw gp, XCP_GP(sp)
|
||||
sw s8, XCP_S8(sp)
|
||||
|
||||
/* I don't know what the following does. [rb] */
|
||||
/* load our _gp pointer */
|
||||
# la gp, _gp
|
||||
|
||||
/* and call the C exception handler */
|
||||
move a0, sp # arg1 = &xcp
|
||||
subu sp, 16 # (arg save area)
|
||||
j _xcpt_call
|
||||
move ra, zero # fake return address
|
||||
|
||||
/* This strange call to _xcpt_call with zero return address is to
|
||||
* help exception-aware debuggers to trace back over the exception event.
|
||||
* We are basically interposing a bogus stackframe (with a zero return
|
||||
* address) between the C exception handler and the actual machine
|
||||
* exception.
|
||||
*/
|
||||
$xcptrest:
|
||||
.set noat
|
||||
add AT, sp, 16
|
||||
|
||||
/* at points to exception frame */
|
||||
$xcptrestother:
|
||||
/* restore all state */
|
||||
/* restore most general registers */
|
||||
lw t0, XCP_T0(AT)
|
||||
lw t1, XCP_T1(AT)
|
||||
lw t2, XCP_T2(AT)
|
||||
lw t3, XCP_T3(AT)
|
||||
lw t4, XCP_T4(AT)
|
||||
lw t5, XCP_T5(AT)
|
||||
lw t6, XCP_T6(AT)
|
||||
lw t7, XCP_T7(AT)
|
||||
lw s0, XCP_S0(AT)
|
||||
lw s1, XCP_S1(AT)
|
||||
lw s2, XCP_S2(AT)
|
||||
lw s3, XCP_S3(AT)
|
||||
lw s4, XCP_S4(AT)
|
||||
lw s5, XCP_S5(AT)
|
||||
lw s6, XCP_S6(AT)
|
||||
lw s7, XCP_S7(AT)
|
||||
lw t8, XCP_T8(AT)
|
||||
lw t9, XCP_T9(AT)
|
||||
lw gp, XCP_GP(AT)
|
||||
lw s8, XCP_S8(AT)
|
||||
|
||||
/* mdhi and mdlo */
|
||||
lw v0, XCP_MDHI(AT)
|
||||
lw v1, XCP_MDLO(AT)
|
||||
mthi v0
|
||||
mtlo v1
|
||||
|
||||
/* remaining general registers */
|
||||
lw a0, XCP_A0(AT)
|
||||
lw a1, XCP_A1(AT)
|
||||
lw a2, XCP_A2(AT)
|
||||
lw a3, XCP_A3(AT)
|
||||
lw ra, XCP_RA(AT)
|
||||
|
||||
/* restore the exception-time status register */
|
||||
.set noreorder
|
||||
lw v0, XCP_SR(AT)
|
||||
nop
|
||||
mtc0 v0, CP0_SR
|
||||
lw v1, XCP_V1(AT)
|
||||
lw v0, XCP_V0(AT)
|
||||
lw sp, XCP_SP(AT)
|
||||
|
||||
/* we are not uninterruptible and can use k1 safely */
|
||||
lw k1, XCP_EPC(AT)
|
||||
lw AT, XCP_AT(AT)
|
||||
mtc0 k1, CP0_EPC
|
||||
j k1
|
||||
rfe
|
||||
|
||||
.set reorder
|
||||
.set at
|
||||
END(_xcpt_handler)
|
||||
|
||||
|
||||
LEAF(_xcpt_call)
|
||||
/* on entry: a0 == &xcp */
|
||||
subu sp, 24
|
||||
sw ra, 16(sp)
|
||||
|
||||
/* punt out to _xcpt_deliver */
|
||||
jal _xcpt_deliver
|
||||
nop
|
||||
lw ra, 16(sp)
|
||||
addu sp, 24
|
||||
beqz ra, $xcptrest
|
||||
nop
|
||||
j ra
|
||||
nop
|
||||
END(_xcpt_call)
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 1985 MIPS Computer Systems, Inc.
|
||||
* Copyright (C) 1994, 95, 99, 2003 by Ralf Baechle
|
||||
* Copyright (C) 1990 - 1992, 1999 Silicon Graphics, Inc.
|
||||
*/
|
||||
#ifndef _ASM_REGDEF_H
|
||||
#define _ASM_REGDEF_H
|
||||
|
||||
/*
|
||||
* Symbolic register names for 32 bit ABI
|
||||
*/
|
||||
#define zero $0 /* wired zero */
|
||||
#define AT $1 /* assembler temp - uppercase because of ".set at" */
|
||||
#define v0 $2 /* return value */
|
||||
#define v1 $3
|
||||
#define a0 $4 /* argument registers */
|
||||
#define a1 $5
|
||||
#define a2 $6
|
||||
#define a3 $7
|
||||
#define t0 $8 /* caller saved */
|
||||
#define t1 $9
|
||||
#define t2 $10
|
||||
#define t3 $11
|
||||
#define t4 $12
|
||||
#define t5 $13
|
||||
#define t6 $14
|
||||
#define t7 $15
|
||||
#define s0 $16 /* callee saved */
|
||||
#define s1 $17
|
||||
#define s2 $18
|
||||
#define s3 $19
|
||||
#define s4 $20
|
||||
#define s5 $21
|
||||
#define s6 $22
|
||||
#define s7 $23
|
||||
#define t8 $24 /* caller saved */
|
||||
#define t9 $25
|
||||
#define jp $25 /* PIC jump register */
|
||||
#define k0 $26 /* kernel scratch */
|
||||
#define k1 $27
|
||||
#define gp $28 /* global pointer */
|
||||
#define sp $29 /* stack pointer */
|
||||
#define fp $30 /* frame pointer */
|
||||
#define s8 $30 /* same like fp! */
|
||||
#define ra $31 /* return address */
|
||||
|
||||
/* CP0 registers */
|
||||
#define CP0_INDEX $0 /* R3000 available */
|
||||
#define CP0_RANDOM $1 /* R3000 available */
|
||||
#define CP0_ENTRYLO $2 /* R3000 available */
|
||||
#define CP0_CONTEXT $4 /* R3000 available */
|
||||
#define CP0_BADDR $8 /* R3000 available */
|
||||
#define CP0_ENTRYHI $10 /* R3000 available */
|
||||
#define CP0_SR $12 /* R3000 available */
|
||||
#define CP0_CR $13 /* R3000 available */
|
||||
#define CP0_EPC $14 /* R3000 available */
|
||||
#define CP0_PRID $15 /* R3000 available */
|
||||
|
||||
/* Status register masks */
|
||||
#define SR_MASK_IEC 0x00000001
|
||||
#define SR_MASK_KUC 0x00000002
|
||||
#define SR_MASK_IEP 0x00000004
|
||||
#define SR_MASK_KUP 0x00000008
|
||||
#define SR_MASK_IEO 0x00000010
|
||||
#define SR_MASK_KUO 0x00000020
|
||||
#define SR_MASK_IM 0x0000FF00
|
||||
#define SR_MASK_DS 0x00FF0000
|
||||
#define SR_MASK_RE 0x01000000
|
||||
#define SR_MASK_CU 0xF0000000
|
||||
|
||||
/* Cause register masks */
|
||||
#define CR_MASK_EXC 0x0000007C
|
||||
#define CR_MASK_IP 0x0000FF00
|
||||
#define CR_MASK_CE 0x40000000
|
||||
#define CR_MASK_BD 0x80000000
|
||||
|
||||
#endif /* _ASM_REGDEF_H */
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "regdef.h"
|
||||
.file "startup.S"
|
||||
|
||||
.section .rodata
|
||||
.data
|
||||
argv0: .asciz "\"This-MIPS-program\""
|
||||
argv: .word argv0
|
||||
|
||||
.text
|
||||
.section .start, "ax"
|
||||
.extern board_init
|
||||
.align 2
|
||||
.set noreorder
|
||||
|
||||
_start:
|
||||
la sp, stack_ptr
|
||||
la gp, _gp
|
||||
nop
|
||||
|
||||
_zero_bss:
|
||||
# zero bss
|
||||
la $8, __bss_start
|
||||
la $9, _end
|
||||
$_zeroise:
|
||||
sw $0, 0($8)
|
||||
bne $8, $9, $_zeroise
|
||||
addiu $8, 4
|
||||
|
||||
_board_init:
|
||||
# Call board_init
|
||||
la k0, board_init
|
||||
jalr k0
|
||||
nop
|
||||
|
||||
# Set environment
|
||||
li a0, 1
|
||||
la a1, argv
|
||||
|
||||
# Call main
|
||||
la k0, main
|
||||
jalr k0
|
||||
nop
|
||||
|
||||
# Terminate after main returns
|
||||
_terminate:
|
||||
nop
|
||||
la t0, exit
|
||||
jalr t0
|
||||
move a0, v0
|
||||
|
||||
.set reorder
|
||||
@@ -0,0 +1,69 @@
|
||||
#ifndef XCPT_ASM_H
|
||||
#define XCPT_ASM_H
|
||||
|
||||
/* LEAF - declare leaf routine */
|
||||
#define LEAF(symbol) \
|
||||
.globl symbol; \
|
||||
.align 2; \
|
||||
.type symbol, @function; \
|
||||
.ent symbol, 0; \
|
||||
symbol: .frame sp, 0, ra
|
||||
|
||||
/* END - mark end of function */
|
||||
#define END(function) \
|
||||
.end function; \
|
||||
.size function, .-function
|
||||
|
||||
/* Exception stack size */
|
||||
#ifndef XCP_SIZE
|
||||
#define XCP_SIZE 65536
|
||||
#endif
|
||||
|
||||
/* save location for registers */
|
||||
#define XCP_SR 0
|
||||
#define XCP_CR 4
|
||||
#define XCP_EPC 8
|
||||
#define XCP_BADDR 12
|
||||
#define XCP_ZERO 16
|
||||
#define XCP_AT 20
|
||||
#define XCP_V0 24
|
||||
#define XCP_V1 28
|
||||
#define XCP_A0 32
|
||||
#define XCP_A1 36
|
||||
#define XCP_A2 40
|
||||
#define XCP_A3 44
|
||||
#define XCP_T0 48
|
||||
#define XCP_T1 52
|
||||
#define XCP_T2 56
|
||||
#define XCP_T3 60
|
||||
#define XCP_T4 64
|
||||
#define XCP_T5 68
|
||||
#define XCP_T6 72
|
||||
#define XCP_T7 76
|
||||
#define XCP_S0 80
|
||||
#define XCP_S1 84
|
||||
#define XCP_S2 88
|
||||
#define XCP_S3 92
|
||||
#define XCP_S4 96
|
||||
#define XCP_S5 100
|
||||
#define XCP_S6 104
|
||||
#define XCP_S7 108
|
||||
#define XCP_T8 112
|
||||
#define XCP_T9 116
|
||||
#define XCP_JP 116
|
||||
#define XCP_K0 120
|
||||
#define XCP_K1 124
|
||||
#define XCP_GP 128
|
||||
#define XCP_SP 132
|
||||
#define XCP_S8 136
|
||||
#define XCP_FP 136
|
||||
#define XCP_RA 140
|
||||
#define XCP_MDLO 144
|
||||
#define XCP_MDHI 148
|
||||
#define XCP_COUNT 152
|
||||
#define XCP_COMPARE 156
|
||||
#define XCP_PREV 160
|
||||
#define XCP_CLASS 164
|
||||
|
||||
|
||||
#endif /* XCPT_ASM_H */
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "board.h"
|
||||
#include "../debugger.h"
|
||||
#include "../../irq.h"
|
||||
#include "../../uart.h"
|
||||
#include "../../console.h"
|
||||
#include "../../asm/regdef.h"
|
||||
#include "../../syscalls.h"
|
||||
|
||||
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Uart
|
||||
// ---------------------------------------------------------------------------------
|
||||
const uart_if_t uart_if[] =
|
||||
{
|
||||
{(uint32_t*)SYS_UART0_STAT, (uint32_t*)SYS_UART0_DATA, (uint32_t*)SYS_UART0_BAUD},
|
||||
{(uint32_t*)SYS_UART1_STAT, (uint32_t*)SYS_UART1_DATA, (uint32_t*)SYS_UART1_BAUD}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Console
|
||||
// ---------------------------------------------------------------------------------
|
||||
const con_if_entry_t con_if_entry[] =
|
||||
{
|
||||
{0, "stdin", &uart_if[0], NULL, NULL, UART_readchar, NULL},
|
||||
{1, "stdout", &uart_if[0], NULL, NULL, NULL, UART_writechar},
|
||||
{2, "stderr", &uart_if[0], NULL, NULL, NULL, UART_writechar},
|
||||
{3, "UART-0", &uart_if[0], NULL, NULL, UART_readchar, UART_writechar},
|
||||
{4, "UART-1", &uart_if[1], NULL, NULL, UART_readchar, UART_writechar}
|
||||
};
|
||||
|
||||
const con_if_t con_if =
|
||||
{
|
||||
con_if_entry, ARRAYSIZE(con_if_entry)
|
||||
};
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
uint32_t volatile *pITIM_ctrl = (uint32_t*)SYS_ITIM_CTRL;
|
||||
|
||||
// Disable interrupts
|
||||
interrupt_global_disable();
|
||||
|
||||
// Disable timers
|
||||
*pITIM_ctrl = 0;
|
||||
|
||||
// Setup syscall support
|
||||
syscalls_init();
|
||||
|
||||
// Setup debugger
|
||||
debugger_init();
|
||||
|
||||
// Setup interrupt support
|
||||
interrupt_init();
|
||||
|
||||
// Enable interrupts
|
||||
interrupt_global_enable();
|
||||
}
|
||||
|
||||
void dbg_putchar(char c)
|
||||
{
|
||||
if (c == 0x0A)
|
||||
{
|
||||
UART_writechar(&uart_if[UART_DEBUGGER], 0x0D);
|
||||
}
|
||||
UART_writechar(&uart_if[UART_DEBUGGER], c);
|
||||
}
|
||||
|
||||
char dbg_getchar()
|
||||
{
|
||||
int c;
|
||||
|
||||
// busy read
|
||||
do
|
||||
{
|
||||
c = UART_readchar(&uart_if[UART_DEBUGGER]);
|
||||
|
||||
} while(c < 0);
|
||||
|
||||
return (char)c;
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: board.h
|
||||
* Author: jens
|
||||
*
|
||||
* Created on 8. Januar 2017, 11:33
|
||||
*/
|
||||
|
||||
#ifndef BOARD_H
|
||||
#define BOARD_H
|
||||
|
||||
#define CPU_FREQ_HZ 50000000
|
||||
#define UART_STDIO 0
|
||||
#define UART_DEBUGGER 1
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// IRQs
|
||||
// ---------------------------------------------------------
|
||||
#define SYS_INT_SOFT_0 0
|
||||
#define SYS_INT_SOFT_1 1
|
||||
#define SYS_INT_TIMER 2
|
||||
#define SYS_INT_UART0 3
|
||||
#define SYS_INT_UART1 4
|
||||
#define SYS_INT_FLASH 5
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Memory-mapped registers
|
||||
// ---------------------------------------------------------
|
||||
#ifndef SYS_IO_BASE
|
||||
#define SYS_IO_BASE 0xA0000000
|
||||
#endif
|
||||
#ifndef SDRAM_BASE
|
||||
#define SDRAM_BASE 0x40000000
|
||||
#endif
|
||||
#ifndef FLASH_BASE_IO
|
||||
#define FLASH_BASE_IO 0xA4000000
|
||||
#endif
|
||||
#ifndef FLASH_BASE_MEM
|
||||
#define FLASH_BASE_MEM 0x00000000
|
||||
#endif
|
||||
|
||||
// Backwards compatibility
|
||||
#define SYS_FLASH_IO FLASH_BASE_IO
|
||||
#define SYS_FLASH_MEM FLASH_BASE_MEM
|
||||
|
||||
// GPIO
|
||||
#define SYS_GPIO_0_BASE (SYS_IO_BASE + 0)
|
||||
#define SYS_GPIO_0_DATA (SYS_GPIO_0_BASE + 0)
|
||||
#define SYS_GPIO_0_DIR (SYS_GPIO_0_BASE + 4)
|
||||
|
||||
#define GPIO_0_DFLT_DIR 0x00000000 // Inputs
|
||||
#define GPIO_0_DFLT_DATA 0x00000000
|
||||
|
||||
#define GPIO_0_MASK_LED 0x000000FF
|
||||
#define GPIO_0_ALIGN_LED 0
|
||||
|
||||
#define GPIO_0_MASK_DIP 0x0000000F
|
||||
#define GPIO_0_ALIGN_DIP 8
|
||||
|
||||
#define GPIO_0_MASK_BTN 0x0000001F
|
||||
#define GPIO_0_ALIGN_BTN 24
|
||||
|
||||
// RTC
|
||||
#define SYS_TIMER_USEC (SYS_IO_BASE + 0x8)
|
||||
#define SYS_TIMER_SEC (SYS_IO_BASE + 0xC)
|
||||
|
||||
// TIMERs
|
||||
#define SYS_ITIM_CTRL (SYS_IO_BASE + 0x18)
|
||||
#define SYS_ITIM_STAT (SYS_IO_BASE + 0x1C)
|
||||
#define SYS_ITIM0_CNT (SYS_IO_BASE + 0x20)
|
||||
#define SYS_ITIM1_CNT (SYS_IO_BASE + 0x24)
|
||||
#define SYS_ITIM2_CNT (SYS_IO_BASE + 0x28)
|
||||
#define SYS_ITIM3_CNT (SYS_IO_BASE + 0x2C)
|
||||
#define SYS_ITIM0_CMP (SYS_IO_BASE + 0x30)
|
||||
#define SYS_ITIM1_CMP (SYS_IO_BASE + 0x34)
|
||||
#define SYS_ITIM2_CMP (SYS_IO_BASE + 0x38)
|
||||
#define SYS_ITIM3_CMP (SYS_IO_BASE + 0x3C)
|
||||
|
||||
// UARTs
|
||||
#define SYS_UART_BIT_TX_HALFFULL 0x00000001
|
||||
#define SYS_UART_BIT_TX_FULL 0x00000002
|
||||
#define SYS_UART_BIT_RX_HALFFULL 0x00000004
|
||||
#define SYS_UART_BIT_RX_FULL 0x00000008
|
||||
#define SYS_UART_BIT_RX_AVAIL 0x00000010
|
||||
#define SYS_UART_BIT_TX_INTEN 0x00000020
|
||||
#define SYS_UART_BIT_RX_INTEN 0x00000040
|
||||
#define SYS_UART_BIT_TX_IRQ 0x00000100
|
||||
#define SYS_UART_BIT_RX_IRQ 0x00000200
|
||||
#define SYS_UART_DATA SYS_UART0_DATA
|
||||
#define SYS_UART_STAT SYS_UART0_STAT
|
||||
#define SYS_UART_BAUD SYS_UART0_BAUD
|
||||
#define SYS_UART0_DATA (SYS_IO_BASE + 0x10000)
|
||||
#define SYS_UART0_STAT (SYS_IO_BASE + 0x10004)
|
||||
#define SYS_UART0_BAUD (SYS_IO_BASE + 0x10008)
|
||||
#define SYS_UART1_DATA (SYS_IO_BASE + 0x30000)
|
||||
#define SYS_UART1_STAT (SYS_IO_BASE + 0x30004)
|
||||
#define SYS_UART1_BAUD (SYS_IO_BASE + 0x30008)
|
||||
|
||||
// SPI
|
||||
#define SYS_SPI_STAT (SYS_IO_BASE + 0x20000)
|
||||
// Read
|
||||
#define SPI_STAT_CMDRDY (0x01)
|
||||
#define SPI_STAT_DINRDY (0x02)
|
||||
#define SPI_STAT_DOUTRDY (0x04)
|
||||
#define SPI_STAT_CMD_FIFO_FULL (0x0100)
|
||||
#define SPI_STAT_CMD_FIFO_EMPTY (0x0200)
|
||||
#define SPI_STAT_WRITE_FIFO_FULL (0x0400)
|
||||
#define SPI_STAT_WRITE_FIFO_EMPTY (0x0800)
|
||||
#define SPI_STAT_READ_FIFO_FULL (0x1000)
|
||||
#define SPI_STAT_READ_FIFO_EMPTY (0x2000)
|
||||
#define SPI_STAT_RX_VALID (0x4000)
|
||||
#define SPI_STAT_SPI_HOLD (0x8000)
|
||||
|
||||
// Write
|
||||
#define SPI_STAT_COMMIT (1)
|
||||
|
||||
#define SYS_SPI_XFER_SIZE (SYS_IO_BASE + 0x20004)
|
||||
#define SYS_SPI_DATA_SIZE (SYS_IO_BASE + 0x20008)
|
||||
#define SYS_SPI_DATA (SYS_IO_BASE + 0x2000C)
|
||||
#define SYS_SPI_CTRL (SYS_IO_BASE + 0x20010)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BOARD_H */
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "board.h"
|
||||
#include "../debugger.h"
|
||||
#include "../../irq.h"
|
||||
#include "../../uart.h"
|
||||
#include "../../console.h"
|
||||
#include "../../asm/regdef.h"
|
||||
#include "../../syscalls.h"
|
||||
|
||||
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Uart
|
||||
// ---------------------------------------------------------------------------------
|
||||
const uart_if_t uart_if[] =
|
||||
{
|
||||
{(uint32_t*)SYS_UART0_STAT, (uint32_t*)SYS_UART0_DATA, (uint32_t*)SYS_UART0_BAUD},
|
||||
{(uint32_t*)SYS_UART1_STAT, (uint32_t*)SYS_UART1_DATA, (uint32_t*)SYS_UART1_BAUD}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Console
|
||||
// ---------------------------------------------------------------------------------
|
||||
const con_if_entry_t con_if_entry[] =
|
||||
{
|
||||
{0, "stdin", &uart_if[0], NULL, NULL, UART_readchar, NULL},
|
||||
{1, "stdout", &uart_if[0], NULL, NULL, NULL, UART_writechar},
|
||||
{2, "stderr", &uart_if[0], NULL, NULL, NULL, UART_writechar},
|
||||
{3, "UART-0", &uart_if[0], NULL, NULL, UART_readchar, UART_writechar},
|
||||
{4, "UART-1", &uart_if[1], NULL, NULL, UART_readchar, UART_writechar}
|
||||
};
|
||||
|
||||
const con_if_t con_if =
|
||||
{
|
||||
con_if_entry, ARRAYSIZE(con_if_entry)
|
||||
};
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
uint32_t volatile *pITIM_ctrl = (uint32_t*)SYS_ITIM_CTRL;
|
||||
|
||||
// Disable interrupts
|
||||
interrupt_global_disable();
|
||||
|
||||
// Disable timers
|
||||
*pITIM_ctrl = 0;
|
||||
|
||||
// Setup syscall support
|
||||
syscalls_init();
|
||||
|
||||
// Setup debugger
|
||||
debugger_init();
|
||||
|
||||
// Setup interrupt support
|
||||
interrupt_init();
|
||||
|
||||
// Enable interrupts
|
||||
interrupt_global_enable();
|
||||
|
||||
}
|
||||
|
||||
void dbg_putchar(char c)
|
||||
{
|
||||
if (c == 0x0A)
|
||||
{
|
||||
UART_writechar(&uart_if[UART_DEBUGGER], 0x0D);
|
||||
}
|
||||
UART_writechar(&uart_if[UART_DEBUGGER], c);
|
||||
}
|
||||
|
||||
char dbg_getchar()
|
||||
{
|
||||
int c;
|
||||
|
||||
// busy read
|
||||
do
|
||||
{
|
||||
c = UART_readchar(&uart_if[UART_DEBUGGER]);
|
||||
|
||||
} while(c < 0);
|
||||
|
||||
return (char)c;
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: board.h
|
||||
* Author: jens
|
||||
*
|
||||
* Created on 8. Januar 2017, 11:33
|
||||
*/
|
||||
|
||||
#ifndef BOARD_H
|
||||
#define BOARD_H
|
||||
|
||||
#define CPU_FREQ_HZ 100000000
|
||||
#define UART_STDIO 0
|
||||
#define UART_DEBUGGER 0
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// IRQs
|
||||
// ---------------------------------------------------------
|
||||
#define SYS_INT_TIMER 7
|
||||
#define SYS_INT_PS2 6
|
||||
#define SYS_INT_EMAC 6
|
||||
#define SYS_INT_VGA 5
|
||||
#define SYS_INT_AC97 5
|
||||
#define SYS_INT_USB 4
|
||||
#define SYS_INT_UART 3
|
||||
#define SYS_INT_DBG 2
|
||||
#define SYS_INT_SOFT_1 1
|
||||
#define SYS_INT_SOFT_0 0
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Memory-mapped registers
|
||||
// ---------------------------------------------------------
|
||||
#ifndef SYS_IO_BASE
|
||||
#define SYS_IO_BASE 0xA0000000
|
||||
#endif
|
||||
#ifndef SDRAM_BASE
|
||||
#define SDRAM_BASE 0x40000000
|
||||
#endif
|
||||
#ifndef FLASH_BASE_IO
|
||||
#define FLASH_BASE_IO 0xA4000000
|
||||
#endif
|
||||
#ifndef FLASH_BASE_MEM
|
||||
#define FLASH_BASE_MEM 0x00000000
|
||||
#endif
|
||||
|
||||
// Backwards compatibility
|
||||
#define SYS_FLASH_IO FLASH_BASE_IO
|
||||
#define SYS_FLASH_MEM FLASH_BASE_MEM
|
||||
|
||||
// GPIO
|
||||
#define SYS_GPIO_0_BASE (SYS_IO_BASE + 0)
|
||||
#define SYS_GPIO_0_DATA (SYS_GPIO_0_BASE + 0)
|
||||
#define SYS_GPIO_0_DIR (SYS_GPIO_0_BASE + 4)
|
||||
|
||||
#define GPIO_0_DFLT_DIR 0x00000000 // Inputs
|
||||
#define GPIO_0_DFLT_DATA 0x00000000
|
||||
|
||||
#define GPIO_0_MASK_LED 0x000001FF
|
||||
#define GPIO_0_ALIGN_LED 0
|
||||
|
||||
#define GPIO_0_MASK_USB 0x00000003
|
||||
#define GPIO_0_ALIGN_USB 12
|
||||
#define GPIO_0_USB_RST 0x00000001
|
||||
#define GPIO_0_USB_INTEN 0x00000002
|
||||
|
||||
#define GPIO_0_MASK_AC97 0x00000001
|
||||
#define GPIO_0_ALIGN_AC97 15
|
||||
#define GPIO_0_AC97_INTEN 0x00000001
|
||||
|
||||
#define GPIO_0_MASK_DIP 0x000000FF
|
||||
#define GPIO_0_ALIGN_DIP 16
|
||||
|
||||
#define GPIO_0_MASK_BTN 0x0000001F
|
||||
#define GPIO_0_ALIGN_BTN 24
|
||||
|
||||
#define GPIO_0_MASK_MDIO 0x00000007
|
||||
#define GPIO_0_ALIGN_MDIO 29
|
||||
#define GPIO_0_MDIO_INTEN 0x00000001 // ToDo: better grouping
|
||||
#define GPIO_0_MDIO_RST 0x00000001
|
||||
#define GPIO_0_MDIO_MDC 0x00000002
|
||||
#define GPIO_0_MDIO_MDIO 0x00000004
|
||||
|
||||
|
||||
// RTC
|
||||
#define SYS_TIMER_USEC (SYS_IO_BASE + 0x8)
|
||||
#define SYS_TIMER_SEC (SYS_IO_BASE + 0xC)
|
||||
|
||||
// TIMERs
|
||||
#define SYS_ITIM_CTRL (SYS_IO_BASE + 0x18)
|
||||
#define SYS_ITIM_STAT (SYS_IO_BASE + 0x1C)
|
||||
#define SYS_ITIM0_CNT (SYS_IO_BASE + 0x20)
|
||||
#define SYS_ITIM1_CNT (SYS_IO_BASE + 0x24)
|
||||
#define SYS_ITIM2_CNT (SYS_IO_BASE + 0x28)
|
||||
#define SYS_ITIM3_CNT (SYS_IO_BASE + 0x2C)
|
||||
#define SYS_ITIM0_CMP (SYS_IO_BASE + 0x30)
|
||||
#define SYS_ITIM1_CMP (SYS_IO_BASE + 0x34)
|
||||
#define SYS_ITIM2_CMP (SYS_IO_BASE + 0x38)
|
||||
#define SYS_ITIM3_CMP (SYS_IO_BASE + 0x3C)
|
||||
|
||||
// UARTs
|
||||
#define SYS_UART_BIT_TX_HALFFULL 0x00000001
|
||||
#define SYS_UART_BIT_TX_FULL 0x00000002
|
||||
#define SYS_UART_BIT_RX_HALFFULL 0x00000004
|
||||
#define SYS_UART_BIT_RX_FULL 0x00000008
|
||||
#define SYS_UART_BIT_RX_AVAIL 0x00000010
|
||||
#define SYS_UART_BIT_TX_INTEN 0x00000020
|
||||
#define SYS_UART_BIT_RX_INTEN 0x00000040
|
||||
#define SYS_UART_BIT_TX_IRQ 0x00000100
|
||||
#define SYS_UART_BIT_RX_IRQ 0x00000200
|
||||
#define SYS_UART_DATA SYS_UART0_DATA
|
||||
#define SYS_UART_STAT SYS_UART0_STAT
|
||||
#define SYS_UART_BAUD SYS_UART0_BAUD
|
||||
#define SYS_UART0_DATA (SYS_IO_BASE + 0x10000)
|
||||
#define SYS_UART0_STAT (SYS_IO_BASE + 0x10004)
|
||||
#define SYS_UART0_BAUD (SYS_IO_BASE + 0x10008)
|
||||
#define SYS_UART1_DATA (SYS_IO_BASE + 0x10100)
|
||||
#define SYS_UART1_STAT (SYS_IO_BASE + 0x10104)
|
||||
#define SYS_UART1_BAUD (SYS_IO_BASE + 0x10108)
|
||||
|
||||
// PS2s
|
||||
#define SYS_PS2_BIT_TX_EMPTY 0x00000001
|
||||
#define SYS_PS2_BIT_RX_AVAIL 0x00000004
|
||||
#define SYS_PS2_BIT_PIN_CLOCK 0x00000008
|
||||
#define SYS_PS2_BIT_PIN_DATA 0x00000010
|
||||
#define SYS_PS2_BIT_TX_INTEN 0x00000020
|
||||
#define SYS_PS2_BIT_RX_INTEN 0x00000040
|
||||
#define SYS_PS2_BIT_TX_IRQ 0x00000100
|
||||
#define SYS_PS2_BIT_RX_IRQ 0x00000200
|
||||
#define SYS_PS2_BIT_RX_ERR_PAR 0x00000800
|
||||
#define SYS_PS2_BIT_RX_ERR_FLAG 0x00008000
|
||||
#define SYS_PS2_0_DATA (SYS_IO_BASE + 0x10200)
|
||||
#define SYS_PS2_0_STAT (SYS_IO_BASE + 0x10204)
|
||||
#define SYS_PS2_1_DATA (SYS_IO_BASE + 0x10300)
|
||||
#define SYS_PS2_1_STAT (SYS_IO_BASE + 0x10304)
|
||||
|
||||
// USB
|
||||
#define SYS_USB_DATA (SYS_IO_BASE + 0x20000)
|
||||
#define SYS_USB_MBX (SYS_IO_BASE + 0x20004)
|
||||
#define SYS_USB_ADDR (SYS_IO_BASE + 0x20008)
|
||||
#define SYS_USB_STATUS (SYS_IO_BASE + 0x2000C)
|
||||
|
||||
// VGA
|
||||
#define SYS_VGA_CTRL (SYS_IO_BASE + 0x30000) // R/W
|
||||
#define SYS_VGA_BIT_CGRDY 0x00000001 // RO
|
||||
#define SYS_VGA_BIT_MSTEN 0x00000002 // R/W
|
||||
#define SYS_VGA_BIT_BUFCHG_INTEN 0x00000004 // RO
|
||||
#define SYS_VGA_BIT_BUFCHG_FLAG 0x00000008 // RO
|
||||
#define SYS_VGA_BIT_CLRSCR 0x00000010 // WO
|
||||
#define SYS_VGA_BIT_CLRLINE 0x00000020 // WO
|
||||
#define SYS_VGA_BIT_BLIT_REQ 0x00000100 // R/W
|
||||
#define SYS_VGA_BIT_BLIT_BSY 0x00000100 // R/W
|
||||
#define SYS_VGA_BIT_BLIT_FIN 0x00000200 // R/W
|
||||
#define SYS_VGA_BIT_BLIT_FIN_ACK 0x00000200 // R/W
|
||||
#define SYS_VGA_BIT_BLIT_FIN_INTEN 0x00000400 // R/W
|
||||
#define SYS_VGA_BIT_BLIT_EMPTY 0x00000800 // R/W
|
||||
#define SYS_VGA_BIT_BLIT_EMPTY_ACK 0x00000800 // R/W
|
||||
#define SYS_VGA_BIT_BLIT_EMPTY_INTEN 0x00001000 // R/W
|
||||
#define SYS_VGA_BIT_BLIT_OP_CONSTCOL 0x00010000 // R/W
|
||||
#define SYS_VGA_BIT_BLIT_ACTIVE 0x80000000 // RO
|
||||
#define SYS_VGA_ASCII (SYS_IO_BASE + 0x30004) // R/W
|
||||
#define SYS_VGA_POSX (SYS_IO_BASE + 0x30008) // R/W
|
||||
#define SYS_VGA_POSY (SYS_IO_BASE + 0x3000C) // R/W
|
||||
#define SYS_VGA_CGCOL (SYS_IO_BASE + 0x30010) // R/W
|
||||
#define SYS_VGA_RES (SYS_IO_BASE + 0x30014) // RO
|
||||
#define SYS_VGA_FB_FRONT (SYS_IO_BASE + 0x30018) // R/W
|
||||
#define SYS_VGA_FB_BACK (SYS_IO_BASE + 0x3001C) // R/W
|
||||
|
||||
#define SYS_VGA_BLIT_SRC0_ADDR (SYS_IO_BASE + 0x30020) // R/W
|
||||
#define SYS_VGA_BLIT_SRC0_DIMX (SYS_IO_BASE + 0x30024) // R/W
|
||||
#define SYS_VGA_BLIT_SRC1_ADDR (SYS_IO_BASE + 0x30030) // R/W
|
||||
#define SYS_VGA_BLIT_SRC1_DIMX (SYS_IO_BASE + 0x30034) // R/W
|
||||
#define SYS_VGA_BLIT_DST_ADDR (SYS_IO_BASE + 0x30040) // R/W
|
||||
#define SYS_VGA_BLIT_DST_DIMX (SYS_IO_BASE + 0x30044) // R/W
|
||||
#define SYS_VGA_BLIT_NX (SYS_IO_BASE + 0x30050) // R/W
|
||||
#define SYS_VGA_BLIT_NY (SYS_IO_BASE + 0x30054) // R/W
|
||||
#define SYS_VGA_BLIT_COLOR (SYS_IO_BASE + 0x30058) // R/W
|
||||
|
||||
// AC'97
|
||||
#define SYS_AC97_STAT (SYS_IO_BASE + 0x40000)
|
||||
#define SYS_AC97_CTRL (SYS_IO_BASE + 0x40000)
|
||||
#define SYS_AC97_ACSTAT (SYS_IO_BASE + 0x40400)
|
||||
#define SYS_AC97_ACCTRL (SYS_IO_BASE + 0x40600)
|
||||
#define SYS_AC97_PCM (SYS_IO_BASE + 0x40800)
|
||||
#define SYS_AC97_WAVIN SYS_AC97_PCM
|
||||
#define SYS_AC97_WAVOUT SYS_AC97_PCM
|
||||
|
||||
// Ethernet MAC
|
||||
#define SYS_EMAC_RX_CTRL (SYS_IO_BASE + 0x50000)
|
||||
#define EMAC_RX_CTRL_RESET (1 << 31)
|
||||
#define EMAC_RX_CTRL_GIGABIT (1 << 30)
|
||||
#define EMAC_RX_CTRL_FCS_CHECK (1 << 29)
|
||||
#define EMAC_RX_CTRL_PROMISCIOUS (1 << 23)
|
||||
#define EMAC_RX_CTRL_PKT_REQ (1 << 17)
|
||||
#define EMAC_RX_CTRL_PKT_FREE (1 << 16)
|
||||
#define EMAC_RX_CTRL_INTEN (1 << 4)
|
||||
|
||||
#define SYS_EMAC_RX_STAT SYS_EMAC_RX_CTRL
|
||||
#define EMAC_RX_STAT_RESET (1 << 31)
|
||||
#define EMAC_RX_STAT_GIGABIT (1 << 30)
|
||||
#define EMAC_RX_STAT_FCS_CHECK (1 << 29)
|
||||
#define EMAC_RX_STAT_PROMISCIOUS (1 << 23)
|
||||
#define EMAC_RX_STAT_PKT_BCAST (1 << 19)
|
||||
#define EMAC_RX_STAT_PKT_MACOK (1 << 18)
|
||||
#define EMAC_RX_STAT_PKT_VALID (1 << 17)
|
||||
#define EMAC_RX_STAT_PKT_AVAIL (1 << 16)
|
||||
#define EMAC_RX_STAT_INTEN (1 << 4)
|
||||
|
||||
#define SYS_EMAC_RX_SIZE (SYS_IO_BASE + 0x50004)
|
||||
|
||||
#define SYS_EMAC_TX_CTRL (SYS_IO_BASE + 0x50008)
|
||||
#define EMAC_TX_CTRL_RESET (1 << 31)
|
||||
#define EMAC_TX_CTRL_GIGABIT (1 << 30)
|
||||
#define EMAC_TX_CTRL_FCS_APPEND (1 << 29)
|
||||
#define EMAC_TX_CTRL_PKT_ALLOC (1 << 17)
|
||||
#define EMAC_TX_CTRL_PKT_COMMIT (1 << 16)
|
||||
#define EMAC_TX_CTRL_INTEN (1 << 4)
|
||||
|
||||
#define SYS_EMAC_TX_STAT SYS_EMAC_TX_CTRL
|
||||
#define EMAC_TX_STAT_RESET (1 << 31)
|
||||
#define EMAC_TX_STAT_GIGABIT (1 << 30)
|
||||
#define EMAC_TX_STAT_FCS_APPEND (1 << 29)
|
||||
#define EMAC_TX_STAT_PKT_DONE (1 << 24)
|
||||
#define EMAC_TX_STAT_PKT_ALLOC_BSY (1 << 17)
|
||||
#define EMAC_TX_STAT_PKT_ARMED (1 << 16)
|
||||
#define EMAC_TX_STAT_INTEN (1 << 4)
|
||||
|
||||
#define SYS_EMAC_TX_SIZE (SYS_IO_BASE + 0x5000C)
|
||||
#define SYS_EMAC_MADDR (SYS_IO_BASE + 0x50018)
|
||||
#define SYS_EMAC_MADDR_0 SYS_EMAC_MADDR_0
|
||||
#define SYS_EMAC_MADDR_1 (SYS_IO_BASE + 0x5001C)
|
||||
|
||||
#define SYS_EMAC_DATA (SYS_IO_BASE + 0x58000)
|
||||
#define SYS_EMAC_RX_DATA SYS_EMAC_DATA
|
||||
#define SYS_EMAC_TX_DATA SYS_EMAC_DATA
|
||||
#define SYS_EMAC_DATA_CACHED (SYS_IO_BASE + 0x10008000)
|
||||
|
||||
// Sync. SRAM
|
||||
#define SYS_SSRAM_IO 0xA8000000
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BOARD_H */
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "board.h"
|
||||
#include "../../irq.h"
|
||||
#include "../../uart.h"
|
||||
#include "../../console.h"
|
||||
#include "../../asm/regdef.h"
|
||||
#include "../../syscalls.h"
|
||||
|
||||
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Uart
|
||||
// ---------------------------------------------------------------------------------
|
||||
const uart_if_t uart_if[] =
|
||||
{
|
||||
{(uint32_t*)SYS_UART0_STAT, (uint32_t*)SYS_UART0_DATA, (uint32_t*)SYS_UART0_BAUD},
|
||||
{(uint32_t*)SYS_UART1_STAT, (uint32_t*)SYS_UART1_DATA, (uint32_t*)SYS_UART1_BAUD}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Console
|
||||
// ---------------------------------------------------------------------------------
|
||||
const con_if_entry_t con_if_entry[] =
|
||||
{
|
||||
{0, "stdin", &uart_if[0], NULL, NULL, UART_readchar, NULL},
|
||||
{1, "stdout", &uart_if[0], NULL, NULL, NULL, UART_writechar},
|
||||
{2, "stderr", &uart_if[0], NULL, NULL, NULL, UART_writechar},
|
||||
{3, "UART-0", &uart_if[0], NULL, NULL, UART_readchar, UART_writechar},
|
||||
{4, "UART-1", &uart_if[1], NULL, NULL, UART_readchar, UART_writechar}
|
||||
};
|
||||
|
||||
const con_if_t con_if =
|
||||
{
|
||||
con_if_entry, ARRAYSIZE(con_if_entry)
|
||||
};
|
||||
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
uint32_t volatile *pITIM_ctrl = (uint32_t*)SYS_ITIM_CTRL;
|
||||
|
||||
// Disable interrupts
|
||||
interrupt_global_disable();
|
||||
|
||||
// Disable timers
|
||||
*pITIM_ctrl = 0;
|
||||
|
||||
// Setup syscall support
|
||||
syscalls_init();
|
||||
|
||||
// Setup interrupt support
|
||||
interrupt_init();
|
||||
|
||||
// Enable interrupts
|
||||
interrupt_global_enable();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: board.h
|
||||
* Author: jens
|
||||
*
|
||||
* Created on 8. Januar 2017, 11:33
|
||||
*/
|
||||
|
||||
#ifndef BOARD_H
|
||||
#define BOARD_H
|
||||
|
||||
#define CPU_FREQ_HZ 100000000
|
||||
#define UART_STDIO 0
|
||||
#define UART_DEBUGGER 1
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// IRQs
|
||||
// ---------------------------------------------------------
|
||||
#define SYS_INT_SOFT_0 0
|
||||
#define SYS_INT_SOFT_1 1
|
||||
#define SYS_INT_TIMER 2
|
||||
#define SYS_INT_UART0 3
|
||||
#define SYS_INT_UART1 4
|
||||
#define SYS_INT_FLASH 5
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Memory-mapped registers
|
||||
// ---------------------------------------------------------
|
||||
#ifndef SYS_IO_BASE
|
||||
#define SYS_IO_BASE 0xA0000000
|
||||
#endif
|
||||
#ifndef SDRAM_BASE
|
||||
#define SDRAM_BASE 0x40000000
|
||||
#endif
|
||||
#ifndef FLASH_BASE_IO
|
||||
#define FLASH_BASE_IO 0xA4000000
|
||||
#endif
|
||||
#ifndef FLASH_BASE_MEM
|
||||
#define FLASH_BASE_MEM 0x00000000
|
||||
#endif
|
||||
|
||||
// Backwards compatibility
|
||||
#define SYS_FLASH_IO FLASH_BASE_IO
|
||||
#define SYS_FLASH_MEM FLASH_BASE_MEM
|
||||
|
||||
// GPIO
|
||||
#define SYS_GPIO_0_BASE (SYS_IO_BASE + 0)
|
||||
#define SYS_GPIO_0_DATA (SYS_GPIO_0_BASE + 0)
|
||||
#define SYS_GPIO_0_DIR (SYS_GPIO_0_BASE + 4)
|
||||
|
||||
#define GPIO_0_DFLT_DIR 0x00000000 // Inputs
|
||||
#define GPIO_0_DFLT_DATA 0x00000000
|
||||
|
||||
#define GPIO_0_MASK_LED 0x000000FF
|
||||
#define GPIO_0_ALIGN_LED 0
|
||||
|
||||
#define GPIO_0_MASK_DIP 0x0000000F
|
||||
#define GPIO_0_ALIGN_DIP 8
|
||||
|
||||
#define GPIO_0_MASK_BTN 0x0000001F
|
||||
#define GPIO_0_ALIGN_BTN 24
|
||||
|
||||
// RTC
|
||||
#define SYS_TIMER_USEC (SYS_IO_BASE + 0x8)
|
||||
#define SYS_TIMER_SEC (SYS_IO_BASE + 0xC)
|
||||
|
||||
// TIMERs
|
||||
#define SYS_ITIM_CTRL (SYS_IO_BASE + 0x18)
|
||||
#define SYS_ITIM_STAT (SYS_IO_BASE + 0x1C)
|
||||
#define SYS_ITIM0_CNT (SYS_IO_BASE + 0x20)
|
||||
#define SYS_ITIM1_CNT (SYS_IO_BASE + 0x24)
|
||||
#define SYS_ITIM2_CNT (SYS_IO_BASE + 0x28)
|
||||
#define SYS_ITIM3_CNT (SYS_IO_BASE + 0x2C)
|
||||
#define SYS_ITIM0_CMP (SYS_IO_BASE + 0x30)
|
||||
#define SYS_ITIM1_CMP (SYS_IO_BASE + 0x34)
|
||||
#define SYS_ITIM2_CMP (SYS_IO_BASE + 0x38)
|
||||
#define SYS_ITIM3_CMP (SYS_IO_BASE + 0x3C)
|
||||
|
||||
// UARTs
|
||||
#define SYS_UART_BIT_TX_HALFFULL 0x00000001
|
||||
#define SYS_UART_BIT_TX_FULL 0x00000002
|
||||
#define SYS_UART_BIT_RX_HALFFULL 0x00000004
|
||||
#define SYS_UART_BIT_RX_FULL 0x00000008
|
||||
#define SYS_UART_BIT_RX_AVAIL 0x00000010
|
||||
#define SYS_UART_BIT_TX_INTEN 0x00000020
|
||||
#define SYS_UART_BIT_RX_INTEN 0x00000040
|
||||
#define SYS_UART_BIT_TX_IRQ 0x00000100
|
||||
#define SYS_UART_BIT_RX_IRQ 0x00000200
|
||||
#define SYS_UART_DATA SYS_UART0_DATA
|
||||
#define SYS_UART_STAT SYS_UART0_STAT
|
||||
#define SYS_UART_BAUD SYS_UART0_BAUD
|
||||
#define SYS_UART0_DATA (SYS_IO_BASE + 0x10000)
|
||||
#define SYS_UART0_STAT (SYS_IO_BASE + 0x10004)
|
||||
#define SYS_UART0_BAUD (SYS_IO_BASE + 0x10008)
|
||||
#define SYS_UART1_DATA (SYS_IO_BASE + 0x30000)
|
||||
#define SYS_UART1_STAT (SYS_IO_BASE + 0x30004)
|
||||
#define SYS_UART1_BAUD (SYS_IO_BASE + 0x30008)
|
||||
|
||||
// SPI
|
||||
#define SYS_SPI_STAT (SYS_IO_BASE + 0x20000)
|
||||
// Read
|
||||
#define SPI_STAT_CMDRDY (0x01)
|
||||
#define SPI_STAT_DINRDY (0x02)
|
||||
#define SPI_STAT_DOUTRDY (0x04)
|
||||
#define SPI_STAT_CMD_FIFO_FULL (0x0100)
|
||||
#define SPI_STAT_CMD_FIFO_EMPTY (0x0200)
|
||||
#define SPI_STAT_WRITE_FIFO_FULL (0x0400)
|
||||
#define SPI_STAT_WRITE_FIFO_EMPTY (0x0800)
|
||||
#define SPI_STAT_READ_FIFO_FULL (0x1000)
|
||||
#define SPI_STAT_READ_FIFO_EMPTY (0x2000)
|
||||
#define SPI_STAT_RX_VALID (0x4000)
|
||||
#define SPI_STAT_SPI_HOLD (0x8000)
|
||||
|
||||
// Write
|
||||
#define SPI_STAT_COMMIT (1)
|
||||
|
||||
#define SYS_SPI_XFER_SIZE (SYS_IO_BASE + 0x20004)
|
||||
#define SYS_SPI_DATA_SIZE (SYS_IO_BASE + 0x20008)
|
||||
#define SYS_SPI_DATA (SYS_IO_BASE + 0x2000C)
|
||||
#define SYS_SPI_CTRL (SYS_IO_BASE + 0x20010)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BOARD_H */
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "console.h"
|
||||
|
||||
extern const con_if_t con_if;
|
||||
|
||||
// Funcs
|
||||
con_if_entry_t const* con_getInterface(int file)
|
||||
{
|
||||
con_if_entry_t const *result = NULL;
|
||||
for (int i=0; i < con_if.length; i++)
|
||||
{
|
||||
if (file == con_if.con_if_entry[i].fd)
|
||||
{
|
||||
result = &con_if.con_if_entry[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
con_if_entry_t const* con_getInterfaceByName(char const *pName)
|
||||
{
|
||||
void const *result = NULL;
|
||||
for (int i=0; i < con_if.length; i++)
|
||||
{
|
||||
if (!strcmp(pName, con_if.con_if_entry[i].pName))
|
||||
{
|
||||
result = &con_if.con_if_entry[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void const* con_getInstanceByName(char const *pName)
|
||||
{
|
||||
void const *result = NULL;
|
||||
for (int i=0; i < con_if.length; i++)
|
||||
{
|
||||
if (!strcmp(pName, con_if.con_if_entry[i].pName))
|
||||
{
|
||||
result = con_if.con_if_entry[i].pInst;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int con_open(char const *pName)
|
||||
{
|
||||
if(pName)
|
||||
{
|
||||
for (int i=0; i < con_if.length; i++)
|
||||
{
|
||||
if (!strcmp(pName, con_if.con_if_entry->pName))
|
||||
{
|
||||
if (con_if.con_if_entry->openFunc)
|
||||
{
|
||||
con_if.con_if_entry->openFunc(&con_if.con_if_entry[i].pInst);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int con_close(int fd)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void con_flush(int fd)
|
||||
{
|
||||
int c;
|
||||
con_if_entry_t const *pIF = con_getInterface(fd);
|
||||
|
||||
if (pIF && pIF->readchar)
|
||||
{
|
||||
do
|
||||
{
|
||||
c = pIF->readchar(pIF->pInst);
|
||||
|
||||
} while(c > 0);
|
||||
}
|
||||
}
|
||||
|
||||
int con_readchar(con_if_entry_t const *pIF)
|
||||
{
|
||||
int c = -1;
|
||||
if (pIF && pIF->readchar)
|
||||
{
|
||||
// busy read
|
||||
do
|
||||
{
|
||||
c = pIF->readchar(pIF->pInst);
|
||||
|
||||
} while(c < 0);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void con_writechar(con_if_entry_t const *pIF, char c)
|
||||
{
|
||||
if (pIF && pIF->writechar)
|
||||
{
|
||||
pIF->writechar(pIF->pInst, c);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
int readchar(int fd)
|
||||
{
|
||||
return con_readchar(con_getInterface(fd));
|
||||
}
|
||||
|
||||
void writechar(int fd, char c)
|
||||
{
|
||||
con_writechar(con_getInterface(fd), c);
|
||||
}
|
||||
|
||||
void _putchar(int fd, char c)
|
||||
{
|
||||
if (c == 0x0A)
|
||||
{
|
||||
writechar(fd, 0x0D);
|
||||
}
|
||||
writechar(fd, c);
|
||||
}
|
||||
|
||||
char _getchar()
|
||||
{
|
||||
return readchar(0);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: console.h
|
||||
* Author: jens
|
||||
*
|
||||
* Created on 8. Januar 2017, 14:25
|
||||
*/
|
||||
|
||||
#ifndef CONSOLE_H
|
||||
#define CONSOLE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int (*read_func_t)(void const *pInst);
|
||||
typedef void (*write_func_t)(void const *pInst, char c);
|
||||
typedef void (*open_func_t)(void const *pInst);
|
||||
typedef void (*close_func_t)(void const *pInst);
|
||||
|
||||
typedef struct _scon_if_entry_t
|
||||
{
|
||||
int fd;
|
||||
char const *pName;
|
||||
void const *pInst;
|
||||
open_func_t openFunc;
|
||||
close_func_t closeFunc;
|
||||
read_func_t readchar;
|
||||
write_func_t writechar;
|
||||
} con_if_entry_t;
|
||||
|
||||
typedef struct _scon_if_t
|
||||
{
|
||||
con_if_entry_t const *con_if_entry;
|
||||
size_t length;
|
||||
} con_if_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
// ---------------------------------------------------------------------------------
|
||||
int con_open(char const *pName);
|
||||
int con_close(int fd);
|
||||
void con_flush(int file);
|
||||
con_if_entry_t const* con_getInterface(int file);
|
||||
con_if_entry_t const* con_getInterfaceByName(char const *pName);
|
||||
void const* con_getInstanceByName(char const *pName);
|
||||
int con_readchar(con_if_entry_t const *pIF);
|
||||
void con_writechar(con_if_entry_t const *pIF, char c);
|
||||
|
||||
int readchar(int file);
|
||||
void writechar(int file, char c);
|
||||
char _getchar();
|
||||
void _putchar(int file, char c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONSOLE_H */
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
#include "cop0.h"
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// MIPS specific
|
||||
// ---------------------------------------------------------------------------------
|
||||
uint32_t CP0_SR_read(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__asm__
|
||||
(
|
||||
"mfc0 %[val], $12\n"
|
||||
: [val] "=r" (result)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CP0_SR_write(uint32_t val)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"mtc0 %[val], $12\n"
|
||||
: /* no output */
|
||||
: [val] "r" (val)
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t CP0_CR_read(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__asm__
|
||||
(
|
||||
"mfc0 %[val], $13\n"
|
||||
: [val] "=r" (result)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CP0_CR_write(uint32_t val)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"mtc0 %[val], $13\n"
|
||||
:
|
||||
: [val] "r" (val)
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t CP0_TR_read(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__asm__
|
||||
(
|
||||
"mfc0 %[val], $31\n"
|
||||
: [val] "=r" (result)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CP0_TR_write(uint32_t val)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"mtc0 %[val], $31\n"
|
||||
:
|
||||
: [val] "r" (val)
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t CP0_PRID_read(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__asm__
|
||||
(
|
||||
"mfc0 %[val], $15\n"
|
||||
: [val] "=r" (result)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CP0_TR_write_ptr(uint32_t* pPtr)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"swc0 $31, 0(%[pPtr])\n"
|
||||
:
|
||||
: [pPtr] "r" (pPtr)
|
||||
);
|
||||
}
|
||||
|
||||
void CP0_TR_read_ptr(uint32_t* pPtr)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"lwc0 $31, 0(%[pPtr])\n"
|
||||
:
|
||||
: [pPtr] "r" (pPtr)
|
||||
);
|
||||
}
|
||||
|
||||
void ICACHE_invalidate_all(void)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"cop0 32\n"
|
||||
);
|
||||
}
|
||||
|
||||
void ICACHE_invalidate_at(uint32_t* pPtr)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"mtc0 %[pPtr], $31\n"
|
||||
"cop0 33\n"
|
||||
:
|
||||
: [pPtr] "r" (pPtr)
|
||||
);
|
||||
}
|
||||
|
||||
void DCACHE_invalidate_all(void)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"cop0 34\n"
|
||||
);
|
||||
}
|
||||
|
||||
void DCACHE_invalidate_at(uint32_t* pPtr)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"mtc0 %[pPtr], $31\n"
|
||||
"cop0 35\n"
|
||||
:
|
||||
: [pPtr] "r" (pPtr)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: cop0.h
|
||||
* Author: jens
|
||||
*
|
||||
* Created on 12. Januar 2017, 16:07
|
||||
*/
|
||||
|
||||
#ifndef COP0_H
|
||||
#define COP0_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Chip registers
|
||||
// ---------------------------------------------------------
|
||||
// COP0 registers
|
||||
#define COP0_REG_INVAT_POINTER 31
|
||||
|
||||
// COP0 instructions
|
||||
#define COP0_INSTR_INVALL_ICACHE 32
|
||||
#define COP0_INSTR_INVAT_ICACHE 33
|
||||
#define COP0_INSTR_INVALL_DCACHE 34
|
||||
#define COP0_INSTR_INVAT_DCACHE 35
|
||||
|
||||
#define CP0_read(idx) \
|
||||
({ \
|
||||
uint32_t result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"mfc0\t%0,$"#idx"\n" \
|
||||
: "=r" (result) \
|
||||
); \
|
||||
result; \
|
||||
})
|
||||
|
||||
#define CP0_write(idx, val) \
|
||||
({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"mtc0\t%0,$"#idx"\n" \
|
||||
"nop\n" \
|
||||
: /* no output */ \
|
||||
: "r" (val) \
|
||||
); \
|
||||
})
|
||||
|
||||
#define CP0_TLBR \
|
||||
({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"tlbr\n" \
|
||||
: /* no output */ \
|
||||
: /* no input */ \
|
||||
); \
|
||||
})
|
||||
|
||||
#define CP0_TLBWI \
|
||||
({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"tlbwi\n" \
|
||||
: /* no output */ \
|
||||
: /* no input */ \
|
||||
); \
|
||||
})
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uint32_t CP0_SR_read(void);
|
||||
void CP0_SR_write(uint32_t val);
|
||||
uint32_t CP0_CR_read(void);
|
||||
void CP0_CR_write(uint32_t val);
|
||||
uint32_t CP0_PRID_read(void);
|
||||
uint32_t CP0_TR_read(void);
|
||||
void CP0_TR_write(uint32_t val);
|
||||
void CP0_TR_write_ptr(uint32_t* pPtr);
|
||||
void CP0_TR_read_ptr(uint32_t* pPtr);
|
||||
void ICACHE_invalidate_all(void);
|
||||
void ICACHE_invalidate_at(uint32_t* pPtr);
|
||||
void DCACHE_invalidate_all(void);
|
||||
void DCACHE_invalidate_at(uint32_t* pPtr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* COP0_H */
|
||||
|
||||
@@ -0,0 +1,642 @@
|
||||
/****************************************************************************
|
||||
|
||||
THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
|
||||
HP offers the following for use in the public domain. HP makes no
|
||||
warranty with regard to the software or it's performance and the
|
||||
user accepts the software "AS IS" with all faults.
|
||||
|
||||
HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
|
||||
*
|
||||
* Module name: remcom.c $
|
||||
* Revision: 1.34 $
|
||||
* Date: 91/03/09 12:29:49 $
|
||||
* Contributor: Lake Stevens Instrument Division$
|
||||
*
|
||||
* Description: low level support for gdb debugger. $
|
||||
*
|
||||
* Considerations: only works on target hardware $
|
||||
*
|
||||
* Written by: Glenn Engel $
|
||||
* ModuleState: Experimental $
|
||||
*
|
||||
* NOTES: See Below $
|
||||
*
|
||||
* Modified for SPARC by Stu Grossman, Cygnus Support.
|
||||
*
|
||||
* This code has been extensively tested on the Fujitsu SPARClite demo board.
|
||||
*
|
||||
* To enable debugger support, two things need to happen. One, a
|
||||
* call to set_debug_traps() is necessary in order to allow any breakpoints
|
||||
* or error conditions to be properly intercepted and reported to gdb.
|
||||
* Two, a breakpoint needs to be generated to begin communication. This
|
||||
* is most easily accomplished by a call to breakpoint(). Breakpoint()
|
||||
* simulates a breakpoint by executing a trap #1.
|
||||
*
|
||||
*************
|
||||
*
|
||||
* The following gdb commands are supported:
|
||||
*
|
||||
* command function Return value
|
||||
*
|
||||
* g return the value of the CPU registers hex data or ENN
|
||||
* G set the value of the CPU registers OK or ENN
|
||||
*
|
||||
* mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
|
||||
* MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
|
||||
*
|
||||
* c Resume at current address SNN ( signal NN)
|
||||
* cAA..AA Continue at address AA..AA SNN
|
||||
*
|
||||
* s Step one instruction SNN
|
||||
* sAA..AA Step one instruction from AA..AA SNN
|
||||
*
|
||||
* k kill
|
||||
*
|
||||
* ? What was the last sigval ? SNN (signal NN)
|
||||
*
|
||||
* All commands and responses are sent with a packet which includes a
|
||||
* checksum. A packet consists of
|
||||
*
|
||||
* $<packet info>#<checksum>.
|
||||
*
|
||||
* where
|
||||
* <packet info> :: <characters representing the command or response>
|
||||
* <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
|
||||
*
|
||||
* When a packet is received, it is first acknowledged with either '+' or '-'.
|
||||
* '+' indicates a successful transfer. '-' indicates a failed transfer.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Host: Reply:
|
||||
* $m0,10#2a +$00010203040506070809101112131415#42
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
/************************************************************************
|
||||
*
|
||||
* external low-level support routines
|
||||
*/
|
||||
|
||||
extern void dbg_putchar(char c); /* write a single character */
|
||||
extern char dbg_getchar(); /* read and return a single char */
|
||||
extern void ICACHE_invalidate_all();
|
||||
extern int sputs(char const *pStr);
|
||||
extern void print_byte(char byte);
|
||||
extern void print_word(int word);
|
||||
|
||||
void putDebugChar(char c)
|
||||
{
|
||||
dbg_putchar(c);
|
||||
}
|
||||
|
||||
int getDebugChar()
|
||||
{
|
||||
return (int)dbg_getchar();
|
||||
}
|
||||
|
||||
void flush_i_cache()
|
||||
{
|
||||
ICACHE_invalidate_all();
|
||||
}
|
||||
|
||||
void dbg_strcpy(char *pDst, const char *pSrc)
|
||||
{
|
||||
while(*pSrc)
|
||||
{
|
||||
*(pDst++) = *(pSrc++);
|
||||
}
|
||||
*pDst = *pSrc;
|
||||
}
|
||||
|
||||
void* dbg_memset(void *pDst, int value, size_t size)
|
||||
{
|
||||
char *dst = (char*)pDst;
|
||||
|
||||
while(size)
|
||||
{
|
||||
*(dst++) = (char)value;
|
||||
size--;
|
||||
}
|
||||
return (void*)dst;
|
||||
}
|
||||
|
||||
void* dbg_memcpy(void *pDst, const void *pSrc, size_t size )
|
||||
{
|
||||
char *dst = (char*)pDst;
|
||||
char *src = (char*)pSrc;
|
||||
|
||||
while(size)
|
||||
{
|
||||
*(dst++) = *(src++);
|
||||
size--;
|
||||
}
|
||||
return (void*)dst;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
|
||||
/* at least NUMREGBYTES*2 are needed for register packets */
|
||||
#define BUFMAX 2048
|
||||
|
||||
const char hexchars[]="0123456789abcdef";
|
||||
|
||||
#define NUMREGS 72
|
||||
|
||||
/* Number of bytes of registers. */
|
||||
#define NUMREGBYTES (NUMREGS * 4)
|
||||
|
||||
enum regnames
|
||||
{
|
||||
START_CPU_REGS = 0,
|
||||
SR = START_CPU_REGS,
|
||||
CR,
|
||||
PC,
|
||||
BV,
|
||||
R00,
|
||||
R01,
|
||||
R02,
|
||||
R03,
|
||||
R04,
|
||||
R05,
|
||||
R06,
|
||||
R07,
|
||||
R08,
|
||||
R09,
|
||||
R10,
|
||||
R11,
|
||||
R12,
|
||||
R13,
|
||||
R14,
|
||||
R15,
|
||||
R16,
|
||||
R17,
|
||||
R18,
|
||||
R19,
|
||||
R20,
|
||||
R21,
|
||||
R22,
|
||||
R23,
|
||||
R24,
|
||||
R25,
|
||||
R26,
|
||||
R27,
|
||||
R28,
|
||||
R29,
|
||||
R30,
|
||||
R31,
|
||||
LO,
|
||||
HI,
|
||||
NUM_REGS
|
||||
};
|
||||
|
||||
/* Convert ch from a hex digit to an int */
|
||||
static int
|
||||
hex (unsigned char ch)
|
||||
{
|
||||
if (ch >= 'a' && ch <= 'f')
|
||||
return ch-'a'+10;
|
||||
|
||||
if (ch >= '0' && ch <= '9')
|
||||
return ch-'0';
|
||||
|
||||
if (ch >= 'A' && ch <= 'F')
|
||||
return ch-'A'+10;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* scan for the sequence $<data>#<checksum> */
|
||||
|
||||
unsigned char *
|
||||
getpacket (unsigned char *buffer)
|
||||
{
|
||||
unsigned char checksum;
|
||||
unsigned char xmitcsum;
|
||||
int count;
|
||||
char ch;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* wait around for the start character, ignore all other characters */
|
||||
while ((ch = getDebugChar ()) != '$')
|
||||
;
|
||||
|
||||
retry:
|
||||
checksum = 0;
|
||||
xmitcsum = -1;
|
||||
count = 0;
|
||||
|
||||
/* now, read until a # or end of buffer is found */
|
||||
while (count < BUFMAX - 1)
|
||||
{
|
||||
ch = getDebugChar ();
|
||||
if (ch == '$')
|
||||
goto retry;
|
||||
if (ch == '#')
|
||||
break;
|
||||
checksum = checksum + ch;
|
||||
buffer[count] = ch;
|
||||
count = count + 1;
|
||||
}
|
||||
buffer[count] = 0;
|
||||
|
||||
if (ch == '#')
|
||||
{
|
||||
ch = getDebugChar ();
|
||||
xmitcsum = hex (ch) << 4;
|
||||
ch = getDebugChar ();
|
||||
xmitcsum += hex (ch);
|
||||
|
||||
#ifdef WITH_CHECKSUM_CHECK
|
||||
if (checksum != xmitcsum)
|
||||
{
|
||||
putDebugChar ('-'); /* failed checksum */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
putDebugChar ('+'); /* successful transfer */
|
||||
|
||||
/* if a sequence char is present, reply the sequence ID */
|
||||
if (buffer[2] == ':')
|
||||
{
|
||||
putDebugChar (buffer[0]);
|
||||
putDebugChar (buffer[1]);
|
||||
|
||||
return &buffer[3];
|
||||
}
|
||||
return &buffer[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* send the packet in buffer. */
|
||||
|
||||
static void
|
||||
putpacket (unsigned char *buffer)
|
||||
{
|
||||
unsigned char checksum;
|
||||
int count;
|
||||
unsigned char ch;
|
||||
|
||||
/* $<packet info>#<checksum>. */
|
||||
do
|
||||
{
|
||||
putDebugChar('$');
|
||||
checksum = 0;
|
||||
count = 0;
|
||||
|
||||
while (ch = buffer[count])
|
||||
{
|
||||
putDebugChar(ch);
|
||||
checksum += ch;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
putDebugChar('#');
|
||||
putDebugChar(hexchars[checksum >> 4]);
|
||||
putDebugChar(hexchars[checksum & 0xf]);
|
||||
|
||||
} while (getDebugChar() != '+');
|
||||
}
|
||||
|
||||
/* Indicate to caller of mem2hex or hex2mem that there has been an
|
||||
error. */
|
||||
const int mem_err = 0;
|
||||
|
||||
/* Convert the memory pointed to by mem into hex, placing result in buf.
|
||||
* Return a pointer to the last char put in buf (null), in case of mem fault,
|
||||
* return 0.
|
||||
* If MAY_FAULT is non-zero, then we will handle memory faults by returning
|
||||
* a 0, else treat a fault like any other fault in the stub.
|
||||
*/
|
||||
|
||||
static unsigned char *
|
||||
mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
|
||||
{
|
||||
unsigned char ch;
|
||||
|
||||
while (count-- > 0)
|
||||
{
|
||||
ch = *mem++;
|
||||
if (mem_err)
|
||||
return 0;
|
||||
*buf++ = hexchars[ch >> 4];
|
||||
*buf++ = hexchars[ch & 0xf];
|
||||
}
|
||||
*buf = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* convert the hex array pointed to by buf into binary to be placed in mem
|
||||
* return a pointer to the character AFTER the last byte written */
|
||||
|
||||
static char *
|
||||
hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
|
||||
{
|
||||
int i;
|
||||
unsigned char ch;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
ch = hex(*buf++) << 4;
|
||||
ch |= hex(*buf++);
|
||||
*mem++ = ch;
|
||||
if (mem_err)
|
||||
return 0;
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
/* This table contains the mapping between SPARC hardware trap types, and
|
||||
signals, which are primarily what GDB understands. It also indicates
|
||||
which hardware traps we need to commandeer when initializing the stub. */
|
||||
|
||||
struct hard_trap_info_t
|
||||
{
|
||||
unsigned long tt; /* Trap type code for SPARClite */
|
||||
unsigned long signo; /* Signal that we map this trap into */
|
||||
};
|
||||
|
||||
const struct hard_trap_info_t hard_trap_info[] =
|
||||
{
|
||||
{0, SIGINT}, /* Interrupt (Int) */
|
||||
{1, SIGSEGV}, /* TLB modification (Mod) */
|
||||
{2, SIGSEGV}, /* TLB load (TLBL) */
|
||||
{3, SIGSEGV}, /* TLB store (TLBS) */
|
||||
{4, SIGSEGV}, /* Address error load (ADEL) */
|
||||
{5, SIGSEGV}, /* Address error store (ADES) */
|
||||
{6, SIGBUS}, /* Bus error on instruction (IBE) */
|
||||
{7, SIGBUS}, /* Bus error on data (DBE) */
|
||||
{8, SIGUSR1}, /* Syscall instruction called (Syscall) */
|
||||
{9, SIGTRAP}, /* Breakpoint instruction called (Breakpoint) */
|
||||
{10, SIGILL}, /* Reserved instruction (RI) */
|
||||
{11, SIGXCPU}, /* Coprocessor unusable (CpU) */
|
||||
{12, SIGFPE}, /* Arithmetic overflow (Ov) */
|
||||
{0, 0} /* Must be last */
|
||||
};
|
||||
|
||||
/* Convert the SPARC hardware trap type code to a unix signal number. */
|
||||
static unsigned long
|
||||
computeSignal (unsigned long tt)
|
||||
{
|
||||
// Determine linux signal from CPU specific exception code
|
||||
struct hard_trap_info_t *ht;
|
||||
|
||||
for (ht = (struct hard_trap_info_t *)hard_trap_info; ht->signo != 0; ht++)
|
||||
{
|
||||
if (ht->tt == tt)
|
||||
{
|
||||
return ht->signo;
|
||||
}
|
||||
}
|
||||
return SIGHUP; /* default for things we don't know about */
|
||||
}
|
||||
|
||||
/*
|
||||
* While we find nice hex chars, build an int.
|
||||
* Return number of chars processed.
|
||||
*/
|
||||
|
||||
static int
|
||||
hexToInt(char **ptr, unsigned long *intValue)
|
||||
{
|
||||
unsigned long numChars = 0;
|
||||
int hexValue;
|
||||
|
||||
*intValue = 0;
|
||||
|
||||
while (**ptr)
|
||||
{
|
||||
hexValue = hex(**ptr);
|
||||
if (hexValue < 0)
|
||||
break;
|
||||
|
||||
*intValue = (*intValue << 4) | hexValue;
|
||||
numChars ++;
|
||||
|
||||
(*ptr)++;
|
||||
}
|
||||
return (numChars);
|
||||
}
|
||||
|
||||
int isBreak(unsigned long instr)
|
||||
{
|
||||
return ((instr & 0xFC00003F) == 0x0000000D);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function does all command procesing for interfacing to gdb. It
|
||||
* returns 1 if you should skip the instruction at the trap address, 0
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
void
|
||||
handle_exception (unsigned long *registers)
|
||||
{
|
||||
char remcomInBuffer[BUFMAX];
|
||||
char remcomOutBuffer[BUFMAX];
|
||||
|
||||
sputs("Entry\n");
|
||||
unsigned long tt; /* Trap type */
|
||||
unsigned long sigval;
|
||||
unsigned long addr;
|
||||
unsigned long length;
|
||||
char *ptr;
|
||||
unsigned long *sp;
|
||||
|
||||
addr = *((unsigned long *)registers[PC]);
|
||||
|
||||
// is break
|
||||
if (isBreak(addr))
|
||||
{
|
||||
registers[PC] += 4;
|
||||
}
|
||||
|
||||
sp = (unsigned long *)®isters[R29];
|
||||
|
||||
tt = (registers[CR] >> 2) & 0x1f;
|
||||
|
||||
/* reply to host that an exception has occurred */
|
||||
sigval = computeSignal(tt);
|
||||
ptr = remcomOutBuffer;
|
||||
|
||||
*ptr++ = 'T';
|
||||
*ptr++ = hexchars[sigval >> 4];
|
||||
*ptr++ = hexchars[sigval & 0xf];
|
||||
|
||||
*ptr++ = hexchars[37 >> 4];
|
||||
*ptr++ = hexchars[37 & 0xf];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((char *)®isters[PC], ptr, 4, 0);
|
||||
*ptr++ = ';';
|
||||
|
||||
*ptr++ = hexchars[29 >> 4];
|
||||
*ptr++ = hexchars[29 & 0xf];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((char *)sp, ptr, 4, 0);
|
||||
*ptr++ = ';';
|
||||
|
||||
*ptr++ = 0;
|
||||
|
||||
putpacket(remcomOutBuffer);
|
||||
|
||||
while (1)
|
||||
{
|
||||
remcomOutBuffer[0] = 0;
|
||||
|
||||
ptr = getpacket(remcomInBuffer);
|
||||
switch (*ptr++)
|
||||
{
|
||||
case '?':
|
||||
sputs("?\n");
|
||||
remcomOutBuffer[0] = 'S';
|
||||
remcomOutBuffer[1] = hexchars[sigval >> 4];
|
||||
remcomOutBuffer[2] = hexchars[sigval & 0xf];
|
||||
remcomOutBuffer[3] = 0;
|
||||
break;
|
||||
|
||||
case 'd': /* toggle debug flag */
|
||||
sputs("d\n");
|
||||
break;
|
||||
|
||||
case 'g': /* return the value of the CPU registers */
|
||||
{
|
||||
sputs("g\n");
|
||||
ptr = remcomOutBuffer;
|
||||
/* R00 .. R31 */
|
||||
ptr = mem2hex((char *)®isters[R00], ptr, 4*32, 0);
|
||||
/* SR, HI, LO, BADVADDR, CR, PC */
|
||||
ptr = mem2hex((char *)®isters[SR], ptr, 4, 0);
|
||||
ptr = mem2hex((char *)®isters[HI], ptr, 4, 0);
|
||||
ptr = mem2hex((char *)®isters[LO], ptr, 4, 0);
|
||||
ptr = mem2hex((char *)®isters[BV], ptr, 4, 0);
|
||||
ptr = mem2hex((char *)®isters[CR], ptr, 4, 0);
|
||||
ptr = mem2hex((char *)®isters[PC], ptr, 4, 0);
|
||||
/* Floating point F00 .. F31*/
|
||||
dbg_memset(ptr, '0', 8 * 32);
|
||||
ptr += 8*32;
|
||||
/* FCSR, FIR, RESTART*/
|
||||
dbg_memset(ptr, '0', 8 * 3);
|
||||
ptr += 8*3;
|
||||
*ptr = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'G': /* set the value of the CPU registers - return OK */
|
||||
{
|
||||
sputs("G\n");
|
||||
unsigned long *newsp, sr;
|
||||
sr = registers[SR];
|
||||
|
||||
hex2mem(ptr, (char *)®isters[R00], 4*32, 0); /* R00 .. R31 */
|
||||
ptr += 4*32 * 2;
|
||||
/* SR, HI, LO, BADVADDR, CR, PC */
|
||||
hex2mem(ptr, (char *)®isters[SR], 4, 0);
|
||||
ptr += 4 * 2;
|
||||
hex2mem(ptr, (char *)®isters[HI], 4, 0);
|
||||
ptr += 4 * 2;
|
||||
hex2mem(ptr, (char *)®isters[LO], 4, 0);
|
||||
ptr += 4 * 2;
|
||||
hex2mem(ptr, (char *)®isters[BV], 4, 0);
|
||||
ptr += 4 * 2;
|
||||
hex2mem(ptr, (char *)®isters[CR], 4, 0);
|
||||
ptr += 4 * 2;
|
||||
hex2mem(ptr, (char *)®isters[PC], 4, 0);
|
||||
ptr += 4 * 2;
|
||||
*ptr = 0;
|
||||
|
||||
dbg_strcpy(remcomOutBuffer,"OK");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
|
||||
sputs("m\n");
|
||||
/* Try to read %x,%x. */
|
||||
|
||||
if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length))
|
||||
{
|
||||
if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
dbg_strcpy (remcomOutBuffer, "E03");
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_strcpy(remcomOutBuffer,"E01");
|
||||
}
|
||||
sputs("m:"); print_word(addr); sputs(",");print_word(length); sputs("\n");
|
||||
break;
|
||||
|
||||
case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
|
||||
/* Try to read '%x,%x:'. */
|
||||
|
||||
if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length) && *ptr++ == ':')
|
||||
{
|
||||
if (hex2mem(ptr, (char *)addr, length, 1))
|
||||
{
|
||||
dbg_strcpy(remcomOutBuffer, "OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_strcpy(remcomOutBuffer, "E03");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_strcpy(remcomOutBuffer, "E02");
|
||||
}
|
||||
sputs("M:"); print_word(addr); sputs(",");print_word(length); sputs("\n");
|
||||
break;
|
||||
|
||||
case 'c': /* cAA..AA Continue at address AA..AA(optional) */
|
||||
/* try to read optional parameter, pc unchanged if no parm */
|
||||
|
||||
sputs("c: PC="); print_word(registers[PC]);sputs("\n");
|
||||
if (hexToInt(&ptr, &addr))
|
||||
{
|
||||
registers[PC] = addr;
|
||||
sputs("c: addr="); print_word(addr);sputs("\n");
|
||||
}
|
||||
|
||||
/* Need to flush the instruction cache here, as we may have deposited a
|
||||
breakpoint, and the icache probably has no way of knowing that a data ref to
|
||||
some location may have changed something that is in the instruction cache.
|
||||
*/
|
||||
|
||||
flush_i_cache();
|
||||
return;
|
||||
|
||||
/* kill the program */
|
||||
case 'k' : /* do nothing */
|
||||
sputs("Kill\n");
|
||||
break;
|
||||
#if 0
|
||||
case 't': /* Test feature */
|
||||
break;
|
||||
#endif
|
||||
case 'r': /* Reset */
|
||||
// Perform reset
|
||||
sputs("Reset\n");
|
||||
break;
|
||||
} /* switch */
|
||||
/* reply to the request */
|
||||
putpacket(remcomOutBuffer);
|
||||
}
|
||||
sputs("Exit\n");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "libsys.h"
|
||||
#include "gpio.h"
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void gpio_init(gpio_if_t *pObj, uint32_t base_addr, uint32_t mask, uint32_t shift)
|
||||
{
|
||||
pObj->pBase = (uint32_t*)base_addr;
|
||||
pObj->mask = mask;
|
||||
pObj->mask_shifted = mask << shift;
|
||||
pObj->shift = shift;
|
||||
}
|
||||
|
||||
void gpio_write(gpio_if_t *pObj, uint32_t value)
|
||||
{
|
||||
*pObj->pBase = (value & pObj->mask) << pObj->shift;
|
||||
}
|
||||
|
||||
uint32_t gpio_read(gpio_if_t *pObj)
|
||||
{
|
||||
uint32_t result = (*pObj->pBase >> pObj->shift) & pObj->mask;
|
||||
return result;
|
||||
}
|
||||
|
||||
void gpio_set(gpio_if_t *pObj, uint32_t value)
|
||||
{
|
||||
*pObj->pBase |= (value & pObj->mask) << pObj->shift;
|
||||
}
|
||||
|
||||
void gpio_clr(gpio_if_t *pObj, uint32_t value)
|
||||
{
|
||||
*pObj->pBase &= ~((value | pObj->mask) << pObj->shift);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef GPIO_H
|
||||
#define GPIO_H
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------
|
||||
typedef struct _sgpio_if_t
|
||||
{
|
||||
volatile uint32_t *pBase;
|
||||
volatile uint32_t mask;
|
||||
volatile uint32_t mask_shifted;
|
||||
volatile uint32_t shift;
|
||||
|
||||
} gpio_if_t;
|
||||
|
||||
void gpio_init(gpio_if_t *pObj, uint32_t base_addr, uint32_t mask, uint32_t shift);
|
||||
|
||||
void gpio_write(gpio_if_t *pObj, uint32_t value);
|
||||
uint32_t gpio_read(gpio_if_t *pObj);
|
||||
|
||||
void gpio_set(gpio_if_t *pObj, uint32_t value);
|
||||
void gpio_clr(gpio_if_t *pObj, uint32_t value);
|
||||
|
||||
#endif // GPIO_H
|
||||
@@ -0,0 +1,107 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "asm/regdef.h"
|
||||
#include "xcpt.h"
|
||||
#include "irq.h"
|
||||
#include <cop0.h>
|
||||
|
||||
static fp_irq_t g_irq_handler[MAX_NUM_IRQ] = {NULL};
|
||||
|
||||
int _irq_dispatch(struct xcptcontext * xcp)
|
||||
{
|
||||
int i, ip, cause;
|
||||
|
||||
cause = xcp->cr & xcp->sr;
|
||||
ip = (cause >> 8) & 0xFF;
|
||||
|
||||
for (i=0; i < MAX_NUM_IRQ; i++)
|
||||
{
|
||||
if (ip & 1)
|
||||
if (g_irq_handler[i])
|
||||
(g_irq_handler[i])(xcp);
|
||||
|
||||
ip >>= 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void interrupt_register(int irq_num, fp_irq_t fp)
|
||||
{
|
||||
if ((irq_num >= 0) && (irq_num < MAX_NUM_IRQ))
|
||||
g_irq_handler[irq_num] = fp;
|
||||
|
||||
}
|
||||
|
||||
void interrupt_enable(int irq_num)
|
||||
{
|
||||
reg_t reg, im;
|
||||
|
||||
if ((irq_num >= 0) && (irq_num < MAX_NUM_IRQ))
|
||||
{
|
||||
im = 1 << irq_num;
|
||||
reg = CP0_SR_read();
|
||||
reg |= (SR_MASK_IM & (im << 8));
|
||||
CP0_SR_write(reg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void interrupt_disable(int irq_num)
|
||||
{
|
||||
reg_t reg, im;
|
||||
|
||||
if ((irq_num >= 0) && (irq_num < MAX_NUM_IRQ))
|
||||
{
|
||||
im = 1 << irq_num;
|
||||
reg = CP0_SR_read();
|
||||
reg &= ~(SR_MASK_IM & (im << 8));
|
||||
CP0_SR_write(reg);
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt_global_enable()
|
||||
{
|
||||
uint32_t reg = CP0_SR_read() | SR_MASK_IEC;
|
||||
CP0_SR_write(reg);
|
||||
}
|
||||
|
||||
void interrupt_global_disable()
|
||||
{
|
||||
uint32_t reg = CP0_SR_read() & ~SR_MASK_IEC;
|
||||
CP0_SR_write(reg);
|
||||
}
|
||||
|
||||
void interrupt_set(int irq_num)
|
||||
{
|
||||
reg_t reg, ip;
|
||||
|
||||
if ((irq_num >= 0) && (irq_num < MAX_NUM_IRQ))
|
||||
{
|
||||
ip = 1 << irq_num;
|
||||
reg = CP0_CR_read();
|
||||
reg |= (CR_MASK_IP & (ip << 8));
|
||||
CP0_CR_write(reg);
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt_clr(int irq_num)
|
||||
{
|
||||
reg_t reg, ip;
|
||||
|
||||
if ((irq_num >= 0) && (irq_num < MAX_NUM_IRQ))
|
||||
{
|
||||
ip = 1 << irq_num;
|
||||
reg = CP0_CR_read();
|
||||
reg &= ~(CR_MASK_IP & (ip << 8));
|
||||
CP0_CR_write(reg);
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt_init(void)
|
||||
{
|
||||
// register interrupt dispatcher
|
||||
xcpt_register(EXC_INT, _irq_dispatch);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef IRQ_H
|
||||
#define IRQ_H
|
||||
|
||||
#include "xcpt.h"
|
||||
|
||||
#define MAX_NUM_IRQ 8
|
||||
|
||||
typedef void (*fp_irq_t)(struct xcptcontext * xcp);
|
||||
|
||||
void interrupt_init(void);
|
||||
int _irq_dispatch(struct xcptcontext * xcp);
|
||||
void interrupt_register(int irq_num, fp_irq_t fp);
|
||||
void interrupt_enable(int irq_num);
|
||||
void interrupt_disable(int irq_num);
|
||||
void interrupt_global_enable();
|
||||
void interrupt_global_disable();
|
||||
void interrupt_set(int irq_num);
|
||||
void interrupt_clr(int irq_num);
|
||||
|
||||
#endif // IRQ_H
|
||||
@@ -0,0 +1,392 @@
|
||||
#include <sys/times.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "libsys.h"
|
||||
#include "asm/regdef.h"
|
||||
|
||||
static uint32_t critical_nesting_counter = 0;
|
||||
|
||||
void enter_critical()
|
||||
{
|
||||
if (critical_nesting_counter == 0)
|
||||
{
|
||||
interrupt_global_disable();
|
||||
}
|
||||
critical_nesting_counter++;
|
||||
}
|
||||
|
||||
void exit_critical()
|
||||
{
|
||||
if (critical_nesting_counter > 0)
|
||||
{
|
||||
critical_nesting_counter--;
|
||||
if (critical_nesting_counter == 0)
|
||||
{
|
||||
interrupt_global_enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _exit (int exitcode)
|
||||
{
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
while(1);
|
||||
}
|
||||
|
||||
void sleep(unsigned ms)
|
||||
{
|
||||
unsigned stop;
|
||||
struct tms t;
|
||||
|
||||
times(&t);
|
||||
stop = t.tms_utime + ms;
|
||||
|
||||
do
|
||||
{
|
||||
times(&t);
|
||||
} while (t.tms_utime < stop);
|
||||
|
||||
}
|
||||
|
||||
void usleep(unsigned us)
|
||||
{
|
||||
unsigned stop_us, stop_s, curr_us, curr_s;
|
||||
struct timeval t;
|
||||
|
||||
if (!us)
|
||||
return;
|
||||
|
||||
gettimeofday(&t, NULL);
|
||||
stop_s = (unsigned)t.tv_sec;
|
||||
stop_us = (unsigned)t.tv_usec + us;
|
||||
if (stop_us >= 1E6)
|
||||
{
|
||||
stop_us -= 1E6;
|
||||
stop_s++;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
gettimeofday(&t, NULL);
|
||||
curr_s = (unsigned)t.tv_sec;
|
||||
curr_us = (unsigned)t.tv_usec;
|
||||
} while ((curr_s < stop_s) || (curr_us < stop_us));
|
||||
|
||||
}
|
||||
|
||||
int getrusage(int who, struct rusage *usage)
|
||||
{
|
||||
volatile long *pReg_usec = (long*)SYS_TIMER_USEC;
|
||||
volatile long *pReg_sec = (long*)SYS_TIMER_SEC;
|
||||
|
||||
// who: RUSAGE_SELF or RUSAGE_CHILDREN
|
||||
usage->ru_utime.tv_usec = *pReg_usec;
|
||||
usage->ru_utime.tv_sec = *pReg_sec;
|
||||
usage->ru_stime.tv_usec = *pReg_usec;
|
||||
usage->ru_stime.tv_sec = *pReg_sec;
|
||||
}
|
||||
|
||||
clock_t times(struct tms *buffer)
|
||||
{
|
||||
volatile long *pReg_usec = (long*)SYS_TIMER_USEC;
|
||||
volatile long *pReg_sec = (long*)SYS_TIMER_SEC;
|
||||
long sec;
|
||||
long usec;
|
||||
|
||||
sec = *pReg_sec;
|
||||
usec = *pReg_usec;
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
buffer->tms_utime = sec*1000 + usec/1000;
|
||||
buffer->tms_stime = 0;
|
||||
buffer->tms_cutime = 0;
|
||||
buffer->tms_cstime = 0;
|
||||
}
|
||||
|
||||
return (clock_t)sec;
|
||||
}
|
||||
|
||||
int gettimeofday(struct timeval *tp, void *tzp)
|
||||
{
|
||||
volatile long *pReg_usec = (long*)SYS_TIMER_USEC;
|
||||
volatile long *pReg_sec = (long*)SYS_TIMER_SEC;
|
||||
|
||||
if (tp)
|
||||
{
|
||||
tp->tv_sec = *pReg_sec;
|
||||
tp->tv_usec = *pReg_usec;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int settimeofday(const struct timeval *tp, const struct timezone *tzp)
|
||||
{
|
||||
volatile long *pReg_usec = (long*)SYS_TIMER_USEC;
|
||||
volatile long *pReg_sec = (long*)SYS_TIMER_SEC;
|
||||
div_t res;
|
||||
|
||||
res = div(tp->tv_usec, 1E6);
|
||||
|
||||
if (tp)
|
||||
{
|
||||
*pReg_usec = res.rem;
|
||||
*pReg_sec = tp->tv_sec + res.quot;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
caddr_t sbrk(int incr)
|
||||
{
|
||||
extern char end;
|
||||
extern char stack_ptr;
|
||||
static char *heap_end;
|
||||
char *prev_heap_end;
|
||||
|
||||
if (heap_end == 0)
|
||||
{
|
||||
heap_end = &end;
|
||||
}
|
||||
|
||||
prev_heap_end = heap_end;
|
||||
if (heap_end + incr > &stack_ptr)
|
||||
{
|
||||
// sputs("Heap and stack collision\n");
|
||||
// sputs("Stack Ptr = ");print_word(&stack_ptr);sputs("\n");
|
||||
// sputs("Heap end = ");print_word(heap_end);sputs("\n");
|
||||
// sputs("Increment = ");print_word(incr);sputs("\n");
|
||||
exit(1);
|
||||
}
|
||||
heap_end += incr;
|
||||
return (caddr_t) prev_heap_end;
|
||||
}
|
||||
|
||||
int fstat(int file, struct stat *st)
|
||||
{
|
||||
// sputs("fstat ("); print_word(file); sputs(")\n");
|
||||
st->st_mode = S_IFCHR;
|
||||
st->st_blksize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lseek(int file, int ptr, int dir)
|
||||
{
|
||||
// sputs("lseek ("); print_word(file); sputs(")\n");
|
||||
errno = ESPIPE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int open(const char *name, int flags, int mode)
|
||||
{
|
||||
return con_open(name);
|
||||
}
|
||||
|
||||
int close(int file)
|
||||
{
|
||||
return con_close(file);
|
||||
}
|
||||
|
||||
int read(int file, char *ptr, int len)
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
int fd_out = file;
|
||||
|
||||
if (file == 0)
|
||||
{
|
||||
fd_out = 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < len)
|
||||
{
|
||||
c = readchar(file);
|
||||
|
||||
if (c == 0x04)
|
||||
break;
|
||||
|
||||
if ((c == 0x0D) || (c == 0x0A))
|
||||
{
|
||||
writechar(fd_out, 0x0D);
|
||||
ptr[i++] = 0x0D;
|
||||
writechar(fd_out, 0x0A);
|
||||
ptr[i++] = 0x0A;
|
||||
break;
|
||||
}
|
||||
|
||||
writechar(fd_out, c);
|
||||
ptr[i++] = c;
|
||||
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int write(int file, char *ptr, int len)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// sputs("write ("); print_word(file); sputs(")\n");
|
||||
|
||||
for (i=0; i < len; i++)
|
||||
_putchar(file, *ptr++);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int isatty(int file)
|
||||
{
|
||||
// sputs("isatty ("); print_word(file); sputs(")\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int getpid(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#include <errno.h>
|
||||
#undef errno
|
||||
extern int errno;
|
||||
int kill(int pid, int sig)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#include <errno.h>
|
||||
#undef errno
|
||||
extern int errno;
|
||||
int link(char *old, char *new)
|
||||
{
|
||||
errno = EMLINK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#include <errno.h>
|
||||
#undef errno
|
||||
extern int errno;
|
||||
int unlink(char *name)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sputs(char const *pStr)
|
||||
{
|
||||
char const *start = pStr;
|
||||
|
||||
while(*pStr)
|
||||
_putchar(1, *(pStr++));
|
||||
|
||||
return pStr - start;
|
||||
}
|
||||
|
||||
void print_byte(char byte)
|
||||
{
|
||||
int i;
|
||||
unsigned char c, nibble;
|
||||
|
||||
for (i=0; i < 2; i++)
|
||||
{
|
||||
nibble = (char)((byte >> 4) & 0xF);
|
||||
byte <<= 4;
|
||||
|
||||
if (nibble < 10)
|
||||
c = nibble + '0';
|
||||
else
|
||||
c = nibble + 'A' - 10;
|
||||
|
||||
_putchar(1, c);
|
||||
}
|
||||
}
|
||||
|
||||
void print_word(int word)
|
||||
{
|
||||
int i;
|
||||
unsigned char c, nibble;
|
||||
|
||||
for (i=0; i < 4; i++)
|
||||
{
|
||||
c = (char) (word >> 24);
|
||||
print_byte(c);
|
||||
word <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// PrintBuffer8()
|
||||
// Prints byte buffer as hex and ascii interpretation
|
||||
// ---------------------------------------------------------------------------------
|
||||
// _Parameters :
|
||||
// pBuf: : IN: Buffer to display
|
||||
// nbpr : Number of bytes per row to display
|
||||
// len : Length of input buffer
|
||||
// _Return: none
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
void PrintBuffer8(uint8_t *pBuf, int nbpr, int len)
|
||||
{
|
||||
memdump(pBuf, 1, nbpr, len);
|
||||
}
|
||||
|
||||
void memdump(uint8_t *pBuf, int print_offset_only, int num_bytes_per_row, int len)
|
||||
{
|
||||
int i, j, cnt_hex, cnt_asc, base;
|
||||
unsigned char c;
|
||||
|
||||
i = j = 0;
|
||||
cnt_hex = len;
|
||||
cnt_asc = len;
|
||||
base = 0;
|
||||
if (!print_offset_only)
|
||||
base = (int)pBuf;
|
||||
|
||||
do
|
||||
{
|
||||
print_word(base + i);
|
||||
sputs(": ");
|
||||
for (j=0; j < num_bytes_per_row; j++)
|
||||
{
|
||||
if (cnt_hex)
|
||||
{
|
||||
print_byte(pBuf[i+j]);
|
||||
sputs(" ");
|
||||
cnt_hex--;
|
||||
}
|
||||
else
|
||||
{
|
||||
sputs(" ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sputs(" ");
|
||||
for (j=0; j < num_bytes_per_row; j++)
|
||||
{
|
||||
if (cnt_asc)
|
||||
{
|
||||
c = pBuf[i+j];
|
||||
if((c < 0x20) || (c > 0x7F))
|
||||
c = '.';
|
||||
|
||||
_putchar(1, c);
|
||||
cnt_asc--;
|
||||
}
|
||||
else
|
||||
{
|
||||
sputs(" ");
|
||||
}
|
||||
}
|
||||
sputs("\n");
|
||||
i += num_bytes_per_row;
|
||||
|
||||
} while (cnt_hex);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef LIBSYS_H
|
||||
#define LIBSYS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <board.h>
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------
|
||||
|
||||
#define NO_ERROR LSYS_SUCCESS
|
||||
#define ERROR LSYS_ERR_BASE
|
||||
#define LSYS_SUCCESS 0
|
||||
#define LSYS_ERR_BASE 0x80000000
|
||||
|
||||
#define IS_ERROR(e) ((e & LSYS_ERR_BASE) == LSYS_ERR_BASE)
|
||||
|
||||
void enter_critical();
|
||||
void exit_critical();
|
||||
|
||||
int write(int file, char *ptr, int len);
|
||||
int sputs(char const *pStr);
|
||||
void print_byte(char byte);
|
||||
void print_word(int word);
|
||||
void _exit (int exitcode);
|
||||
void sleep(unsigned ms);
|
||||
void usleep(unsigned us);
|
||||
|
||||
void PrintBuffer8(uint8_t *pBuf, int nbpr, int len);
|
||||
void memdump(uint8_t *pBuf, int print_offset_only, int num_bytes_per_row, int len);
|
||||
|
||||
#endif // LIBSYS_H
|
||||
|
||||
@@ -0,0 +1,738 @@
|
||||
#include <sys/times.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "libsys.h"
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
// ---------------------------------------------------------------------------------
|
||||
void flush(UINT32 port);
|
||||
UINT32 GetPort(int file);
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------------
|
||||
void libsys_init(void)
|
||||
{
|
||||
UINT32 volatile *pITIM_ctrl = (UINT32*)SYS_ITIM_CTRL;
|
||||
|
||||
// Disable timers
|
||||
*pITIM_ctrl = 0;
|
||||
|
||||
// Initialzie syscall support
|
||||
syscalls_init();
|
||||
|
||||
// Initialzie interrupt support
|
||||
interrupt_init();
|
||||
|
||||
// flush stdin
|
||||
flush(GetPort(0));
|
||||
|
||||
// Do some initializations here
|
||||
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PORT_IN_UART_0 = 0,
|
||||
PORT_IN_UART_1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PORT_OUT_UART0 = 0,
|
||||
PORT_OUT_UART1
|
||||
};
|
||||
|
||||
|
||||
UINT32 GetPort(int file)
|
||||
{
|
||||
if (file == 0) // STDIN
|
||||
return PORT_IN_UART_0;
|
||||
|
||||
if (file == 1) // STDOUT
|
||||
return PORT_OUT_UART0;
|
||||
|
||||
if (file == 2) // STDERR
|
||||
return PORT_OUT_UART0;
|
||||
|
||||
if (file == 10) // AUX0
|
||||
return PORT_IN_UART_1;
|
||||
|
||||
if (file == 11) // AUX1
|
||||
return PORT_OUT_UART1;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
IF_TYPE_INVALID = 0,
|
||||
IF_TYPE_UART
|
||||
};
|
||||
|
||||
typedef struct _suart_if_t
|
||||
{
|
||||
volatile UINT32 *pCTRL;
|
||||
volatile UINT32 *pDATA;
|
||||
volatile UINT32 *pBAUD;
|
||||
} uart_if_t;
|
||||
|
||||
typedef struct _scon_if_in_t
|
||||
{
|
||||
UINT32 type;
|
||||
void *pIF;
|
||||
} con_if_in_t;
|
||||
|
||||
typedef struct _scon_if_out_t
|
||||
{
|
||||
UINT32 type;
|
||||
void *pIF;
|
||||
} con_if_out_t;
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Globals
|
||||
// ---------------------------------------------------------------------------------
|
||||
static uart_if_t uart_if[2] =
|
||||
{
|
||||
{(UINT32*)SYS_UART0_STAT, (UINT32*)SYS_UART0_DATA, (UINT32*)SYS_UART0_BAUD},
|
||||
{(UINT32*)SYS_UART1_STAT, (UINT32*)SYS_UART1_DATA, (UINT32*)SYS_UART1_BAUD}
|
||||
};
|
||||
|
||||
static con_if_in_t con_if_in[] =
|
||||
{
|
||||
{IF_TYPE_UART, &uart_if[0]},
|
||||
{IF_TYPE_UART, &uart_if[1]},
|
||||
{IF_TYPE_INVALID, NULL}
|
||||
};
|
||||
|
||||
static con_if_out_t con_if_out[] =
|
||||
{
|
||||
{IF_TYPE_UART, &uart_if[0]},
|
||||
{IF_TYPE_UART, &uart_if[1]},
|
||||
{IF_TYPE_INVALID, NULL}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// MIPS specific
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
UINT32 CP0_SR_read(void)
|
||||
{
|
||||
UINT32 result;
|
||||
|
||||
__asm__
|
||||
(
|
||||
"mfc0 %[val], $12\n"
|
||||
: [val] "=r" (result)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CP0_SR_write(UINT32 val)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"mtc0 %[val], $12\n"
|
||||
: /* no output */
|
||||
: [val] "r" (val)
|
||||
);
|
||||
}
|
||||
|
||||
UINT32 CP0_CR_read(void)
|
||||
{
|
||||
UINT32 result;
|
||||
|
||||
__asm__
|
||||
(
|
||||
"mfc0 %[val], $13\n"
|
||||
: [val] "=r" (result)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CP0_CR_write(UINT32 val)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"mtc0 %[val], $13\n"
|
||||
:
|
||||
: [val] "r" (val)
|
||||
);
|
||||
}
|
||||
|
||||
UINT32 CP0_TR_read(void)
|
||||
{
|
||||
UINT32 result;
|
||||
|
||||
__asm__
|
||||
(
|
||||
"mfc0 %[val], $31\n"
|
||||
: [val] "=r" (result)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CP0_TR_write(UINT32 val)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"mtc0 %[val], $31\n"
|
||||
:
|
||||
: [val] "r" (val)
|
||||
);
|
||||
}
|
||||
|
||||
UINT32 CP0_PRID_read(void)
|
||||
{
|
||||
UINT32 result;
|
||||
|
||||
__asm__
|
||||
(
|
||||
"mfc0 %[val], $15\n"
|
||||
: [val] "=r" (result)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CP0_TR_write_ptr(UINT32* pPtr)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"swc0 $31, 0(%[pPtr])\n"
|
||||
:
|
||||
: [pPtr] "r" (pPtr)
|
||||
);
|
||||
}
|
||||
|
||||
void CP0_TR_read_ptr(UINT32* pPtr)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"lwc0 $31, 0(%[pPtr])\n"
|
||||
:
|
||||
: [pPtr] "r" (pPtr)
|
||||
);
|
||||
}
|
||||
|
||||
void ICACHE_invalidate_all(void)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"cop0 32\n"
|
||||
);
|
||||
}
|
||||
|
||||
void ICACHE_invalidate_at(UINT32* pPtr)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"mtc0 %[pPtr], $31\n"
|
||||
"cop0 33\n"
|
||||
:
|
||||
: [pPtr] "r" (pPtr)
|
||||
);
|
||||
}
|
||||
|
||||
void DCACHE_invalidate_all(void)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"cop0 34\n"
|
||||
);
|
||||
}
|
||||
|
||||
void DCACHE_invalidate_at(UINT32* pPtr)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"mtc0 %[pPtr], $31\n"
|
||||
"cop0 35\n"
|
||||
:
|
||||
: [pPtr] "r" (pPtr)
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------------
|
||||
// Low-level I/O
|
||||
// ------------------------------------
|
||||
int UART_readchar(uart_if_t *pIF)
|
||||
{
|
||||
if (!pIF)
|
||||
return -1;
|
||||
|
||||
if (SYS_UART_BIT_RX_AVAIL & *pIF->pCTRL)
|
||||
return (*pIF->pDATA & 0xFF);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void UART_writechar(uart_if_t *pIF, char c)
|
||||
{
|
||||
if (!pIF)
|
||||
return;
|
||||
|
||||
while((SYS_UART_BIT_TX_HALFFULL & *pIF->pCTRL) != 0);
|
||||
|
||||
*pIF->pDATA = (UINT32)c;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
void flush(UINT32 port)
|
||||
{
|
||||
int c;
|
||||
con_if_in_t *pIF;
|
||||
|
||||
pIF = &con_if_in[port];
|
||||
|
||||
do
|
||||
{
|
||||
switch(pIF->type)
|
||||
{
|
||||
case IF_TYPE_UART:
|
||||
c = UART_readchar((uart_if_t*)pIF->pIF);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} while(c > 0);
|
||||
}
|
||||
|
||||
char readchar(UINT32 port)
|
||||
{
|
||||
int c;
|
||||
con_if_in_t *pIF;
|
||||
|
||||
pIF = &con_if_in[port];
|
||||
|
||||
do
|
||||
{
|
||||
switch(pIF->type)
|
||||
{
|
||||
case IF_TYPE_UART:
|
||||
c = UART_readchar((uart_if_t*)pIF->pIF);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} while(c < 0);
|
||||
|
||||
return (char)c;
|
||||
}
|
||||
|
||||
void writechar(UINT32 port, char c)
|
||||
{
|
||||
con_if_out_t *pIF;
|
||||
|
||||
pIF = &con_if_out[port];
|
||||
|
||||
switch(pIF->type)
|
||||
{
|
||||
case IF_TYPE_UART:
|
||||
UART_writechar((uart_if_t*)pIF->pIF, c);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _putchar(UINT32 port, char c)
|
||||
{
|
||||
|
||||
con_if_out_t *pIF;
|
||||
|
||||
pIF = &con_if_out[port];
|
||||
|
||||
switch(pIF->type)
|
||||
{
|
||||
case IF_TYPE_UART:
|
||||
if (c == 0x0A)
|
||||
UART_writechar((uart_if_t*)pIF->pIF, 0x0D);
|
||||
UART_writechar((uart_if_t*)pIF->pIF, c);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char _getchar(void)
|
||||
{
|
||||
return readchar(GetPort(0));
|
||||
}
|
||||
|
||||
void _exit (int exitcode)
|
||||
{
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
while(1);
|
||||
}
|
||||
|
||||
void sleep(unsigned ms)
|
||||
{
|
||||
unsigned stop;
|
||||
struct tms t;
|
||||
|
||||
times(&t);
|
||||
stop = t.tms_utime + ms;
|
||||
|
||||
do
|
||||
{
|
||||
times(&t);
|
||||
} while (t.tms_utime < stop);
|
||||
|
||||
}
|
||||
|
||||
void usleep(unsigned us)
|
||||
{
|
||||
unsigned stop_us, stop_s, curr_us, curr_s;
|
||||
struct timeval t;
|
||||
|
||||
if (!us)
|
||||
return;
|
||||
|
||||
gettimeofday(&t, NULL);
|
||||
stop_s = (unsigned)t.tv_sec;
|
||||
stop_us = (unsigned)t.tv_usec + us;
|
||||
if (stop_us >= 1E6)
|
||||
{
|
||||
stop_us -= 1E6;
|
||||
stop_s++;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
gettimeofday(&t, NULL);
|
||||
curr_s = (unsigned)t.tv_sec;
|
||||
curr_us = (unsigned)t.tv_usec;
|
||||
} while ((curr_s < stop_s) || (curr_us < stop_us));
|
||||
|
||||
}
|
||||
|
||||
int getrusage(int who, struct rusage *usage)
|
||||
{
|
||||
volatile long *pReg_usec = (long*)SYS_TIMER_USEC;
|
||||
volatile long *pReg_sec = (long*)SYS_TIMER_SEC;
|
||||
|
||||
// who: RUSAGE_SELF or RUSAGE_CHILDREN
|
||||
usage->ru_utime.tv_usec = *pReg_usec;
|
||||
usage->ru_utime.tv_sec = *pReg_sec;
|
||||
usage->ru_stime.tv_usec = *pReg_usec;
|
||||
usage->ru_stime.tv_sec = *pReg_sec;
|
||||
}
|
||||
|
||||
clock_t times(struct tms *buffer)
|
||||
{
|
||||
volatile long *pReg_usec = (long*)SYS_TIMER_USEC;
|
||||
volatile long *pReg_sec = (long*)SYS_TIMER_SEC;
|
||||
long sec;
|
||||
long usec;
|
||||
|
||||
sec = *pReg_sec;
|
||||
usec = *pReg_usec;
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
buffer->tms_utime = sec*1000 + usec/1000;
|
||||
buffer->tms_stime = 0;
|
||||
buffer->tms_cutime = 0;
|
||||
buffer->tms_cstime = 0;
|
||||
}
|
||||
|
||||
return (clock_t)sec;
|
||||
}
|
||||
|
||||
int gettimeofday(struct timeval *tp, void *tzp)
|
||||
{
|
||||
volatile long *pReg_usec = (long*)SYS_TIMER_USEC;
|
||||
volatile long *pReg_sec = (long*)SYS_TIMER_SEC;
|
||||
|
||||
if (tp)
|
||||
{
|
||||
tp->tv_sec = *pReg_sec;
|
||||
tp->tv_usec = *pReg_usec;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int settimeofday(const struct timeval *tp, const struct timezone *tzp)
|
||||
{
|
||||
volatile long *pReg_usec = (long*)SYS_TIMER_USEC;
|
||||
volatile long *pReg_sec = (long*)SYS_TIMER_SEC;
|
||||
div_t res;
|
||||
|
||||
res = div(tp->tv_usec, 1E6);
|
||||
|
||||
if (tp)
|
||||
{
|
||||
*pReg_usec = res.rem;
|
||||
*pReg_sec = tp->tv_sec + res.quot;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
caddr_t sbrk(int incr)
|
||||
{
|
||||
extern char end;
|
||||
extern char stack_ptr;
|
||||
static char *heap_end;
|
||||
char *prev_heap_end;
|
||||
|
||||
if (heap_end == 0)
|
||||
{
|
||||
heap_end = &end;
|
||||
}
|
||||
|
||||
prev_heap_end = heap_end;
|
||||
if (heap_end + incr > &stack_ptr)
|
||||
{
|
||||
// sputs("Heap and stack collision\n");
|
||||
// sputs("Stack Ptr = ");print_word(&stack_ptr);sputs("\n");
|
||||
// sputs("Heap end = ");print_word(heap_end);sputs("\n");
|
||||
// sputs("Increment = ");print_word(incr);sputs("\n");
|
||||
exit(1);
|
||||
}
|
||||
heap_end += incr;
|
||||
return (caddr_t) prev_heap_end;
|
||||
}
|
||||
|
||||
int fstat(int file, struct stat *st)
|
||||
{
|
||||
// sputs("fstat ("); print_word(file); sputs(")\n");
|
||||
st->st_mode = S_IFCHR;
|
||||
st->st_blksize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lseek(int file, int ptr, int dir)
|
||||
{
|
||||
// sputs("lseek ("); print_word(file); sputs(")\n");
|
||||
errno = ESPIPE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int open(const char *name, int flags, int mode)
|
||||
{
|
||||
// sputs("open (\""); sputs(name); sputs("\")\n");
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int close(int file)
|
||||
{
|
||||
// sputs("close ("); print_word(file); sputs(")\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read(int file, char *ptr, int len)
|
||||
{
|
||||
UINT32 port;
|
||||
int i;
|
||||
char c;
|
||||
|
||||
// sputs("read (file="); print_word(file); sputs(", len ="); print_word(len); sputs(")\n");
|
||||
i = 0;
|
||||
port = GetPort(file);
|
||||
|
||||
while (i < len)
|
||||
{
|
||||
c = readchar(port);
|
||||
|
||||
if (c == 0x04)
|
||||
break;
|
||||
|
||||
if ((c == 0x0D) || (c == 0x0A))
|
||||
{
|
||||
writechar(port, 0x0D);
|
||||
ptr[i++] = 0x0D;
|
||||
writechar(port, 0x0A);
|
||||
ptr[i++] = 0x0A;
|
||||
break;
|
||||
}
|
||||
|
||||
writechar(port, c);
|
||||
ptr[i++] = c;
|
||||
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int write(int file, char *ptr, int len)
|
||||
{
|
||||
UINT32 port;
|
||||
int i = 0;
|
||||
|
||||
// sputs("write ("); print_word(file); sputs(")\n");
|
||||
|
||||
port = GetPort(file);
|
||||
for (i=0; i < len; i++)
|
||||
_putchar(port, *ptr++);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int isatty(int file)
|
||||
{
|
||||
// sputs("isatty ("); print_word(file); sputs(")\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int getpid(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#include <errno.h>
|
||||
#undef errno
|
||||
extern int errno;
|
||||
int kill(int pid, int sig)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#include <errno.h>
|
||||
#undef errno
|
||||
extern int errno;
|
||||
int link(char *old, char *new)
|
||||
{
|
||||
errno = EMLINK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#include <errno.h>
|
||||
#undef errno
|
||||
extern int errno;
|
||||
int unlink(char *name)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sputs(char *pStr)
|
||||
{
|
||||
char *start;
|
||||
start = pStr;
|
||||
|
||||
while(*pStr)
|
||||
_putchar(GetPort(1), *(pStr++));
|
||||
|
||||
return pStr - start;
|
||||
}
|
||||
|
||||
void print_byte(char byte)
|
||||
{
|
||||
int i;
|
||||
unsigned char c, nibble;
|
||||
|
||||
for (i=0; i < 2; i++)
|
||||
{
|
||||
nibble = (char)((byte >> 4) & 0xF);
|
||||
byte <<= 4;
|
||||
|
||||
if (nibble < 10)
|
||||
c = nibble + '0';
|
||||
else
|
||||
c = nibble + 'A' - 10;
|
||||
|
||||
_putchar(GetPort(1), c);
|
||||
}
|
||||
}
|
||||
|
||||
void print_word(int word)
|
||||
{
|
||||
int i;
|
||||
unsigned char c, nibble;
|
||||
|
||||
for (i=0; i < 4; i++)
|
||||
{
|
||||
c = (char) (word >> 24);
|
||||
print_byte(c);
|
||||
word <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// PrintBuffer8()
|
||||
// Prints byte buffer as hex and ascii interpretation
|
||||
// ---------------------------------------------------------------------------------
|
||||
// _Parameters :
|
||||
// pBuf: : IN: Buffer to display
|
||||
// nbpr : Number of bytes per row to display
|
||||
// len : Length of input buffer
|
||||
// _Return: none
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
void PrintBuffer8(UINT8 *pBuf, int nbpr, int len)
|
||||
{
|
||||
memdump(pBuf, 1, nbpr, len);
|
||||
}
|
||||
|
||||
void memdump(UINT8 *pBuf, int print_offset_only, int num_bytes_per_row, int len)
|
||||
{
|
||||
int i, j, cnt_hex, cnt_asc, base;
|
||||
unsigned char c;
|
||||
|
||||
i = j = 0;
|
||||
cnt_hex = len;
|
||||
cnt_asc = len;
|
||||
base = 0;
|
||||
if (!print_offset_only)
|
||||
base = (int)pBuf;
|
||||
|
||||
do
|
||||
{
|
||||
print_word(base + i);
|
||||
sputs(": ");
|
||||
for (j=0; j < num_bytes_per_row; j++)
|
||||
{
|
||||
if (cnt_hex)
|
||||
{
|
||||
print_byte(pBuf[i+j]);
|
||||
sputs(" ");
|
||||
cnt_hex--;
|
||||
}
|
||||
else
|
||||
{
|
||||
sputs(" ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sputs(" ");
|
||||
for (j=0; j < num_bytes_per_row; j++)
|
||||
{
|
||||
if (cnt_asc)
|
||||
{
|
||||
c = pBuf[i+j];
|
||||
if((c < 0x20) || (c > 0x7F))
|
||||
c = '.';
|
||||
|
||||
_putchar(GetPort(1), c);
|
||||
cnt_asc--;
|
||||
}
|
||||
else
|
||||
{
|
||||
sputs(" ");
|
||||
}
|
||||
}
|
||||
sputs("\n");
|
||||
i += num_bytes_per_row;
|
||||
|
||||
} while (cnt_hex);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,626 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "xcpt.h"
|
||||
#include "libsys.h"
|
||||
#include "mips_dis.h"
|
||||
#include "cop0.h"
|
||||
|
||||
extern int instr_info(unsigned iword, instr_info_t *pInfo);
|
||||
extern int tdisasm(char *buffer, unsigned address, unsigned iword, unsigned char ext, unsigned *regmask, unsigned *symbol_value, unsigned *ls_register);
|
||||
|
||||
#define DBG_PRINT_REG_CHG(tag_str, reg, reg_last) \
|
||||
dbg_puts(tag_str); \
|
||||
dbg_print_word(reg); \
|
||||
dbg_puts(reg != reg_last ? "*" : " "); \
|
||||
dbg_puts(" ");
|
||||
|
||||
#define MAX_USER_BP 16
|
||||
#define BP_MASK_ID 0x00FFF
|
||||
#define BP_MASK_TYPE 0xFF000
|
||||
|
||||
#define BP_GET_ID(bp) ((bp >> 6) & 0xFFF)
|
||||
|
||||
#define BP_USER_BASE 0x10000
|
||||
#define BP_USER(id) (((BP_USER_BASE + id) << 6) | 0x0D)
|
||||
|
||||
#define BP_MGMT_BASE_SS 0x20000
|
||||
#define BP_MGMT_SS(id) (((BP_MGMT_BASE_SS + id) << 6) | 0x0D)
|
||||
|
||||
#define BP_MGMT_BASE_RU 0x30000
|
||||
#define BP_MGMT_RU(id) (((BP_MGMT_BASE_RU + id) << 6) | 0x0D)
|
||||
|
||||
static char g_buf[80];
|
||||
static int DEBUG_PRINT = 0;
|
||||
static int SHOW_NUM_INSTR = 5;
|
||||
|
||||
enum
|
||||
{
|
||||
STATE_INIT = 0,
|
||||
STATE_RUN,
|
||||
STATE_STEP_SINGLE,
|
||||
STATE_STEP_PROC,
|
||||
STATE_NUM_ENTRIES
|
||||
};
|
||||
|
||||
static int g_state = STATE_INIT;
|
||||
static char *g_state_names[STATE_NUM_ENTRIES] = {"Init", "Run", "Single step", "Precedure step"};
|
||||
|
||||
typedef struct _sbp_t
|
||||
{
|
||||
uint32_t *pAddr;
|
||||
uint32_t instr;
|
||||
} bp_t;
|
||||
|
||||
static EXCEPTION_CONTEXT xcp_last;
|
||||
static bp_t user_bp[MAX_USER_BP];
|
||||
static bp_t mgmt_bp_ss[2];
|
||||
static bp_t mgmt_bp_ru[2];
|
||||
static int g_is_ss;
|
||||
static int g_bp_count;
|
||||
|
||||
extern void dbg_putchar(char c);
|
||||
extern char dbg_getchar();
|
||||
|
||||
void dbg_puts(const char *buffer)
|
||||
{
|
||||
while(*buffer)
|
||||
{
|
||||
dbg_putchar(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
void dbg_print_byte(char byte)
|
||||
{
|
||||
int i;
|
||||
unsigned char c, nibble;
|
||||
|
||||
for (i=0; i < 2; i++)
|
||||
{
|
||||
nibble = (char)((byte >> 4) & 0xF);
|
||||
byte <<= 4;
|
||||
|
||||
if (nibble < 10)
|
||||
c = nibble + '0';
|
||||
else
|
||||
c = nibble + 'A' - 10;
|
||||
|
||||
dbg_putchar(c);
|
||||
}
|
||||
}
|
||||
|
||||
void dbg_print_word(int word)
|
||||
{
|
||||
int i;
|
||||
unsigned char c;
|
||||
|
||||
for (i=0; i < 4; i++)
|
||||
{
|
||||
c = (char) (word >> 24);
|
||||
dbg_print_byte(c);
|
||||
word <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
int dbg_gets(char *buffer, size_t size)
|
||||
{
|
||||
size_t len = 0;
|
||||
while(size)
|
||||
{
|
||||
char c = dbg_getchar();
|
||||
if (c == 0x0A || c == 0x0D)
|
||||
{
|
||||
if (len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[len++] = c;
|
||||
dbg_putchar(c);
|
||||
if (len == size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer[len] = 0;
|
||||
dbg_putchar(0x0D);
|
||||
dbg_putchar(0x0A);
|
||||
return len;
|
||||
}
|
||||
|
||||
void dbg_puts_d(const char *buffer)
|
||||
{
|
||||
if (DEBUG_PRINT)
|
||||
{
|
||||
dbg_puts(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void dbg_print_word_d(int word)
|
||||
{
|
||||
if (DEBUG_PRINT)
|
||||
{
|
||||
dbg_print_word(word);
|
||||
}
|
||||
}
|
||||
|
||||
void dbg_strcpy(char *pDst, const char *pSrc)
|
||||
{
|
||||
while(*pSrc)
|
||||
{
|
||||
*(pDst++) = *(pSrc++);
|
||||
}
|
||||
*pDst = *pSrc;
|
||||
}
|
||||
|
||||
void* dbg_memset(void *pDst, int value, size_t size)
|
||||
{
|
||||
char *dst = (char*)pDst;
|
||||
|
||||
while(size)
|
||||
{
|
||||
*(dst++) = (char)value;
|
||||
size--;
|
||||
}
|
||||
return (void*)dst;
|
||||
}
|
||||
|
||||
void* dbg_memcpy(void *pDst, const void *pSrc, size_t size )
|
||||
{
|
||||
char *dst = (char*)pDst;
|
||||
char *src = (char*)pSrc;
|
||||
|
||||
while(size)
|
||||
{
|
||||
*(dst++) = *(src++);
|
||||
size--;
|
||||
}
|
||||
return (void*)dst;
|
||||
}
|
||||
|
||||
int IsBreak(uint32_t instr)
|
||||
{
|
||||
return ((instr & 0xFC00003F) == 0x0000000D);
|
||||
}
|
||||
|
||||
uint32_t BreakGetType(uint32_t instr)
|
||||
{
|
||||
return (instr >> 6) & BP_MASK_TYPE;
|
||||
}
|
||||
|
||||
void print_regs(struct xcptcontext * xcp, struct xcptcontext * xcp_last)
|
||||
{
|
||||
DBG_PRINT_REG_CHG(" Status : ", xcp->sr, xcp_last->sr);
|
||||
DBG_PRINT_REG_CHG(" Cause : ", xcp->cr, xcp_last->cr);
|
||||
DBG_PRINT_REG_CHG(" EPC : ", xcp->epc, xcp_last->epc);
|
||||
DBG_PRINT_REG_CHG("BadAddr : ", xcp->baddr, xcp_last->baddr);
|
||||
dbg_puts("\n");
|
||||
DBG_PRINT_REG_CHG(" MDLO : ", xcp->mdlo, xcp_last->mdlo);
|
||||
DBG_PRINT_REG_CHG(" MDHI : ", xcp->mdhi, xcp_last->mdhi);
|
||||
|
||||
dbg_puts("\n");
|
||||
|
||||
dbg_puts("Registers:\n");
|
||||
DBG_PRINT_REG_CHG(" 0 (ze) : ", xcp->regs[0], xcp_last->regs[0]);
|
||||
DBG_PRINT_REG_CHG(" 1 (at) : ", xcp->regs[1], xcp_last->regs[1]);
|
||||
DBG_PRINT_REG_CHG(" 2 (v0) : ", xcp->regs[2], xcp_last->regs[2]);
|
||||
DBG_PRINT_REG_CHG(" 3 (v1) : ", xcp->regs[3], xcp_last->regs[3]);
|
||||
dbg_puts("\n");
|
||||
DBG_PRINT_REG_CHG(" 4 (a0) : ", xcp->regs[4], xcp_last->regs[4]);
|
||||
DBG_PRINT_REG_CHG(" 5 (a1) : ", xcp->regs[5], xcp_last->regs[5]);
|
||||
DBG_PRINT_REG_CHG(" 6 (a2) : ", xcp->regs[6], xcp_last->regs[6]);
|
||||
DBG_PRINT_REG_CHG(" 7 (a3) : ", xcp->regs[7], xcp_last->regs[7]);
|
||||
dbg_puts("\n");
|
||||
DBG_PRINT_REG_CHG(" 8 (t0) : ", xcp->regs[8], xcp_last->regs[8]);
|
||||
DBG_PRINT_REG_CHG(" 9 (t1) : ", xcp->regs[9], xcp_last->regs[9]);
|
||||
DBG_PRINT_REG_CHG("10 (t2) : ", xcp->regs[10], xcp_last->regs[10]);
|
||||
DBG_PRINT_REG_CHG("11 (t3) : ", xcp->regs[11], xcp_last->regs[11]);
|
||||
dbg_puts("\n");
|
||||
DBG_PRINT_REG_CHG("12 (t4) : ", xcp->regs[12], xcp_last->regs[12]);
|
||||
DBG_PRINT_REG_CHG("13 (t5) : ", xcp->regs[13], xcp_last->regs[13]);
|
||||
DBG_PRINT_REG_CHG("14 (t6) : ", xcp->regs[14], xcp_last->regs[14]);
|
||||
DBG_PRINT_REG_CHG("15 (t7) : ", xcp->regs[15], xcp_last->regs[15]);
|
||||
dbg_puts("\n");
|
||||
DBG_PRINT_REG_CHG("16 (s0) : ", xcp->regs[16], xcp_last->regs[16]);
|
||||
DBG_PRINT_REG_CHG("17 (s1) : ", xcp->regs[17], xcp_last->regs[17]);
|
||||
DBG_PRINT_REG_CHG("18 (s2) : ", xcp->regs[18], xcp_last->regs[18]);
|
||||
DBG_PRINT_REG_CHG("19 (s3) : ", xcp->regs[19], xcp_last->regs[19]);
|
||||
dbg_puts("\n");
|
||||
DBG_PRINT_REG_CHG("20 (s4) : ", xcp->regs[20], xcp_last->regs[20]);
|
||||
DBG_PRINT_REG_CHG("21 (s5) : ", xcp->regs[21], xcp_last->regs[21]);
|
||||
DBG_PRINT_REG_CHG("22 (s6) : ", xcp->regs[22], xcp_last->regs[22]);
|
||||
DBG_PRINT_REG_CHG("23 (s7) : ", xcp->regs[23], xcp_last->regs[23]);
|
||||
dbg_puts("\n");
|
||||
DBG_PRINT_REG_CHG("24 (t8) : ", xcp->regs[24], xcp_last->regs[24]);
|
||||
DBG_PRINT_REG_CHG("25 (t9) : ", xcp->regs[25], xcp_last->regs[25]);
|
||||
DBG_PRINT_REG_CHG("26 (k0) : ", xcp->regs[26], xcp_last->regs[26]);
|
||||
DBG_PRINT_REG_CHG("27 (k1) : ", xcp->regs[27], xcp_last->regs[27]);
|
||||
dbg_puts("\n");
|
||||
DBG_PRINT_REG_CHG("28 (gp) : ", xcp->regs[28], xcp_last->regs[28]);
|
||||
DBG_PRINT_REG_CHG("29 (sp) : ", xcp->regs[29], xcp_last->regs[29]);
|
||||
DBG_PRINT_REG_CHG("30 (fp) : ", xcp->regs[30], xcp_last->regs[30]);
|
||||
DBG_PRINT_REG_CHG("31 (ra) : ", xcp->regs[31], xcp_last->regs[31]);
|
||||
dbg_puts("\n");
|
||||
}
|
||||
|
||||
void set_mgmt_break(uint32_t *pAddr_break, int index)
|
||||
{
|
||||
mgmt_bp_ss[index].pAddr = NULL;
|
||||
mgmt_bp_ss[index].instr = 0;
|
||||
|
||||
dbg_puts_d("Set management break at ");dbg_print_word_d((long)pAddr_break);dbg_puts_d("\n");
|
||||
// Don't overwrite user breaks
|
||||
if (IsBreak(*pAddr_break) && (BreakGetType(*pAddr_break) == BP_USER_BASE))
|
||||
{
|
||||
dbg_puts_d("Instruction at address ");dbg_print_word_d((long)pAddr_break);dbg_puts_d(" is user break\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save original instruction
|
||||
mgmt_bp_ss[index].pAddr = pAddr_break;
|
||||
mgmt_bp_ss[index].instr = *(mgmt_bp_ss[index].pAddr);
|
||||
// Replace instruction with managment breakpoint
|
||||
*(mgmt_bp_ss[index].pAddr) = BP_MGMT_SS(index+1);
|
||||
ICACHE_invalidate_at(mgmt_bp_ss[index].pAddr);
|
||||
}
|
||||
}
|
||||
|
||||
void singlestep(struct xcptcontext * xcp, uint32_t *pAddr_curr, uint32_t is_branch_shadow)
|
||||
{
|
||||
|
||||
int junk;
|
||||
uint32_t branch_addr, reg, bp_type;
|
||||
uint32_t *pInstr, *pAddr_prev, *pAddr_next;
|
||||
instr_info_t info;
|
||||
int set_break_at_jump_target = 0;
|
||||
|
||||
pAddr_prev = pAddr_curr - 1;
|
||||
pAddr_next = pAddr_curr + 1;
|
||||
|
||||
mgmt_bp_ss[1].pAddr = NULL;
|
||||
mgmt_bp_ss[1].instr = 0;
|
||||
|
||||
// We have two possible management breaks, if previous instruction was branch or jump
|
||||
if (is_branch_shadow)
|
||||
{
|
||||
int type = instr_info(*pAddr_prev, &info);
|
||||
|
||||
tdisasm(g_buf, (unsigned int)pAddr_prev, (unsigned int)*pAddr_prev, 0, &junk, (unsigned int*)&branch_addr, (unsigned int*)®);
|
||||
// Is jump target stored in register
|
||||
if (type == INSTR_TYPE_JUMP || type == INSTR_TYPE_BRANCH)
|
||||
{
|
||||
if (info.flags & (INSTR_FLAGS_JUMP_REGISTER|INSTR_FLAGS_BRANCH_REGISTER))
|
||||
{
|
||||
branch_addr = xcp->regs[reg&0x1F];
|
||||
}
|
||||
}
|
||||
// Don't overwrite user breaks
|
||||
if (IsBreak(branch_addr) && (BreakGetType(branch_addr) == BP_USER_BASE))
|
||||
{
|
||||
dbg_puts_d("Instruction at branch address ");dbg_print_word_d((long)branch_addr);dbg_puts_d(" is user break\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
set_break_at_jump_target = 1;
|
||||
}
|
||||
}
|
||||
set_mgmt_break(pAddr_next, 0);
|
||||
if (set_break_at_jump_target)
|
||||
{
|
||||
set_mgmt_break((uint32_t*)branch_addr, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int dbg_handler(struct xcptcontext * xcp)
|
||||
{
|
||||
|
||||
uint32_t bp_addr, bp_index = 0, branch_addr, reg, result, bp_type;
|
||||
int junk, i, leave_isr, is_branch_shadow, is_user_bp;
|
||||
uint32_t *pInstr, *pAddr_curr, *pAddr_prev, *pAddr_next;
|
||||
instr_info_t info;
|
||||
|
||||
is_user_bp = 0;
|
||||
pAddr_curr = (uint32_t*)xcp->epc;
|
||||
is_branch_shadow = ((xcp->cr & 0x80000000) == 0x80000000);
|
||||
if (is_branch_shadow)
|
||||
pAddr_curr++;
|
||||
|
||||
pAddr_prev = pAddr_curr - 1;
|
||||
pAddr_next = pAddr_curr + 1;
|
||||
|
||||
if (g_state = STATE_INIT)
|
||||
{
|
||||
dbg_memset(&xcp_last, 0, sizeof(EXCEPTION_CONTEXT));
|
||||
}
|
||||
|
||||
dbg_puts_d("\n");dbg_puts_d(g_state_names[g_state]);dbg_puts_d("\n");
|
||||
|
||||
if (IsBreak(*pAddr_curr))
|
||||
{
|
||||
bp_type = BreakGetType(*pAddr_curr);
|
||||
|
||||
switch (bp_type)
|
||||
{
|
||||
case BP_MGMT_BASE_SS:
|
||||
|
||||
// Restore original instructions after single-step
|
||||
dbg_puts_d("1. Restore after single-step at ");dbg_print_word_d((long)mgmt_bp_ss[0].pAddr);dbg_puts_d("\n");
|
||||
*(mgmt_bp_ss[0].pAddr) = mgmt_bp_ss[0].instr;
|
||||
ICACHE_invalidate_at(mgmt_bp_ss[0].pAddr);
|
||||
if (mgmt_bp_ss[1].pAddr)
|
||||
{
|
||||
dbg_puts_d("2. Restore after single-step at ");dbg_print_word_d((long)mgmt_bp_ss[1].pAddr);dbg_puts_d("\n");
|
||||
*(mgmt_bp_ss[1].pAddr) = mgmt_bp_ss[1].instr;
|
||||
ICACHE_invalidate_at(mgmt_bp_ss[1].pAddr);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BP_MGMT_BASE_RU:
|
||||
|
||||
bp_index = BP_GET_ID(*pAddr_curr);
|
||||
dbg_puts_d("Restore user break at ");dbg_print_word_d((long)user_bp[bp_index].pAddr);dbg_puts_d("\n");
|
||||
|
||||
*(user_bp[bp_index].pAddr) = BP_USER(bp_index);
|
||||
ICACHE_invalidate_at(user_bp[bp_index].pAddr);
|
||||
|
||||
*(mgmt_bp_ru[0].pAddr) = mgmt_bp_ru[0].instr;
|
||||
ICACHE_invalidate_at(mgmt_bp_ru[0].pAddr);
|
||||
dbg_puts_d("1. Restore after RU at ");dbg_print_word_d((long)mgmt_bp_ru[0].pAddr);dbg_puts_d("\n");
|
||||
if (mgmt_bp_ru[1].pAddr)
|
||||
{
|
||||
*(mgmt_bp_ru[1].pAddr) = mgmt_bp_ru[1].instr;
|
||||
ICACHE_invalidate_at(mgmt_bp_ru[1].pAddr);
|
||||
dbg_puts_d("2. Restore after RU at ");dbg_print_word_d((long)mgmt_bp_ru[1].pAddr);dbg_puts_d("\n");
|
||||
}
|
||||
if (!g_is_ss)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BP_USER_BASE:
|
||||
|
||||
is_user_bp = 1;
|
||||
bp_index = BP_GET_ID(*pAddr_curr);
|
||||
dbg_puts_d("Restore instruction at ");dbg_print_word_d((long)user_bp[bp_index].pAddr);dbg_puts_d("\n");
|
||||
*(user_bp[bp_index].pAddr) = user_bp[bp_index].instr;
|
||||
ICACHE_invalidate_at(user_bp[bp_index].pAddr);
|
||||
break;
|
||||
|
||||
default:
|
||||
dbg_puts_d("Found ordinary break at ");dbg_print_word_d((long)pAddr_curr);dbg_puts_d("\n");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
dbg_puts("\n");
|
||||
print_regs(xcp, &xcp_last);
|
||||
|
||||
pInstr = pAddr_prev;
|
||||
// Disassemble instructions
|
||||
for (i=0; i < SHOW_NUM_INSTR; i++)
|
||||
{
|
||||
dbg_print_word((long)pInstr);
|
||||
if (pInstr != pAddr_curr)
|
||||
{
|
||||
if (IsBreak(*pInstr) && (BreakGetType(*pInstr) == BP_USER_BASE))
|
||||
{
|
||||
tdisasm(g_buf, (long)user_bp[BP_GET_ID(*pInstr)].pAddr, user_bp[BP_GET_ID(*pInstr)].instr, 0, &junk, &junk, &junk);
|
||||
dbg_puts(": b("); dbg_print_byte((char)BP_GET_ID(*pInstr)); dbg_puts(") ");
|
||||
}
|
||||
else
|
||||
{
|
||||
tdisasm(g_buf, (long)pInstr, *pInstr, 0, &junk, &junk, &junk);
|
||||
dbg_puts(": ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tdisasm(g_buf, (long)pInstr, *pInstr, 0, &junk, &junk, &junk);
|
||||
if (is_user_bp)
|
||||
{
|
||||
dbg_puts(": b("); dbg_print_byte((char)bp_index); dbg_puts(")-> ");
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_puts(": -> ");
|
||||
}
|
||||
}
|
||||
dbg_puts(g_buf);
|
||||
dbg_puts("\n");
|
||||
pInstr++;
|
||||
}
|
||||
|
||||
if (is_user_bp)
|
||||
{
|
||||
// Save original instruction
|
||||
mgmt_bp_ru[0].pAddr = pAddr_next;
|
||||
mgmt_bp_ru[0].instr = *(mgmt_bp_ru[0].pAddr);
|
||||
// Replace instruction with managment breakpoint
|
||||
*(mgmt_bp_ru[0].pAddr) = BP_MGMT_RU(bp_index);
|
||||
ICACHE_invalidate_at(mgmt_bp_ru[0].pAddr);
|
||||
mgmt_bp_ru[1].pAddr = NULL;
|
||||
mgmt_bp_ru[1].instr = 0;
|
||||
dbg_puts_d("1. Insert RU-break at ");dbg_print_word_d((long)mgmt_bp_ru[0].pAddr);dbg_puts_d("\n");
|
||||
|
||||
// We have two possible management breaks, if previous instruction was branch or jump
|
||||
if (is_branch_shadow)
|
||||
{
|
||||
int type = instr_info(*pAddr_prev, &info);
|
||||
tdisasm(g_buf, (long)pAddr_prev, *pAddr_prev, 0, &junk, (unsigned int*)&branch_addr, (unsigned int*)®);
|
||||
// Is jump target stored in register
|
||||
if (type == INSTR_TYPE_JUMP || type == INSTR_TYPE_BRANCH)
|
||||
{
|
||||
if (info.flags & (INSTR_FLAGS_JUMP_REGISTER|INSTR_FLAGS_BRANCH_REGISTER))
|
||||
{
|
||||
branch_addr = xcp->regs[reg&0x1F];
|
||||
}
|
||||
}
|
||||
// Save original instruction
|
||||
mgmt_bp_ru[1].pAddr = (uint32_t*)branch_addr;
|
||||
mgmt_bp_ru[1].instr = *(mgmt_bp_ru[1].pAddr);
|
||||
// Replace instruction with managment breakpoint
|
||||
*(mgmt_bp_ru[1].pAddr) = BP_MGMT_RU(bp_index);
|
||||
ICACHE_invalidate_at(mgmt_bp_ru[1].pAddr);
|
||||
dbg_puts_d("2. Insert RU-break at ");dbg_print_word_d((long)mgmt_bp_ru[1].pAddr);dbg_puts_d("\n");
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
char buffer[33];
|
||||
leave_isr = 0;
|
||||
switch(dbg_getchar())
|
||||
{
|
||||
case 'c':
|
||||
g_state = STATE_RUN;
|
||||
leave_isr = 1;
|
||||
g_is_ss = 0;
|
||||
if (IsBreak(*pAddr_curr))
|
||||
{
|
||||
if (BreakGetType(*pAddr_curr) != BP_USER_BASE)
|
||||
{
|
||||
xcp->epc += 4; // Skip ordinary program breaks
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
g_state = STATE_RUN;
|
||||
leave_isr = 1;
|
||||
g_is_ss = 0;
|
||||
dbg_puts("Enter address: ");
|
||||
dbg_gets(buffer, sizeof(buffer));
|
||||
xcp->epc = strtol(buffer, NULL, 16);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
dbg_puts("Enter breakpoint: ");
|
||||
dbg_gets(buffer, sizeof(buffer));
|
||||
bp_addr = strtol(buffer, NULL, 16);
|
||||
dbg_puts("Insert breakpoint at "); dbg_print_word(bp_addr); dbg_puts("\n");
|
||||
|
||||
user_bp[g_bp_count].pAddr = (uint32_t*)bp_addr;
|
||||
user_bp[g_bp_count].instr = *(user_bp[g_bp_count].pAddr);
|
||||
*(user_bp[g_bp_count].pAddr) = BP_USER(g_bp_count);
|
||||
|
||||
tdisasm(g_buf, (long)user_bp[g_bp_count].pAddr, user_bp[g_bp_count].instr, 0, &junk, &junk, &junk);
|
||||
dbg_print_word((long)user_bp[g_bp_count].pAddr);dbg_puts(": b ");dbg_puts(g_buf);dbg_puts("\n");
|
||||
ICACHE_invalidate_at(user_bp[g_bp_count].pAddr);
|
||||
g_bp_count++;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
g_state = STATE_STEP_SINGLE;
|
||||
g_is_ss = 1;
|
||||
leave_isr = 1;
|
||||
|
||||
if (is_user_bp)
|
||||
break;
|
||||
|
||||
if (IsBreak(*pAddr_curr))
|
||||
{
|
||||
if (BreakGetType(*pAddr_curr) == BP_USER_BASE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
xcp->epc += 4; // Skip ordinary program breaks
|
||||
}
|
||||
}
|
||||
|
||||
singlestep(xcp, pAddr_curr, is_branch_shadow);
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
g_state = STATE_STEP_SINGLE;
|
||||
g_is_ss = 1;
|
||||
leave_isr = 1;
|
||||
|
||||
if (is_user_bp)
|
||||
break;
|
||||
|
||||
if (IsBreak(*pAddr_curr))
|
||||
{
|
||||
if (BreakGetType(*pAddr_curr) == BP_USER_BASE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
xcp->epc += 4; // Skip ordinary program breaks
|
||||
}
|
||||
}
|
||||
|
||||
pInstr = pAddr_curr;
|
||||
|
||||
do
|
||||
{
|
||||
result = instr_info(*pInstr, &info);
|
||||
if (result == INSTR_TYPE_JUMP)
|
||||
{
|
||||
if (info.rs == 0x1F)
|
||||
break;
|
||||
}
|
||||
else if (result == INSTR_TYPE_LOAD)
|
||||
{
|
||||
if (info.rs == 0x1F)
|
||||
break;
|
||||
}
|
||||
pInstr++;
|
||||
} while(1);
|
||||
|
||||
dbg_puts_d("Return found at "); dbg_print_word_d((long)pInstr);dbg_puts_d("\n");
|
||||
set_mgmt_break(pInstr, 0);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
g_state = STATE_STEP_PROC;
|
||||
g_is_ss = 1;
|
||||
leave_isr = 1;
|
||||
|
||||
if (is_user_bp)
|
||||
break;
|
||||
|
||||
if (IsBreak(*pAddr_curr))
|
||||
{
|
||||
if (BreakGetType(*pAddr_curr) == BP_USER_BASE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
xcp->epc += 4; // Skip ordinary program breaks
|
||||
}
|
||||
}
|
||||
|
||||
result = instr_info(*pAddr_curr, &info);
|
||||
if ((result == INSTR_TYPE_JUMP) && (info.flags & INSTR_FLAGS_JUMP_LINK))
|
||||
{
|
||||
singlestep(xcp, pAddr_next, 0);
|
||||
dbg_puts_d("Skip sub-routine\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
singlestep(xcp, pAddr_curr, is_branch_shadow);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (!leave_isr);
|
||||
|
||||
dbg_memcpy(&xcp_last, xcp, sizeof(EXCEPTION_CONTEXT));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,825 @@
|
||||
/* +----------------------------------------------------------------+ */
|
||||
/* | Copyright (c) 1994 Stanford University. | */
|
||||
/* | All Rights Reserved. | */
|
||||
/* | | */
|
||||
/* | This software is distributed with *ABSOLUTELY NO SUPPORT* | */
|
||||
/* | and *NO WARRANTY*. Use or reproduction of this code for | */
|
||||
/* | commerical gains is strictly prohibited. Otherwise, you | */
|
||||
/* | are given permission to use or modify this code as long | */
|
||||
/* | as you do not remove this notice. | */
|
||||
/* +----------------------------------------------------------------+ */
|
||||
/* --------------------------------------------------- */
|
||||
/* | Copyright (c) 1986 MIPS Computer Systems, Inc. | */
|
||||
/* | All Rights Reserved. | */
|
||||
/* --------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Copyright 1985 by MIPS Computer Systems, Inc.
|
||||
*/
|
||||
|
||||
/* TORCH disassembler */
|
||||
/* derived from MIPS instruction dissassembler by PGL October 91 */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "mips_dis.h"
|
||||
|
||||
#define false 0
|
||||
#define true 1
|
||||
typedef int boolean;
|
||||
char *strcat();
|
||||
|
||||
#define ZERO 0
|
||||
|
||||
#define COMPILER_NAMES tdis_reg_names[0]
|
||||
#define HARDWARE_NAMES tdis_reg_names[1]
|
||||
#define ASSEMBLER_NAMES tdis_reg_names[2]
|
||||
#define DIS_REG_NAMES(x) tdis_reg_names[x]
|
||||
|
||||
union extension_byte {
|
||||
unsigned char byte;
|
||||
struct { /* extension byte bits in little-endian order */
|
||||
#if (defined __MIPSEB || defined _MIPSEB || defined MIPSEB)
|
||||
unsigned reserved:1;
|
||||
unsigned dyn_nop:1;
|
||||
unsigned rs_boost:2;
|
||||
unsigned rt_boost:2;
|
||||
unsigned rd_boost:2;
|
||||
#elif (defined __MIPSEL || defined _MIPSEL || defined MIPSEL)
|
||||
unsigned rd_boost:2;
|
||||
unsigned rt_boost:2;
|
||||
unsigned rs_boost:2;
|
||||
unsigned dyn_nop:1;
|
||||
unsigned reserved:1;
|
||||
#endif /*MIPSEB*/
|
||||
} e;
|
||||
};
|
||||
|
||||
#define blez_op_T blez_op
|
||||
#define blez_op_N (blez_op | 0x10)
|
||||
#define bgtz_op_T bgtz_op
|
||||
#define bgtz_op_N (bgtz_op | 0x10)
|
||||
#define beq_op_T beq_op
|
||||
#define beq_op_N (beq_op | 0x10)
|
||||
#define bne_op_T bne_op
|
||||
#define bne_op_N (bne_op | 0x10)
|
||||
#define bc_op_T bc_op
|
||||
#define bc_op_N (bc_op | 0x02)
|
||||
|
||||
static char *op_name[64] = {
|
||||
/* 0 */ "special", "regimm","j", "jal", "beq", "bne", "blez", "bgtz",
|
||||
/* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui",
|
||||
/*16 */ "cop0", "cop1", "cop2", "cop3", "beql","bnel","blezl","bgtzl",
|
||||
/*24 */ "op60", "op64", "op68", "op6c", "op70", "op74", "op78", "op7c",
|
||||
/*32 */ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "ld",
|
||||
/*40 */ "sb", "sh", "swl", "sw", "opb0", "opb4", "swr", "sd",
|
||||
/*48 */ "lwc0", "lwc1", "lwc2", "lwc3", "ldc0", "ldc1", "ldc2", "ldc3",
|
||||
/*56 */ "swc0", "swc1", "swc2", "swc3", "sdc0", "sdc1", "sdc2", "sdc3"
|
||||
};
|
||||
|
||||
static char *spec_name[64] = {
|
||||
/* 0*/ "sll", "spec01","srl", "sra", "sllv", "spec05","srlv","srav",
|
||||
/* 8*/ "jr", "jalr", "spec12","spec13","syscall","break","vcall","spec17",
|
||||
/*16*/ "mfhi", "mthi", "mflo", "mtlo", "spec24","spec25","spec26","spec27",
|
||||
/*24*/ "mult", "multu","div", "divu", "spec34","spec35","spec36","spec37",
|
||||
/*32*/ "add", "addu", "sub", "subu", "and", "or", "xor", "nor",
|
||||
/*40*/ "spec50","spec51","slt","sltu", "spec54","spec55","spec56","spec57",
|
||||
/*48*/ "spec60","spec61","spec62","spec63","spec64","spec65","spec66","spec67",
|
||||
/*56*/ "spec70","spec71","spec72","spec73","spec74","spec75","spec76","spec77"
|
||||
};
|
||||
|
||||
static char *bcond_name[32] = {
|
||||
"bltz",
|
||||
"bgez",
|
||||
"bltzl",
|
||||
"bgezl",
|
||||
"bcond04",
|
||||
"bcond05",
|
||||
"bcond06",
|
||||
"bcond07",
|
||||
"tgei",
|
||||
"tgeiu",
|
||||
"tlti",
|
||||
"tltiu",
|
||||
"teqi",
|
||||
"bcond0d",
|
||||
"tnei",
|
||||
"bcond0f",
|
||||
"bltzal",
|
||||
"bgezal",
|
||||
"bltzall",
|
||||
"bgezall",
|
||||
"bcond14",
|
||||
"bcond15",
|
||||
"bcond16",
|
||||
"bcond17",
|
||||
"bcond18",
|
||||
"bcond19",
|
||||
"bcond1a",
|
||||
"bcond1b",
|
||||
"bcond1c",
|
||||
"bcond1d",
|
||||
"bcond1e",
|
||||
"bcond1f"
|
||||
};
|
||||
|
||||
static char *cop1_name[64] = {
|
||||
/* 0 */ "add", "sub", "mul", "div", "sqrt", "abs", "mov", "neg",
|
||||
/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f",
|
||||
/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17",
|
||||
/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f",
|
||||
/*32 */ "cvt.s","cvt.d","cvt.e","fop23","cvt.w","fop25","fop26","fop27",
|
||||
/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f",
|
||||
/*48 */ "c.f", "c.un","c.eq","c.ueq","c.olt","c.ult","c.ole","c.ule",
|
||||
/*56 */ "c.sf","c.ngle","c.seq","c.ngl","c.lt","c.nge","c.le","c.ngt"
|
||||
};
|
||||
|
||||
static char *fmt_name[16] = {
|
||||
"s", "d", "e", "q",
|
||||
"w", "fmt5", "fmt6", "fmt7",
|
||||
"fmt8", "fmt9", "fmta", "fmtb",
|
||||
"fmtc", "fmtd", "fmte", "fmtf"
|
||||
};
|
||||
|
||||
/* public */
|
||||
/* Three sets of commonly used register names */
|
||||
const char *tdis_reg_names[3][64] = {
|
||||
{ /* compiler names */
|
||||
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
|
||||
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
|
||||
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
|
||||
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
|
||||
"zero.B","at.B","v0.B", "v1.B", "a0.B", "a1.B", "a2.B", "a3.B",
|
||||
"t0.B", "t1.B", "t2.B", "t3.B", "t4.B", "t5.B", "t6.B", "t7.B",
|
||||
"s0.B", "s1.B", "s2.B", "s3.B", "s4.B", "s5.B", "s6.B", "s7.B",
|
||||
"t8.B", "t9.B", "k0.B", "k1.B", "gp.B", "sp.B", "s8.B", "ra.B"
|
||||
},
|
||||
{ /* hardware names */
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "r25", "r26", "r27", "gp", "sp", "r30", "r31",
|
||||
"r0.B", "r1.B", "r2.B", "r3.B", "r4.B", "r5.B", "r6.B", "r7.B",
|
||||
"r8.B", "r9.B", "r10.B","r11.B","r12.B","r13.B","r14.B","r15.B",
|
||||
"r16.B","r17.B","r18.B","r19.B","r20.B","r21.B","r22.B","r23.B",
|
||||
"r24.B","r25.B","r26.B","r27.B","gp.B", "sp.B", "r30.B","r31.B"
|
||||
},
|
||||
{ /* assembler names */
|
||||
"$0", "$at", "$2", "$3", "$4", "$5", "$6", "$7",
|
||||
"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
|
||||
"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
|
||||
"$24", "$25", "$26", "$27", "$gp", "$sp", "$30", "$31",
|
||||
"$0.B", "$at.B","$2.B", "$3.B", "$4.B", "$5.B", "$6.B", "$7.B",
|
||||
"$8.B", "$9.B", "$10.B","$11.B","$12.B","$13.B","$14.B","$15.B",
|
||||
"$16.B","$17.B","$18.B","$19.B","$20.B","$21.B","$22.B","$23.B",
|
||||
"$24.B","$25.B","$26.B","$27.B","$gp.B","$sp.B","$30.B","$31.B"
|
||||
}
|
||||
};
|
||||
|
||||
static char *c0_opname[64] = {
|
||||
"c0op0","tlbr","tlbwi","c0op3","c0op4","c0op5","tlbwr","c0op7",
|
||||
"tlbp","c0op9","c0op10","c0op11","c0op12","c0op13","c0op14","c0op15",
|
||||
"rfe","c0op17","c0op18","c0op19","c0op20","c0op21","c0op22","c0op23",
|
||||
"c0op24","c0op25","c0op26","c0op27","c0op28","c0op29","c0op30","c0op31",
|
||||
"c0op32","c0op33","c0op34","c0op35","c0op36","c0op37","c0op38","c0op39",
|
||||
"c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
|
||||
"c0op48","c0op49","c0op50","c0op51","c0op52","c0op53","c0op54","c0op55",
|
||||
"c0op56","c0op57","c0op58","c0op59","c0op60","c0op61","c0op62","c0op63"
|
||||
};
|
||||
|
||||
static char *c0_reg[32] = {
|
||||
"index","random","tlblo","c0r3","context","c0r5","c0r6","c0r7",
|
||||
"badvaddr","c0r9","tlbhi","epcn","sr", "cause","epc", "c0r15",
|
||||
"c0r16","c0r17","c0r18","c0r19","c0r20","c0r21","c0r22","c0r23",
|
||||
"c0r24","c0r25","c0r26","c0r27","c0r28","c0r29","c0r30","c0r31"
|
||||
};
|
||||
|
||||
/* Remember the options set by dis_init */
|
||||
//#define ADDR_DEFAULT "%#010x:\t"
|
||||
#define ADDR_DEFAULT 0
|
||||
//#define VALUE_DEFAULT "%#010x\t"
|
||||
#define VALUE_DEFAULT 0
|
||||
#define NAME_DEFAULT COMPILER_NAMES
|
||||
static struct {
|
||||
char *addr_format;
|
||||
char *value_format;
|
||||
const char **reg_names;
|
||||
int print_jal_targets;
|
||||
} save = {
|
||||
ADDR_DEFAULT,
|
||||
VALUE_DEFAULT,
|
||||
NAME_DEFAULT,
|
||||
true
|
||||
};
|
||||
|
||||
/* Update regmask to reflect the use of this general-purpose (not fp)
|
||||
register, and return its name */
|
||||
static const char *
|
||||
register_name(ireg, boosted, regmask)
|
||||
unsigned ireg, *regmask;
|
||||
int boosted;
|
||||
{
|
||||
if (!boosted)
|
||||
*regmask |= (1 << ireg);
|
||||
return save.reg_names[boosted ? ireg + 32 : ireg];
|
||||
}
|
||||
|
||||
int instr_info(unsigned iword, instr_info_t *pInfo)
|
||||
{
|
||||
unsigned address, *regmask, *symbol_value, *ls_register;
|
||||
|
||||
int return_value = 0;
|
||||
boolean do_b_displacement = false;
|
||||
boolean do_loadstore = false;
|
||||
union mips_instruction i;
|
||||
union extension_byte e;
|
||||
|
||||
i.word = iword;
|
||||
*regmask = *symbol_value = *ls_register = 0;
|
||||
|
||||
/* decode the instruction */
|
||||
switch (i.j_format.opcode)
|
||||
{
|
||||
|
||||
case spec_op:
|
||||
|
||||
if (i.word == 0x20)
|
||||
{
|
||||
pInfo->type = INSTR_TYPE_NOP;
|
||||
break;
|
||||
|
||||
}
|
||||
else if (i.r_format.func == addu_op && i.r_format.rt == ZERO)
|
||||
{
|
||||
pInfo->type = INSTR_TYPE_MOVE;
|
||||
pInfo->rd = i.r_format.rd;
|
||||
pInfo->rs = i.r_format.rs;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (i.r_format.func)
|
||||
{
|
||||
case sll_op:
|
||||
case srl_op:
|
||||
case sra_op:
|
||||
pInfo->type = INSTR_TYPE_ARITH;
|
||||
pInfo->rd = i.r_format.rd;
|
||||
pInfo->rt = i.r_format.rt;
|
||||
pInfo->re = i.r_format.re;
|
||||
break;
|
||||
case sllv_op:
|
||||
case srlv_op:
|
||||
case srav_op:
|
||||
pInfo->type = INSTR_TYPE_ARITH;
|
||||
pInfo->rd = i.r_format.rd;
|
||||
pInfo->rt = i.r_format.rt;
|
||||
pInfo->rs = i.r_format.rs;
|
||||
break;
|
||||
case mfhi_op:
|
||||
case mflo_op:
|
||||
pInfo->type = INSTR_TYPE_ARITH;
|
||||
pInfo->rd = i.r_format.rd;
|
||||
break;
|
||||
case jalr_op:
|
||||
pInfo->type = INSTR_TYPE_JUMP;
|
||||
pInfo->flags = INSTR_FLAGS_JUMP_LINK | INSTR_FLAGS_JUMP_REGISTER;
|
||||
pInfo->rd = i.r_format.rd;
|
||||
pInfo->rs = i.r_format.rs;
|
||||
break;
|
||||
case jr_op:
|
||||
pInfo->type = INSTR_TYPE_JUMP;
|
||||
pInfo->flags = INSTR_FLAGS_JUMP_REGISTER;
|
||||
pInfo->rs = i.r_format.rs;
|
||||
break;
|
||||
case mtlo_op:
|
||||
case mthi_op:
|
||||
pInfo->rs = i.r_format.rs;
|
||||
case mult_op:
|
||||
case multu_op:
|
||||
case div_op:
|
||||
case divu_op:
|
||||
pInfo->type = INSTR_TYPE_ARITH;
|
||||
pInfo->rt = i.r_format.rt;
|
||||
break;
|
||||
case syscall_op:
|
||||
pInfo->type = INSTR_TYPE_SYSCALL;
|
||||
break;
|
||||
case break_op:
|
||||
case vcall_op:
|
||||
pInfo->type = INSTR_TYPE_BREAK;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case bcond_op:
|
||||
pInfo->type = INSTR_TYPE_BRANCH;
|
||||
pInfo->rs = i.i_format.rs;
|
||||
do_b_displacement = true;
|
||||
break;
|
||||
|
||||
case blez_op_T:
|
||||
case bgtz_op_T:
|
||||
case blez_op_N:
|
||||
case bgtz_op_N:
|
||||
pInfo->type = INSTR_TYPE_BRANCH;
|
||||
pInfo->rs = i.i_format.rs;
|
||||
do_b_displacement = true;
|
||||
break;
|
||||
case beq_op_T:
|
||||
case beq_op_N:
|
||||
case bne_op_T:
|
||||
case bne_op_N:
|
||||
pInfo->type = INSTR_TYPE_BRANCH;
|
||||
pInfo->rs = i.i_format.rs;
|
||||
pInfo->rt = i.i_format.rt;
|
||||
do_b_displacement = true;
|
||||
break;
|
||||
|
||||
case cop0_op:
|
||||
case cop1_op:
|
||||
case cop2_op:
|
||||
case cop3_op:
|
||||
pInfo->type = INSTR_TYPE_COP;
|
||||
break; /* End of cop0, cop1, cop2, cop3 */
|
||||
|
||||
case jal_op:
|
||||
pInfo->type = INSTR_TYPE_JUMP;
|
||||
pInfo->flags = INSTR_FLAGS_JUMP_LINK | INSTR_FLAGS_JUMP_IMMEDIATE;
|
||||
break;
|
||||
case j_op:
|
||||
pInfo->type = INSTR_TYPE_JUMP;
|
||||
pInfo->flags = INSTR_FLAGS_JUMP_IMMEDIATE;
|
||||
break;
|
||||
|
||||
case swc1_op:
|
||||
case sdc1_op:
|
||||
pInfo->type = INSTR_TYPE_STORE;
|
||||
pInfo->flags = INSTR_FLAGS_STORE_COP;
|
||||
do_loadstore = true;
|
||||
break;
|
||||
|
||||
case lwc1_op:
|
||||
case ldc1_op:
|
||||
pInfo->type = INSTR_TYPE_LOAD;
|
||||
pInfo->flags = INSTR_FLAGS_LOAD_COP;
|
||||
do_loadstore = true;
|
||||
break;
|
||||
break;
|
||||
|
||||
case lb_op:
|
||||
case lh_op:
|
||||
case lw_op:
|
||||
case ld_op:
|
||||
case lbu_op:
|
||||
case lhu_op:
|
||||
case lwl_op:
|
||||
case lwr_op:
|
||||
pInfo->type = INSTR_TYPE_LOAD;
|
||||
pInfo->flags = INSTR_FLAGS_LOAD_MEMORY;
|
||||
pInfo->rt = i.i_format.rt;
|
||||
do_loadstore = true;
|
||||
break;
|
||||
case sb_op:
|
||||
case sh_op:
|
||||
case sw_op:
|
||||
case sd_op:
|
||||
pInfo->type = INSTR_TYPE_STORE;
|
||||
pInfo->flags = INSTR_FLAGS_STORE_MEMORY;
|
||||
pInfo->rt = i.i_format.rt;
|
||||
do_loadstore = true;
|
||||
break;
|
||||
|
||||
case ori_op:
|
||||
case xori_op:
|
||||
pInfo->type = INSTR_TYPE_ARITH;
|
||||
pInfo->flags = INSTR_FLAGS_ARITH_IMMEDIATE;
|
||||
pInfo->rt = i.i_format.rt;
|
||||
break;
|
||||
|
||||
/* fall through */
|
||||
case andi_op:
|
||||
pInfo->type = INSTR_TYPE_ARITH;
|
||||
pInfo->flags = INSTR_FLAGS_ARITH_IMMEDIATE;
|
||||
pInfo->rt = i.u_format.rt;
|
||||
pInfo->rs = i.u_format.rs;
|
||||
break;
|
||||
|
||||
case lui_op:
|
||||
pInfo->type = INSTR_TYPE_LOAD;
|
||||
pInfo->flags = INSTR_FLAGS_LOAD_IMMEDIATE;
|
||||
pInfo->rt = i.u_format.rt;
|
||||
break;
|
||||
case addi_op:
|
||||
case addiu_op:
|
||||
pInfo->type = INSTR_TYPE_ARITH;
|
||||
pInfo->flags = INSTR_FLAGS_ARITH_IMMEDIATE;
|
||||
pInfo->rt = i.i_format.rt;
|
||||
/* fall through */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return pInfo->type;
|
||||
}
|
||||
|
||||
/* public -- see dissassembler.h */
|
||||
int
|
||||
tdisasm(buffer, address, iword, ext, regmask, symbol_value, ls_register)
|
||||
char *buffer;
|
||||
unsigned char ext; /* extension byte */
|
||||
unsigned address, iword, *regmask, *symbol_value, *ls_register;
|
||||
{
|
||||
int return_value = 0;
|
||||
char *bufptr = buffer;
|
||||
boolean do_b_displacement = false;
|
||||
boolean do_loadstore = false;
|
||||
union mips_instruction i;
|
||||
union extension_byte e;
|
||||
|
||||
*bufptr = 0;
|
||||
i.word = iword;
|
||||
e.byte = ext;
|
||||
*regmask = *symbol_value = *ls_register = 0;
|
||||
|
||||
/* Put out the address and hex value of the instruction,
|
||||
leaving bufptr set at the end */
|
||||
if (save.addr_format) {
|
||||
sprintf(bufptr, save.addr_format, address);
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
if (save.value_format) {
|
||||
sprintf(bufptr, save.value_format, iword);
|
||||
bufptr += strlen(bufptr);
|
||||
}
|
||||
|
||||
/* check for dynamic NOP */
|
||||
if (e.e.dyn_nop) {
|
||||
strcat(bufptr, "D.");
|
||||
bufptr += 2;
|
||||
}
|
||||
|
||||
/* decode the instruction */
|
||||
switch (i.j_format.opcode) {
|
||||
|
||||
case spec_op:
|
||||
|
||||
if (i.word == 0x20) {
|
||||
strcat(bufptr, "nop");
|
||||
if (e.e.rd_boost)
|
||||
strcat(bufptr, ".B");
|
||||
bufptr += strlen(bufptr);
|
||||
break;
|
||||
} else if (i.r_format.func == addu_op && i.r_format.rt == ZERO) {
|
||||
sprintf(bufptr, "move%s\t%s,%s",
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.r_format.rd, e.e.rd_boost, regmask),
|
||||
register_name(i.r_format.rs, e.e.rs_boost, regmask));
|
||||
bufptr += strlen(bufptr);
|
||||
break;
|
||||
}
|
||||
strcat(bufptr, spec_name[i.r_format.func]);
|
||||
if (e.e.rd_boost)
|
||||
strcat(bufptr, ".B");
|
||||
bufptr += strlen(bufptr);
|
||||
|
||||
switch (i.r_format.func) {
|
||||
case sll_op:
|
||||
case srl_op:
|
||||
case sra_op:
|
||||
sprintf(bufptr, "\t%s,%s,%d",
|
||||
register_name(i.r_format.rd, e.e.rd_boost, regmask),
|
||||
register_name(i.r_format.rt, e.e.rt_boost, regmask),
|
||||
i.r_format.re);
|
||||
break;
|
||||
case sllv_op:
|
||||
case srlv_op:
|
||||
case srav_op:
|
||||
sprintf(bufptr, "\t%s,%s,%s",
|
||||
register_name(i.r_format.rd, e.e.rd_boost, regmask),
|
||||
register_name(i.r_format.rt, e.e.rt_boost, regmask),
|
||||
register_name(i.r_format.rs, e.e.rs_boost, regmask));
|
||||
break;
|
||||
case mfhi_op:
|
||||
case mflo_op:
|
||||
sprintf(bufptr, "\t%s",
|
||||
register_name(i.r_format.rd, e.e.rd_boost, regmask));
|
||||
break;
|
||||
case jalr_op:
|
||||
return_value = 3;
|
||||
sprintf(bufptr, "\t%s,%s",
|
||||
register_name(i.r_format.rd, e.e.rd_boost, regmask),
|
||||
register_name(i.r_format.rs, e.e.rs_boost, regmask));
|
||||
*ls_register = i.r_format.rs;
|
||||
break;
|
||||
case jr_op:
|
||||
return_value = 3;
|
||||
*ls_register = i.r_format.rs;
|
||||
/* fall through */
|
||||
case mtlo_op:
|
||||
case mthi_op:
|
||||
sprintf(bufptr, "\t%s",
|
||||
register_name(i.r_format.rs, e.e.rs_boost, regmask));
|
||||
break;
|
||||
case mult_op:
|
||||
case multu_op:
|
||||
case div_op:
|
||||
case divu_op:
|
||||
sprintf(bufptr, "\t%s,%s",
|
||||
register_name(i.r_format.rs, e.e.rs_boost, regmask),
|
||||
register_name(i.r_format.rt, e.e.rt_boost, regmask));
|
||||
break;
|
||||
case syscall_op:
|
||||
break;
|
||||
case break_op:
|
||||
case vcall_op:
|
||||
{
|
||||
char *format = "\t%d";
|
||||
unsigned op2 = i.r_format.rd * 32 + i.r_format.re;
|
||||
|
||||
if (op2)
|
||||
format = "\t%d,%d";
|
||||
sprintf(bufptr, format, i.r_format.rs*32+i.r_format.rt,
|
||||
op2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sprintf(bufptr, "\t%s,%s,%s",
|
||||
register_name(i.r_format.rd, e.e.rd_boost, regmask),
|
||||
register_name(i.r_format.rs, e.e.rs_boost, regmask),
|
||||
register_name(i.r_format.rt, e.e.rt_boost, regmask));
|
||||
break;
|
||||
};
|
||||
break;
|
||||
|
||||
case bcond_op:
|
||||
sprintf(bufptr, "%s%s\t%s,",
|
||||
bcond_name[i.i_format.rt],
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.i_format.rs, e.e.rs_boost, regmask));
|
||||
do_b_displacement = true;
|
||||
break;
|
||||
|
||||
case blez_op_T:
|
||||
case bgtz_op_T:
|
||||
case blez_op_N:
|
||||
case bgtz_op_N:
|
||||
sprintf(bufptr, "%s%s\t%s,", op_name[i.i_format.opcode],
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.i_format.rs, e.e.rs_boost, regmask));
|
||||
do_b_displacement = true;
|
||||
break;
|
||||
case beq_op_T:
|
||||
case beq_op_N:
|
||||
if (i.i_format.rs == ZERO && i.i_format.rt == ZERO) {
|
||||
strcat(bufptr, "b");
|
||||
if (i.j_format.opcode == beq_op_T)
|
||||
strcat(bufptr, ".T");
|
||||
else
|
||||
strcat(bufptr, ".N");
|
||||
if (e.e.rd_boost)
|
||||
strcat(bufptr, ".B\t");
|
||||
else
|
||||
strcat(bufptr, "\t");
|
||||
do_b_displacement = true;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case bne_op_T:
|
||||
case bne_op_N:
|
||||
sprintf(bufptr, "%s%s\t%s,%s,", op_name[i.i_format.opcode],
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.i_format.rs, e.e.rs_boost, regmask),
|
||||
register_name(i.i_format.rt, e.e.rt_boost, regmask));
|
||||
do_b_displacement = true;
|
||||
break;
|
||||
|
||||
case cop0_op:
|
||||
case cop1_op:
|
||||
case cop2_op:
|
||||
case cop3_op:
|
||||
{
|
||||
unsigned which_cop = i.j_format.opcode - cop0_op;
|
||||
char *f_or_r = "rf";
|
||||
|
||||
switch (i.r_format.rs) {
|
||||
case bc_op_T:
|
||||
sprintf(bufptr, "bc%d%c.T%s\t", which_cop,
|
||||
"ft"[i.r_format.rt],
|
||||
e.e.rd_boost ? ".B" : "");
|
||||
do_b_displacement = true;
|
||||
break;
|
||||
case bc_op_N:
|
||||
sprintf(bufptr, "bc%d%c.N%s\t", which_cop,
|
||||
"ft"[i.r_format.rt],
|
||||
e.e.rd_boost ? ".B" : "");
|
||||
do_b_displacement = true;
|
||||
break;
|
||||
case mtc_op:
|
||||
if (which_cop == 0)
|
||||
sprintf(bufptr, "mtc%d%s\t%s,%s", which_cop,
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.r_format.rt, e.e.rt_boost,regmask),
|
||||
c0_reg[i.f_format.rd]);
|
||||
else
|
||||
sprintf(bufptr, "mtc%d%s\t%s,%c%d", which_cop,
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.r_format.rt, e.e.rt_boost,regmask),
|
||||
f_or_r[(which_cop == 1)],
|
||||
i.f_format.rd);
|
||||
break;
|
||||
case mfc_op:
|
||||
if (which_cop == 0)
|
||||
sprintf(bufptr, "mfc%d%s\t%s,%s", which_cop,
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.r_format.rt, e.e.rt_boost,regmask),
|
||||
c0_reg[i.f_format.rd]);
|
||||
else
|
||||
sprintf(bufptr, "mfc%d%s\t%s,%c%d", which_cop,
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.r_format.rt, e.e.rt_boost,regmask),
|
||||
f_or_r[(which_cop == 1)],
|
||||
i.f_format.rd);
|
||||
break;
|
||||
case cfc_op:
|
||||
sprintf(bufptr, "cfc%d%s\t%s,%c%d", which_cop,
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.r_format.rt, e.e.rt_boost, regmask),
|
||||
f_or_r[(which_cop == 1)],
|
||||
i.f_format.rd);
|
||||
break;
|
||||
case ctc_op:
|
||||
sprintf(bufptr, "ctc%d%s\t%s,%c%d", which_cop,
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.r_format.rt, e.e.rt_boost, regmask),
|
||||
f_or_r[(which_cop == 1)],
|
||||
i.f_format.rd);
|
||||
break;
|
||||
default:
|
||||
if (which_cop != 1)
|
||||
sprintf(bufptr, "c0%s\t%s", e.e.rd_boost ? ".B" : "",
|
||||
c0_opname[i.f_format.func]);
|
||||
else
|
||||
{
|
||||
sprintf(bufptr, "%s.%s%s\t",
|
||||
cop1_name[i.f_format.func],
|
||||
fmt_name[i.f_format.fmt],
|
||||
e.e.rd_boost ? ".B" : "");
|
||||
bufptr += strlen(bufptr);
|
||||
switch (i.f_format.func) {
|
||||
case fsqrt_op:
|
||||
case fabs_op:
|
||||
case fmov_op:
|
||||
case fcvts_op:
|
||||
case fcvtd_op:
|
||||
case fcvte_op:
|
||||
case fcvtw_op:
|
||||
sprintf(bufptr, "f%d,f%d",
|
||||
i.f_format.re,
|
||||
i.f_format.rd);
|
||||
break;
|
||||
case fcmp_op+0x0:
|
||||
case fcmp_op+0x1:
|
||||
case fcmp_op+0x2:
|
||||
case fcmp_op+0x3:
|
||||
case fcmp_op+0x4:
|
||||
case fcmp_op+0x5:
|
||||
case fcmp_op+0x6:
|
||||
case fcmp_op+0x7:
|
||||
case fcmp_op+0x8:
|
||||
case fcmp_op+0x9:
|
||||
case fcmp_op+0xa:
|
||||
case fcmp_op+0xb:
|
||||
case fcmp_op+0xc:
|
||||
case fcmp_op+0xd:
|
||||
case fcmp_op+0xe:
|
||||
case fcmp_op+0xf:
|
||||
sprintf(bufptr, "f%d,f%d",
|
||||
i.f_format.rd,
|
||||
i.f_format.rt);
|
||||
break;
|
||||
default:
|
||||
sprintf(bufptr, "f%d,f%d,f%d",
|
||||
i.f_format.re,
|
||||
i.f_format.rd,
|
||||
i.f_format.rt);
|
||||
break;
|
||||
} /* switch on func */
|
||||
}
|
||||
break; /* End of default */
|
||||
} /* switch on rs */
|
||||
}
|
||||
break; /* End of cop0, cop1, cop2, cop3 */
|
||||
|
||||
case jal_op:
|
||||
case j_op:
|
||||
sprintf(bufptr, "%s%s\t", op_name[i.j_format.opcode],
|
||||
e.e.rd_boost ? ".B" : "");
|
||||
*symbol_value = (address & 0xF0000000) | i.j_format.target << 2;
|
||||
if (save.print_jal_targets)
|
||||
{
|
||||
bufptr += strlen(bufptr);
|
||||
sprintf(bufptr, "%#x", *symbol_value);
|
||||
}
|
||||
return_value = 1;
|
||||
break;
|
||||
|
||||
case swc1_op:
|
||||
case sdc1_op:
|
||||
case lwc1_op:
|
||||
case ldc1_op:
|
||||
sprintf(bufptr, "%s%s\tf%d,", op_name[i.i_format.opcode],
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
i.i_format.rt);
|
||||
do_loadstore = true;
|
||||
break;
|
||||
|
||||
case lb_op:
|
||||
case lh_op:
|
||||
case lw_op:
|
||||
case ld_op:
|
||||
case lbu_op:
|
||||
case lhu_op:
|
||||
case sb_op:
|
||||
case sh_op:
|
||||
case sw_op:
|
||||
case sd_op:
|
||||
case lwl_op:
|
||||
case lwr_op:
|
||||
sprintf(bufptr, "%s%s\t%s,", op_name[i.i_format.opcode],
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.i_format.rt, e.e.rt_boost, regmask));
|
||||
do_loadstore = true;
|
||||
break;
|
||||
|
||||
case ori_op:
|
||||
case xori_op:
|
||||
if (i.u_format.rs == ZERO) {
|
||||
sprintf(bufptr, "li%s\t%s,%d",
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.u_format.rt, e.e.rt_boost, regmask),
|
||||
i.u_format.uimmediate);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case andi_op:
|
||||
sprintf(bufptr, "%s%s\t%s,%s,%#x", op_name[i.u_format.opcode],
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.u_format.rt, e.e.rt_boost, regmask),
|
||||
register_name(i.u_format.rs, e.e.rs_boost, regmask),
|
||||
i.u_format.uimmediate);
|
||||
break;
|
||||
case lui_op:
|
||||
sprintf(bufptr, "%s%s\t%s,%#x", op_name[i.u_format.opcode],
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.u_format.rt, e.e.rt_boost, regmask),
|
||||
i.u_format.uimmediate);
|
||||
break;
|
||||
case addi_op:
|
||||
case addiu_op:
|
||||
if (i.i_format.rs == ZERO) {
|
||||
short sign_extender = i.i_format.simmediate;
|
||||
sprintf(bufptr, "li%s\t%s,%d",
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.i_format.rt, e.e.rt_boost, regmask),
|
||||
sign_extender);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
{
|
||||
short sign_extender = i.i_format.simmediate;
|
||||
sprintf(bufptr, "%s%s\t%s,%s,%d", op_name[i.i_format.opcode],
|
||||
e.e.rd_boost ? ".B" : "",
|
||||
register_name(i.i_format.rt, e.e.rt_boost, regmask),
|
||||
register_name(i.i_format.rs, e.e.rs_boost, regmask),
|
||||
sign_extender);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Some instructions require more than just registers */
|
||||
|
||||
if (do_loadstore)
|
||||
{
|
||||
short sign_extender = i.i_format.simmediate;
|
||||
*symbol_value = sign_extender;
|
||||
*ls_register = i.i_format.rs;
|
||||
bufptr += strlen(bufptr);
|
||||
sprintf(bufptr, "%d(%s)", sign_extender,
|
||||
register_name(i.i_format.rs, e.e.rs_boost, regmask));
|
||||
return_value = -1;
|
||||
}
|
||||
else if (do_b_displacement)
|
||||
{
|
||||
short sign_extender = i.i_format.simmediate;
|
||||
bufptr += strlen(bufptr);
|
||||
*symbol_value = 4 + address + ((((long)sign_extender & 0xFFFD0000) | (0x3FFFF & (sign_extender << 2))));
|
||||
sprintf(bufptr, "%#x", *symbol_value);
|
||||
return_value = 2;
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,489 @@
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* | Copyright Unpublished, MIPS Computer Systems, Inc. All Rights | */
|
||||
/* | Reserved. This software contains proprietary and confidential | */
|
||||
/* | information of MIPS and its suppliers. Use, disclosure or | */
|
||||
/* | reproduction is prohibited without the prior express written | */
|
||||
/* | consent of MIPS. | */
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* inst.h 4.2 */
|
||||
/*
|
||||
* inst.h -- instruction format defines
|
||||
*/
|
||||
|
||||
/**
|
||||
** UPDATE - 19 Sept 89 by Michael Smith
|
||||
**
|
||||
** Removed signed type to remove obnoxious C++ warning message.
|
||||
**/
|
||||
|
||||
#ifdef LANGUAGE_C
|
||||
#ifdef MIPSEB
|
||||
union mips_instruction {
|
||||
unsigned word;
|
||||
unsigned char byte[4];
|
||||
struct {
|
||||
unsigned opcode : 6;
|
||||
unsigned target : 26;
|
||||
} j_format;
|
||||
struct {
|
||||
unsigned opcode : 6;
|
||||
unsigned rs : 5;
|
||||
unsigned rt : 5;
|
||||
unsigned simmediate : 16;
|
||||
} i_format;
|
||||
struct {
|
||||
unsigned opcode : 6;
|
||||
unsigned rs : 5;
|
||||
unsigned rt : 5;
|
||||
unsigned uimmediate : 16;
|
||||
} u_format;
|
||||
struct {
|
||||
unsigned opcode : 6;
|
||||
unsigned rs : 5;
|
||||
unsigned rt : 5;
|
||||
unsigned rd : 5;
|
||||
unsigned re : 5;
|
||||
unsigned func : 6;
|
||||
} r_format;
|
||||
struct {
|
||||
unsigned opcode : 6;
|
||||
unsigned : 1;
|
||||
unsigned fmt : 4;
|
||||
unsigned rt : 5;
|
||||
unsigned rd : 5;
|
||||
unsigned re : 5;
|
||||
unsigned func : 6;
|
||||
} f_format;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef MIPSEL
|
||||
union mips_instruction {
|
||||
unsigned word;
|
||||
unsigned char byte[4];
|
||||
struct {
|
||||
unsigned target : 26;
|
||||
unsigned opcode : 6;
|
||||
} j_format;
|
||||
struct {
|
||||
unsigned simmediate : 16;
|
||||
unsigned rt : 5;
|
||||
unsigned rs : 5;
|
||||
unsigned opcode : 6;
|
||||
} i_format;
|
||||
struct {
|
||||
unsigned uimmediate : 16;
|
||||
unsigned rt : 5;
|
||||
unsigned rs : 5;
|
||||
unsigned opcode : 6;
|
||||
} u_format;
|
||||
struct {
|
||||
unsigned func : 6;
|
||||
unsigned re : 5;
|
||||
unsigned rd : 5;
|
||||
unsigned rt : 5;
|
||||
unsigned rs : 5;
|
||||
unsigned opcode : 6;
|
||||
} r_format;
|
||||
struct {
|
||||
unsigned func : 6;
|
||||
unsigned re : 5;
|
||||
unsigned rd : 5;
|
||||
unsigned rt : 5;
|
||||
unsigned fmt : 4;
|
||||
unsigned : 1;
|
||||
unsigned opcode : 6;
|
||||
} f_format;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define INSTR_FLAGS_ARITH_IMMEDIATE 0x0000001
|
||||
#define INSTR_FLAGS_ARITH_REGISTER 0x0000002
|
||||
#define INSTR_FLAGS_JUMP_LINK 0x8000000
|
||||
#define INSTR_FLAGS_JUMP_IMMEDIATE 0x0000001
|
||||
#define INSTR_FLAGS_JUMP_REGISTER 0x0000002
|
||||
#define INSTR_FLAGS_BRANCH_LINK 0x8000000
|
||||
#define INSTR_FLAGS_BRANCH_IMMEDIATE 0x0000001
|
||||
#define INSTR_FLAGS_BRANCH_REGISTER 0x0000002
|
||||
#define INSTR_FLAGS_LOAD_IMMEDIATE 0x0000001
|
||||
#define INSTR_FLAGS_LOAD_MEMORY 0x0000002
|
||||
#define INSTR_FLAGS_LOAD_COP 0x0000004
|
||||
#define INSTR_FLAGS_STORE_MEMORY 0x0000002
|
||||
#define INSTR_FLAGS_STORE_COP 0x0000004
|
||||
|
||||
enum
|
||||
{
|
||||
INSTR_TYPE_NOP = 0,
|
||||
INSTR_TYPE_MOVE,
|
||||
INSTR_TYPE_ARITH,
|
||||
INSTR_TYPE_JUMP,
|
||||
INSTR_TYPE_BRANCH,
|
||||
INSTR_TYPE_LOAD,
|
||||
INSTR_TYPE_STORE,
|
||||
INSTR_TYPE_COP,
|
||||
INSTR_TYPE_MUL,
|
||||
INSTR_TYPE_DIV,
|
||||
INSTR_TYPE_BREAK,
|
||||
INSTR_TYPE_SYSCALL
|
||||
};
|
||||
|
||||
typedef struct _sinstr_info_t
|
||||
{
|
||||
unsigned type;
|
||||
unsigned flags;
|
||||
unsigned rd, rt, rs, re;
|
||||
|
||||
} instr_info_t;
|
||||
|
||||
|
||||
#define spec_op 0x00
|
||||
#define bcond_op 0x01
|
||||
#define j_op 0x02
|
||||
#define jal_op 0x03
|
||||
|
||||
#define beq_op 0x04
|
||||
#define bne_op 0x05
|
||||
#define blez_op 0x06
|
||||
#define bgtz_op 0x07
|
||||
|
||||
#define addi_op 0x08
|
||||
#define addiu_op 0x09
|
||||
#define slti_op 0x0A
|
||||
#define sltiu_op 0x0B
|
||||
|
||||
#define andi_op 0x0C
|
||||
#define ori_op 0x0D
|
||||
#define xori_op 0x0E
|
||||
#define lui_op 0x0F
|
||||
|
||||
#define lb_op 0x20
|
||||
#define lh_op 0x21
|
||||
#define lw_op 0x23
|
||||
#define lbu_op 0x24
|
||||
#define lhu_op 0x25
|
||||
#define ld_op 0x27
|
||||
#define sb_op 0x28
|
||||
#define sh_op 0x29
|
||||
#define sw_op 0x2B
|
||||
#define sd_op 0x2F
|
||||
#define lwl_op 0x22
|
||||
#define lwr_op 0x26
|
||||
#define swl_op 0x2a
|
||||
#define swr_op 0x2e
|
||||
|
||||
/* Co-processor sub-opcodes */
|
||||
#define bc_op 0x08
|
||||
#define mfc_op 0x00
|
||||
#define cfc_op 0x02
|
||||
#define mtc_op 0x04
|
||||
#define ctc_op 0x06
|
||||
|
||||
/* Co-processor 0 opcodes */
|
||||
#define cop0_op 0x10
|
||||
#define lwc0_op 0x30
|
||||
#define ldc0_op 0x34
|
||||
#define swc0_op 0x38
|
||||
#define sdc0_op 0x3c
|
||||
|
||||
/* Co-processor 0 sub-opcodes */
|
||||
#define tlbr_op 0x1
|
||||
#define tlbwi_op 0x2
|
||||
#define tlbwr_op 0x6
|
||||
#define tlbp_op 0x8
|
||||
#define rfe_op 0x10
|
||||
|
||||
/* Co-processor 1 opcodes */
|
||||
#define cop1_op 0x11
|
||||
#define lwc1_op 0x31
|
||||
#define ldc1_op 0x35
|
||||
#define swc1_op 0x39
|
||||
#define sdc1_op 0x3D
|
||||
|
||||
/* Co-processor 1 sub-opcodes */
|
||||
#define fadd_op 0x00
|
||||
#define fsub_op 0x01
|
||||
#define fmpy_op 0x02
|
||||
#define fdiv_op 0x03
|
||||
#define fsqrt_op 0x04
|
||||
#define fabs_op 0x05
|
||||
#define fmov_op 0x06
|
||||
#define fneg_op 0x07
|
||||
#define fcvts_op 0x20
|
||||
#define fcvtd_op 0x21
|
||||
#define fcvte_op 0x22
|
||||
#define fcvtw_op 0x24
|
||||
#define fcmp_op 0x30
|
||||
#define s_fmt 0
|
||||
#define d_fmt 1
|
||||
#define e_fmt 2
|
||||
#define w_fmt 4
|
||||
|
||||
/* Other coprocessor opcodes */
|
||||
#define cop2_op 0x12
|
||||
#define lwc2_op 0x32
|
||||
#define ldc2_op 0x36
|
||||
#define swc2_op 0x3a
|
||||
#define sdc2_op 0x3e
|
||||
|
||||
#define cop3_op 0x13
|
||||
#define lwc3_op 0x33
|
||||
#define ldc3_op 0x37
|
||||
#define swc3_op 0x3b
|
||||
#define sdc3_op 0x3f
|
||||
|
||||
|
||||
/* bcond subopcodes */
|
||||
#define bltz_op 0x00
|
||||
#define bgez_op 0x01
|
||||
#define bltzal_op 0x10
|
||||
#define bgezal_op 0x11
|
||||
|
||||
/* special subopcodes */
|
||||
#define sll_op 0x00
|
||||
#define srl_op 0x02
|
||||
#define sra_op 0x03
|
||||
#define sllv_op 0x04
|
||||
#define srlv_op 0x06
|
||||
#define srav_op 0x07
|
||||
#define jr_op 0x08
|
||||
#define jalr_op 0x09
|
||||
#define syscall_op 0x0C
|
||||
#define break_op 0x0D
|
||||
#define vcall_op 0x0E
|
||||
|
||||
#define mfhi_op 0x10
|
||||
#define mthi_op 0x11
|
||||
#define mflo_op 0x12
|
||||
#define mtlo_op 0x13
|
||||
#define mult_op 0x18
|
||||
#define multu_op 0x19
|
||||
#define div_op 0x1A
|
||||
#define divu_op 0x1B
|
||||
|
||||
#define add_op 0x20
|
||||
#define addu_op 0x21
|
||||
#define and_op 0x24
|
||||
#define or_op 0x25
|
||||
#define xor_op 0x26
|
||||
#define nor_op 0x27
|
||||
#define sub_op 0x22
|
||||
#define subu_op 0x23
|
||||
#define slt_op 0x2A
|
||||
#define sltu_op 0x2B
|
||||
|
||||
#endif /* LANGUAGE_C */
|
||||
|
||||
#ifdef LANGUAGE_PASCAL
|
||||
|
||||
#ifdef MIPSEB
|
||||
type
|
||||
mips_instruction =
|
||||
packed record
|
||||
case cardinal of
|
||||
0: (
|
||||
word: cardinal;
|
||||
);
|
||||
1: (
|
||||
byte: packed array[0..3] of 0..255;
|
||||
);
|
||||
2: (
|
||||
opcode: 0..63;
|
||||
target: 0..67108863;
|
||||
);
|
||||
3: (
|
||||
opcode3: 0..63;
|
||||
rs: 0..31;
|
||||
rt: 0..31;
|
||||
simmediate: -32768..32767;
|
||||
);
|
||||
4: (
|
||||
opcode4: 0..63;
|
||||
rs4: 0..63;
|
||||
rt4: 0..63;
|
||||
uimmediate: 0..65535;
|
||||
);
|
||||
5: (
|
||||
opcode5: 0..63;
|
||||
rs5: 0..63;
|
||||
rt5: 0..63;
|
||||
rd5: 0..63;
|
||||
re5: 0..63;
|
||||
func: 0..63;
|
||||
);
|
||||
end {record};
|
||||
#endif
|
||||
|
||||
#ifdef MIPSEL
|
||||
type
|
||||
mips_instruction =
|
||||
packed record
|
||||
case cardinal of
|
||||
0: (
|
||||
word: cardinal;
|
||||
);
|
||||
1: (
|
||||
byte: packed array[0..3] of 0..255;
|
||||
);
|
||||
2: (
|
||||
target: 0..67108863;
|
||||
opcode: 0..63;
|
||||
);
|
||||
3: (
|
||||
simmediate: -32768..32767;
|
||||
rt: 0..31;
|
||||
rs: 0..31;
|
||||
opcode3: 0..63;
|
||||
);
|
||||
4: (
|
||||
uimmediate: 0..65535;
|
||||
rt4: 0..63;
|
||||
rs4: 0..63;
|
||||
opcode4: 0..63;
|
||||
);
|
||||
5: (
|
||||
func: 0..63;
|
||||
re5: 0..63;
|
||||
rd5: 0..63;
|
||||
rt5: 0..63;
|
||||
rs5: 0..63;
|
||||
opcode5: 0..63;
|
||||
);
|
||||
end {record};
|
||||
#endif
|
||||
|
||||
#define spec_op 16#00
|
||||
#define bcond_op 16#01
|
||||
#define j_op 16#02
|
||||
#define jal_op 16#03
|
||||
|
||||
#define beq_op 16#04
|
||||
#define bne_op 16#05
|
||||
#define blez_op 16#06
|
||||
#define bgtz_op 16#07
|
||||
|
||||
#define addi_op 16#08
|
||||
#define addiu_op 16#09
|
||||
#define slti_op 16#0A
|
||||
#define sltiu_op 16#0B
|
||||
|
||||
#define andi_op 16#0C
|
||||
#define ori_op 16#0D
|
||||
#define xori_op 16#0E
|
||||
#define lui_op 16#0F
|
||||
|
||||
#define lb_op 16#20
|
||||
#define lh_op 16#21
|
||||
#define lw_op 16#23
|
||||
#define lbu_op 16#24
|
||||
#define lhu_op 16#25
|
||||
#define ld_op 16#27
|
||||
#define sb_op 16#28
|
||||
#define sh_op 16#29
|
||||
#define sw_op 16#2B
|
||||
#define sd_op 16#2F
|
||||
#define lwl_op 16#22
|
||||
#define lwr_op 16#26
|
||||
#define swl_op 16#2a
|
||||
#define swr_op 16#2e
|
||||
|
||||
/* Co-processor sub-opcodes */
|
||||
#define bc_op 16#08
|
||||
#define mfc_op 16#00
|
||||
#define cfc_op 16#02
|
||||
#define mtc_op 16#04
|
||||
#define ctc_op 16#06
|
||||
|
||||
/* Co-processor 0 opcodes */
|
||||
#define cop0_op 16#10
|
||||
#define lwc0_op 16#30
|
||||
#define ldc0_op 16#34
|
||||
#define swc0_op 16#38
|
||||
#define sdc0_op 16#3c
|
||||
|
||||
/* Co-processor 0 sub-opcodes */
|
||||
#define tlbr_op 16#1
|
||||
#define tlbwi_op 16#2
|
||||
#define tlbwr_op 16#6
|
||||
#define tlbp_op 16#8
|
||||
#define rfe_op 16#10
|
||||
|
||||
/* Co-processor 1 opcodes */
|
||||
#define cop1_op 16#11
|
||||
#define lwc1_op 16#31
|
||||
#define ldc1_op 16#35
|
||||
#define swc1_op 16#39
|
||||
#define sdc1_op 16#3D
|
||||
|
||||
/* Co-processor 1 sub-opcodes */
|
||||
#define fadd_op 16#00
|
||||
#define fsub_op 16#01
|
||||
#define fmpy_op 16#02
|
||||
#define fdiv_op 16#03
|
||||
#define fsqrt_op 16#04
|
||||
#define fabs_op 16#05
|
||||
#define fmov_op 16#06
|
||||
#define fneg_op 16#07
|
||||
#define fcvts_op 16#20
|
||||
#define fcvtd_op 16#21
|
||||
#define fcvte_op 16#22
|
||||
#define fcvtw_op 16#24
|
||||
#define fcmp_op 16#30
|
||||
#define s_fmt 0
|
||||
#define d_fmt 1
|
||||
#define e_fmt 2
|
||||
#define w_fmt 4
|
||||
|
||||
/* Other coprocessor opcodes */
|
||||
#define cop2_op 16#12
|
||||
#define lwc2_op 16#32
|
||||
#define ldc2_op 16#36
|
||||
#define swc2_op 16#3a
|
||||
#define sdc2_op 16#3e
|
||||
|
||||
#define cop3_op 16#13
|
||||
#define lwc3_op 16#33
|
||||
#define ldc3_op 16#37
|
||||
#define swc3_op 16#3b
|
||||
#define sdc3_op 16#3f
|
||||
|
||||
|
||||
/* bcond subopcodes */
|
||||
#define bltz_op 16#00
|
||||
#define bgez_op 16#01
|
||||
#define bltzal_op 16#10
|
||||
#define bgezal_op 16#11
|
||||
|
||||
/* special subopcodes */
|
||||
#define sll_op 16#00
|
||||
#define srl_op 16#02
|
||||
#define sra_op 16#03
|
||||
#define sllv_op 16#04
|
||||
#define srlv_op 16#06
|
||||
#define srav_op 16#07
|
||||
#define jr_op 16#08
|
||||
#define jalr_op 16#09
|
||||
#define syscall_op 16#0C
|
||||
#define break_op 16#0D
|
||||
#define vcall_op 16#0E
|
||||
|
||||
#define mfhi_op 16#10
|
||||
#define mthi_op 16#11
|
||||
#define mflo_op 16#12
|
||||
#define mtlo_op 16#13
|
||||
#define mult_op 16#18
|
||||
#define multu_op 16#19
|
||||
#define div_op 16#1A
|
||||
#define divu_op 16#1B
|
||||
|
||||
#define add_op 16#20
|
||||
#define addu_op 16#21
|
||||
#define and_op 16#24
|
||||
#define or_op 16#25
|
||||
#define xor_op 16#26
|
||||
#define nor_op 16#27
|
||||
#define sub_op 16#22
|
||||
#define subu_op 16#23
|
||||
#define slt_op 16#2A
|
||||
#define sltu_op 16#2B
|
||||
|
||||
#endif /* LANGUAGE_PASCAL */
|
||||
@@ -0,0 +1,831 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "libsys.h"
|
||||
#include "mips_gfx.h"
|
||||
|
||||
#define USE_HW_BLITTER
|
||||
|
||||
|
||||
static vga_hw_t *g_pRegs;
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Functions
|
||||
// -------------------------------------------------------------
|
||||
void __gfx_block_set_8(uint32_t* pDst, uint32_t value)
|
||||
{
|
||||
__asm__ volatile
|
||||
(
|
||||
"sw %[value], 0(%[pDst])\n"
|
||||
"sw %[value], 4(%[pDst])\n"
|
||||
"sw %[value], 8(%[pDst])\n"
|
||||
"sw %[value], 12(%[pDst])\n"
|
||||
"sw %[value], 16(%[pDst])\n"
|
||||
"sw %[value], 20(%[pDst])\n"
|
||||
"sw %[value], 24(%[pDst])\n"
|
||||
"sw %[value], 28(%[pDst])\n"
|
||||
:
|
||||
: [pDst] "r" (pDst), [value] "r" (value)
|
||||
);
|
||||
}
|
||||
|
||||
void __gfx_block_copy_8(uint32_t* pDst, uint32_t* pSrc)
|
||||
{
|
||||
__asm__ volatile
|
||||
(
|
||||
".set noreorder\n"
|
||||
".set nomacro\n"
|
||||
"lw $s0, 0(%[pSrc])\n"
|
||||
"lw $s1, 4(%[pSrc])\n"
|
||||
"sw $s0, 0(%[pDst])\n"
|
||||
"lw $s0, 8(%[pSrc])\n"
|
||||
"sw $s1, 4(%[pDst])\n"
|
||||
"lw $s1, 12(%[pSrc])\n"
|
||||
"sw $s0, 8(%[pDst])\n"
|
||||
"lw $s0, 16(%[pSrc])\n"
|
||||
"sw $s1, 12(%[pDst])\n"
|
||||
"lw $s1, 20(%[pSrc])\n"
|
||||
"sw $s0, 16(%[pDst])\n"
|
||||
"lw $s0, 24(%[pSrc])\n"
|
||||
"sw $s1, 20(%[pDst])\n"
|
||||
"lw $s1, 28(%[pSrc])\n"
|
||||
"sw $s0, 24(%[pDst])\n"
|
||||
"sw $s1, 28(%[pDst])\n"
|
||||
".set macro\n"
|
||||
".set reorder\n"
|
||||
:
|
||||
: [pDst] "r" (pDst), [pSrc] "r" (pSrc)
|
||||
: "s0", "s1"
|
||||
);
|
||||
}
|
||||
|
||||
void _GFX_copy32(uint32_t* pDst, uint32_t* pSrc, uint32_t ndwords)
|
||||
{
|
||||
while (ndwords > 3)
|
||||
{
|
||||
__gfx_block_copy_8(pDst, pSrc);
|
||||
pDst += 8;
|
||||
pSrc += 8;
|
||||
ndwords -= 8;
|
||||
}
|
||||
while (ndwords)
|
||||
{
|
||||
*(pDst++) = *(pSrc++);
|
||||
ndwords -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void _GFX_memset32(uint32_t* pDst, uint32_t value, uint32_t ndwords)
|
||||
{
|
||||
while (ndwords > 3)
|
||||
{
|
||||
__gfx_block_set_8(pDst, value);
|
||||
pDst += 8;
|
||||
ndwords -= 8;
|
||||
}
|
||||
while (ndwords)
|
||||
{
|
||||
*(pDst++) = value;
|
||||
ndwords -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void _GFX_copy32_hw(uint32_t* pDst, uint32_t* pSrc, uint32_t ndwords, uint32_t wait_finish)
|
||||
{
|
||||
g_pRegs->pVGA_src0 = (uint32_t)pSrc;
|
||||
g_pRegs->pVGA_dst = (uint32_t)pDst;
|
||||
g_pRegs->pVGA_src0_dimx = 0;
|
||||
g_pRegs->pVGA_dst_dimx = 0;
|
||||
g_pRegs->pVGA_nx = ndwords;
|
||||
g_pRegs->pVGA_ny = 1;
|
||||
g_pRegs->pVGA_ctrl &= ~SYS_VGA_BIT_BLIT_OP_CONSTCOL;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY);
|
||||
|
||||
g_pRegs->pVGA_ctrl |= SYS_VGA_BIT_BLIT_REQ;
|
||||
|
||||
if (!wait_finish)
|
||||
return;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_ACTIVE);
|
||||
|
||||
}
|
||||
|
||||
void _GFX_memset32_hw(uint32_t* pDst, uint32_t value, uint32_t ndwords, uint32_t wait_finish)
|
||||
{
|
||||
g_pRegs->pVGA_dst = (uint32_t)pDst;
|
||||
g_pRegs->pVGA_src0_dimx = 0;
|
||||
g_pRegs->pVGA_dst_dimx = 0;
|
||||
g_pRegs->pVGA_nx = ndwords;
|
||||
g_pRegs->pVGA_ny = 1;
|
||||
g_pRegs->pVGA_color = value;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY);
|
||||
|
||||
g_pRegs->pVGA_ctrl |= (SYS_VGA_BIT_BLIT_REQ | SYS_VGA_BIT_BLIT_OP_CONSTCOL);
|
||||
|
||||
if (!wait_finish)
|
||||
return;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_ACTIVE);
|
||||
|
||||
}
|
||||
|
||||
void _GFX_BLIT_const(uint32_t* pDst, uint32_t xdim_dst, uint32_t xmin, uint32_t ymin, uint32_t xmax, uint32_t ymax, uint32_t value)
|
||||
{
|
||||
uint32_t xmax8, x, y;
|
||||
uint32_t *pStart, *pEnd;
|
||||
|
||||
xmax8 = xmax - ((xmax-xmin)%8);
|
||||
for (y=ymin; y < ymax; y += xdim_dst)
|
||||
{
|
||||
pStart = &pDst[xmin + y];
|
||||
pEnd = &pDst[xmax8 + y];
|
||||
while(pStart < pEnd)
|
||||
{
|
||||
__gfx_block_set_8(pStart, value);
|
||||
pStart += 8;
|
||||
}
|
||||
// Do remainder
|
||||
for (x=xmax8; x < xmax; x++)
|
||||
{
|
||||
pDst[x + y] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _GFX_BLIT_const_hw(uint32_t* pDst, uint32_t xdim_dst, uint32_t xmin, uint32_t ymin, uint32_t xmax, uint32_t ymax, uint32_t value, uint32_t wait_finish)
|
||||
{
|
||||
uint32_t *pStart, *pEnd;
|
||||
|
||||
pStart = (uint32_t*)&pDst[xmin + ymin*xdim_dst];
|
||||
|
||||
g_pRegs->pVGA_dst = (uint32_t)pStart;
|
||||
g_pRegs->pVGA_dst_dimx = xdim_dst;
|
||||
g_pRegs->pVGA_nx = xmax - xmin + 1;
|
||||
g_pRegs->pVGA_ny = ymax - ymin + 1;
|
||||
g_pRegs->pVGA_color = value;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY);
|
||||
|
||||
g_pRegs->pVGA_ctrl |= (SYS_VGA_BIT_BLIT_REQ | SYS_VGA_BIT_BLIT_OP_CONSTCOL);
|
||||
|
||||
if (!wait_finish)
|
||||
return;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_ACTIVE);
|
||||
}
|
||||
|
||||
void GFX_DirtyRectSetClean(gfx_t *pObj, buf_t *pBuf)
|
||||
{
|
||||
pBuf->dirty.xmin = pBuf->w;
|
||||
pBuf->dirty.xmax = 0;
|
||||
pBuf->dirty.ymin = pBuf->h;
|
||||
pBuf->dirty.ymax = 0;
|
||||
pBuf->is_dirty = 0;
|
||||
}
|
||||
|
||||
void GFX_DirtyRectInit(gfx_t *pObj, buf_t *pBuf, uint32_t w, uint32_t h)
|
||||
{
|
||||
pBuf->w = w;
|
||||
pBuf->h = h;
|
||||
GFX_DirtyRectSetClean(pObj, pBuf);
|
||||
}
|
||||
|
||||
void GFX_DirtyRectUpdate(gfx_t *pObj, buf_t *pBuf, uint32_t xmin, uint32_t xmax, uint32_t ymin, uint32_t ymax)
|
||||
{
|
||||
|
||||
if (xmin < pBuf->dirty.xmin)
|
||||
{
|
||||
pBuf->is_dirty = 1;
|
||||
pBuf->dirty.xmin = xmin;
|
||||
}
|
||||
|
||||
if (xmax > pBuf->dirty.xmax)
|
||||
{
|
||||
pBuf->is_dirty = 1;
|
||||
pBuf->dirty.xmax = xmax;
|
||||
}
|
||||
|
||||
if (ymin < pBuf->dirty.ymin)
|
||||
{
|
||||
pBuf->is_dirty = 1;
|
||||
pBuf->dirty.ymin = ymin;
|
||||
}
|
||||
|
||||
if (ymax > pBuf->dirty.ymax)
|
||||
{
|
||||
pBuf->is_dirty = 1;
|
||||
pBuf->dirty.ymax = ymax;
|
||||
}
|
||||
|
||||
if (pBuf->is_dirty && ((pBuf->dirty.xmax-pBuf->dirty.xmin+1)%8))
|
||||
pBuf->dirty.xmax = pBuf->dirty.xmin + ((pBuf->dirty.xmax-pBuf->dirty.xmin)/8 + 1) * 8; // Make len_x multiple of 8
|
||||
|
||||
pObj->restore.xmin = pBuf->dirty.xmin;
|
||||
pObj->restore.xmax = pBuf->dirty.xmax;
|
||||
pObj->restore.ymin = pBuf->dirty.ymin;
|
||||
pObj->restore.ymax = pBuf->dirty.ymax;
|
||||
|
||||
}
|
||||
|
||||
void GFX_DirtyRectCopy(gfx_t *pObj, buf_t *pBuf)
|
||||
{
|
||||
uint32_t xmin, xmax, xmax8, ymin, ymax, x, y;
|
||||
uint32_t *pDst, *pDst_end;
|
||||
uint32_t *pSrc, *pSrc_end;
|
||||
|
||||
xmin = pBuf->dirty.xmin;
|
||||
xmax = pBuf->dirty.xmax;
|
||||
|
||||
ymin = pBuf->dirty.ymin;
|
||||
ymax = pBuf->dirty.ymax;
|
||||
|
||||
ymin *= pBuf->w;
|
||||
ymax *= pBuf->w;
|
||||
|
||||
#ifdef USE_HW_BLITTER
|
||||
pSrc = (uint32_t*)&pBuf->pLast->pFB[xmin + ymin];
|
||||
pDst = (uint32_t*)&pBuf->pFB[xmin + ymin];
|
||||
|
||||
g_pRegs->pVGA_src0 = (uint32_t)pSrc;
|
||||
g_pRegs->pVGA_dst = (uint32_t)pDst;
|
||||
g_pRegs->pVGA_src0_dimx = (uint32_t)pBuf->w;
|
||||
g_pRegs->pVGA_dst_dimx = (uint32_t)pBuf->w;
|
||||
g_pRegs->pVGA_nx = (uint32_t)(pBuf->dirty.xmax-pBuf->dirty.xmin);
|
||||
g_pRegs->pVGA_ny = (uint32_t)(pBuf->dirty.ymax-pBuf->dirty.ymin);
|
||||
g_pRegs->pVGA_ctrl &= ~SYS_VGA_BIT_BLIT_OP_CONSTCOL;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY);
|
||||
|
||||
g_pRegs->pVGA_ctrl |= SYS_VGA_BIT_BLIT_REQ;
|
||||
|
||||
#else
|
||||
|
||||
xmax8 = xmax - ((xmax-xmin)%8);
|
||||
for (y=ymin; y < ymax; y += pBuf->w)
|
||||
{
|
||||
pSrc = &pBuf->pLast->pFB[xmin + y];
|
||||
pSrc_end = &pBuf->pLast->pFB[xmax8 + y];
|
||||
pDst = &pBuf->pFB[xmin + y];
|
||||
pDst_end = &pBuf->pFB[xmax8 + y];
|
||||
while(pDst < pDst_end)
|
||||
{
|
||||
__gfx_block_copy_8(pDst, pSrc);
|
||||
pDst += 8;
|
||||
pSrc += 8;
|
||||
}
|
||||
// Do remainder
|
||||
for (x=xmax8; x < xmax; x++)
|
||||
{
|
||||
pBuf->pFB[x + y] = pBuf->pLast->pFB[x + y];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void GFX_init(gfx_t *pObj)
|
||||
{
|
||||
int i;
|
||||
buf_t *pBuf;
|
||||
uint32_t w, h, fps;
|
||||
|
||||
g_pRegs = (vga_hw_t*)SYS_VGA_CTRL;
|
||||
|
||||
g_pRegs->pVGA_ctrl &= ~SYS_VGA_BIT_MSTEN;
|
||||
|
||||
w = Screen_get_resx();
|
||||
h = Screen_get_resy();
|
||||
fps = Screen_get_fps();
|
||||
|
||||
// printf("VGA screen = %d x %d @ %d fps\n", w, h, fps);
|
||||
|
||||
pObj->w = w;
|
||||
pObj->h = h;
|
||||
|
||||
// Init background buffer
|
||||
pObj->pBG = (uint32_t*)calloc(w * h, sizeof(buf_t));
|
||||
|
||||
// Init framebuffers
|
||||
pObj->pBuf = (buf_t*)calloc(1, sizeof(buf_t));
|
||||
pBuf = pObj->pBuf;
|
||||
pBuf->pFB = (uint32_t*)calloc((w+8) * h, sizeof(uint32_t)); // w+8 because of dirty rectangle 8 byte min. x-size
|
||||
for (i=1; i < GFX_NUM_FRAME_BUFFERS; i++)
|
||||
{
|
||||
|
||||
pBuf->pNext = (buf_t*)calloc(1, sizeof(buf_t));
|
||||
pBuf->pNext->pLast = pBuf;
|
||||
pBuf = pBuf->pNext;
|
||||
pBuf->pFB = (uint32_t*)calloc((w+8) * h, sizeof(uint32_t)); // w+8 because of dirty rectangle 8 byte min. x-size
|
||||
}
|
||||
pObj->pBuf->pLast = pBuf;
|
||||
pBuf->pNext = pObj->pBuf;
|
||||
|
||||
pBuf = pObj->pBuf;
|
||||
for (i=0; i < GFX_NUM_FRAME_BUFFERS; i++)
|
||||
{
|
||||
GFX_DirtyRectInit(pObj, pBuf, w, h);
|
||||
|
||||
// fprintf(stderr, "pBuf = %08X, pLast = %08X, pNext = %08X\n", pBuf, pBuf->pLast, pBuf->pNext);
|
||||
pBuf = pBuf->pNext;
|
||||
}
|
||||
|
||||
g_pRegs->pVGA_front = (uint32_t)pObj->pBuf->pLast->pFB;
|
||||
g_pRegs->pVGA_back = (uint32_t)pObj->pBuf->pLast->pFB;
|
||||
g_pRegs->pVGA_ctrl |= SYS_VGA_BIT_MSTEN;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void GFX_set_background(gfx_t *pObj, uint32_t *pImage, uint32_t image_nx, uint32_t image_ny, uint32_t image_scale_x, uint32_t image_scale_y)
|
||||
{
|
||||
|
||||
uint32_t off_x, off_y;
|
||||
uint32_t i, j;
|
||||
uint32_t *pDst, *pSrc;
|
||||
buf_t *pBuf;
|
||||
|
||||
if (!pImage)
|
||||
return;
|
||||
|
||||
off_x = (pObj->w-(image_scale_x*image_nx))/2;
|
||||
off_y = (pObj->h-(image_scale_y*image_ny))/2;
|
||||
|
||||
#ifdef USE_HW_BLITTER
|
||||
|
||||
pDst = ((uint32_t*)pObj->pBG) + pObj->w*off_y + off_x;
|
||||
pSrc = pImage;
|
||||
|
||||
g_pRegs->pVGA_src0 = (uint32_t)pSrc;
|
||||
g_pRegs->pVGA_dst = (uint32_t)pDst;
|
||||
g_pRegs->pVGA_src0_dimx = (uint32_t)0;
|
||||
g_pRegs->pVGA_dst_dimx = (uint32_t)0;
|
||||
g_pRegs->pVGA_nx = (uint32_t)image_ny*image_nx;
|
||||
g_pRegs->pVGA_ny = (uint32_t)1;
|
||||
g_pRegs->pVGA_ctrl &= ~SYS_VGA_BIT_BLIT_OP_CONSTCOL;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY);
|
||||
|
||||
g_pRegs->pVGA_ctrl |= SYS_VGA_BIT_BLIT_REQ;
|
||||
|
||||
pBuf = pObj->pBuf;
|
||||
|
||||
pDst = pBuf->pFB;
|
||||
pSrc = pObj->pBG;
|
||||
|
||||
g_pRegs->pVGA_src0 = (uint32_t)pSrc;
|
||||
g_pRegs->pVGA_dst = (uint32_t)pDst;
|
||||
g_pRegs->pVGA_src0_dimx = (uint32_t)0;
|
||||
g_pRegs->pVGA_dst_dimx = (uint32_t)0;
|
||||
g_pRegs->pVGA_nx = (uint32_t)image_ny*image_nx;
|
||||
g_pRegs->pVGA_ny = (uint32_t)1;
|
||||
g_pRegs->pVGA_ctrl &= ~SYS_VGA_BIT_BLIT_OP_CONSTCOL;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY);
|
||||
|
||||
g_pRegs->pVGA_ctrl |= SYS_VGA_BIT_BLIT_REQ;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_ACTIVE);
|
||||
|
||||
#else
|
||||
|
||||
pDst = ((uint32_t*)pObj->pBG) + pObj->w*off_y + off_x;
|
||||
pSrc = pImage;
|
||||
|
||||
for (i=0; i < image_ny*image_nx; i += 8)
|
||||
{
|
||||
__gfx_block_copy_8(pDst, pSrc);
|
||||
pDst += 8;
|
||||
pSrc += 8;
|
||||
}
|
||||
|
||||
pBuf = pObj->pBuf;
|
||||
|
||||
pDst = pBuf->pFB;
|
||||
pSrc = pObj->pBG;
|
||||
|
||||
for (i=0; i < image_ny*image_nx; i += 8)
|
||||
{
|
||||
__gfx_block_copy_8(pDst, pSrc);
|
||||
pDst += 8;
|
||||
pSrc += 8;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
GFX_DirtyRectUpdate(pObj, pBuf, 0, pObj->w-1, 0, pObj->h-1);
|
||||
pBuf = pBuf->pNext;
|
||||
|
||||
} while(pBuf != pObj->pBuf);
|
||||
|
||||
}
|
||||
|
||||
void GFX_frame(gfx_t *pObj, uint32_t sync_mode)
|
||||
{
|
||||
|
||||
// Wait until back buffer becomes front
|
||||
if (sync_mode == GFX_FRAME_SYNC)
|
||||
{
|
||||
while(g_pRegs->pVGA_front == (uint32_t)pObj->pBuf->pFB);
|
||||
}
|
||||
|
||||
GFX_copy_front2back(pObj);
|
||||
|
||||
// Invalidate D-Cache after blitting has finished
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY);
|
||||
|
||||
#ifdef USE_HW_BLITTER
|
||||
DCACHE_invalidate_all();
|
||||
#endif
|
||||
}
|
||||
|
||||
void GFX_show(gfx_t *pObj)
|
||||
{
|
||||
|
||||
g_pRegs->pVGA_back = (uint32_t)pObj->pBuf->pFB;
|
||||
pObj->pBuf = pObj->pBuf->pNext;
|
||||
|
||||
}
|
||||
|
||||
void GFX_copy_front2back(gfx_t *pObj)
|
||||
{
|
||||
buf_t *pBuf;
|
||||
|
||||
pBuf = pObj->pBuf;
|
||||
|
||||
// Lopp over all frame buffers, except front buffer
|
||||
while(pBuf != pObj->pBuf->pLast)
|
||||
{
|
||||
if (pBuf->is_dirty)
|
||||
{
|
||||
// fprintf(stderr, "Dirty rect [%08X]: w=%d, h=%d\n", (int)pBuf, pBuf->dirty.xmax - pBuf->dirty.xmin, pBuf->dirty.ymax - pBuf->dirty.ymin);
|
||||
GFX_DirtyRectCopy(pObj, pBuf);
|
||||
GFX_DirtyRectSetClean(pObj, pBuf);
|
||||
}
|
||||
pBuf = pBuf->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
void GFX_get_FB_front(gfx_t *pObj, uint32_t **ppFB)
|
||||
{
|
||||
*ppFB = pObj->pBuf->pLast->pFB;
|
||||
}
|
||||
|
||||
void box_create(box_t *pObj, uint32_t w, uint32_t h)
|
||||
{
|
||||
pObj->w = w;
|
||||
pObj->h = h;
|
||||
}
|
||||
|
||||
void GFX_restore(gfx_t *pObj, box_t *pBox, uint32_t posx, uint32_t posy)
|
||||
{
|
||||
uint32_t xmin, xmax, xmax8, ymin, ymax, x, y, nx, ny;
|
||||
uint32_t *pDst, *pDst_end;
|
||||
uint32_t *pSrc, *pSrc_end;
|
||||
buf_t *pBuf;
|
||||
|
||||
if (pBox)
|
||||
{
|
||||
xmin = posx;
|
||||
xmax = pBox->w + posx - 0;
|
||||
if (xmax >= pObj->w)
|
||||
xmax = pObj->w - 0;
|
||||
|
||||
ymin = posy;
|
||||
ymax = pBox->h + posy - 0;
|
||||
if (ymax >= pObj->h)
|
||||
ymax = pObj->h - 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xmin = pObj->restore.xmin;
|
||||
xmax = pObj->restore.xmax;
|
||||
ymin = pObj->restore.ymin;
|
||||
ymax = pObj->restore.ymax;
|
||||
}
|
||||
pObj->restore.xmin = 0;
|
||||
pObj->restore.xmax = 0;
|
||||
pObj->restore.ymin = 0;
|
||||
pObj->restore.ymax = 0;
|
||||
pBuf = pObj->pBuf->pNext;
|
||||
|
||||
// Lopp over all frame buffers, except current back buffer
|
||||
while(pBuf != pObj->pBuf)
|
||||
{
|
||||
GFX_DirtyRectUpdate(pObj, pBuf, xmin, xmax, ymin, ymax);
|
||||
pBuf = pBuf->pNext;
|
||||
|
||||
}
|
||||
|
||||
nx = xmax - xmin;
|
||||
ny = ymax - ymin;
|
||||
|
||||
pBuf = pObj->pBuf;
|
||||
|
||||
ymin *= pObj->w;
|
||||
ymax *= pObj->w;
|
||||
|
||||
#ifdef USE_HW_BLITTER
|
||||
pSrc = (uint32_t*)&pObj->pBG[xmin + ymin];
|
||||
pDst = (uint32_t*)&pBuf->pFB[xmin + ymin];
|
||||
|
||||
g_pRegs->pVGA_src0 = (uint32_t)pSrc;
|
||||
g_pRegs->pVGA_dst = (uint32_t)pDst;
|
||||
g_pRegs->pVGA_src0_dimx = (uint32_t)pObj->w;
|
||||
g_pRegs->pVGA_dst_dimx = (uint32_t)pObj->w;
|
||||
g_pRegs->pVGA_nx = (uint32_t)nx;
|
||||
g_pRegs->pVGA_ny = (uint32_t)ny;
|
||||
g_pRegs->pVGA_ctrl &= ~SYS_VGA_BIT_BLIT_OP_CONSTCOL;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY);
|
||||
|
||||
g_pRegs->pVGA_ctrl |= SYS_VGA_BIT_BLIT_REQ;
|
||||
|
||||
#else
|
||||
|
||||
xmax8 = xmax - ((xmax-xmin)%8);
|
||||
for (y=ymin; y < ymax; y += pBuf->w)
|
||||
{
|
||||
pSrc = &pObj->pBG[xmin + y];
|
||||
pSrc_end = &pObj->pBG[xmax8 + y];
|
||||
pDst = &pBuf->pFB[xmin + y];
|
||||
pDst_end = &pBuf->pFB[xmax8 + y];
|
||||
while(pDst < pDst_end)
|
||||
{
|
||||
__gfx_block_copy_8(pDst, pSrc);
|
||||
pDst += 8;
|
||||
pSrc += 8;
|
||||
}
|
||||
// Do remainder
|
||||
for (x=xmax8; x < xmax; x++)
|
||||
{
|
||||
pBuf->pFB[x + y] = pObj->pBG[x + y];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void GFX_box_draw_direct(gfx_t *pObj, box_t *pBox, uint32_t posx, uint32_t posy, uint32_t color)
|
||||
{
|
||||
uint32_t xmin, xmax, xmax8, ymin, ymax, x, y;
|
||||
uint32_t *pFB, *pFB_end;
|
||||
buf_t *pBuf;
|
||||
|
||||
pBuf = pObj->pBuf->pLast;
|
||||
|
||||
xmin = posx;
|
||||
xmax = pBox->w + posx - 0;
|
||||
if (xmax >= pObj->w)
|
||||
xmax = pObj->w - 0;
|
||||
|
||||
ymin = posy;
|
||||
ymax = pBox->h + posy - 0;
|
||||
if (ymax >= pObj->h)
|
||||
ymax = pObj->h - 0;
|
||||
|
||||
ymin *= pObj->w;
|
||||
ymax *= pObj->w;
|
||||
|
||||
xmax8 = xmax - ((xmax-xmin)%8);
|
||||
for (y=ymin; y < ymax; y += pObj->w)
|
||||
{
|
||||
pFB = &pBuf->pFB[xmin + y];
|
||||
pFB_end = &pBuf->pFB[xmax8 + y];
|
||||
while(pFB < pFB_end)
|
||||
{
|
||||
__gfx_block_set_8(pFB, color);
|
||||
pFB += 8;
|
||||
}
|
||||
// Do remainder
|
||||
for (x=xmax8; x < xmax; x++)
|
||||
{
|
||||
pBuf->pFB[x + y] = color;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GFX_box_draw(gfx_t *pObj, box_t *pBox, uint32_t posx, uint32_t posy, uint32_t color)
|
||||
{
|
||||
uint32_t xmin, xmax, xmax8, ymin, ymax, x, y, nx, ny;
|
||||
uint32_t *pFB, *pFB_end;
|
||||
buf_t *pBuf;
|
||||
|
||||
xmin = posx;
|
||||
xmax = pBox->w + posx - 0;
|
||||
if (xmax >= pObj->w)
|
||||
xmax = pObj->w - 0;
|
||||
|
||||
ymin = posy;
|
||||
ymax = pBox->h + posy - 0;
|
||||
if (ymax >= pObj->h)
|
||||
ymax = pObj->h - 0;
|
||||
|
||||
nx = xmax - xmin;
|
||||
ny = ymax - ymin;
|
||||
|
||||
// fprintf(stderr, "GFX_box_draw(): x=%d, y=%d, nx=%d, ny=%d\n", posx, posy, nx, ny);
|
||||
|
||||
pBuf = pObj->pBuf->pNext;
|
||||
|
||||
// Lopp over all frame buffers, except current back buffer
|
||||
while(pBuf != pObj->pBuf)
|
||||
{
|
||||
GFX_DirtyRectUpdate(pObj, pBuf, xmin, xmax-1, ymin, ymax-1);
|
||||
pBuf = pBuf->pNext;
|
||||
|
||||
}
|
||||
pBuf = pObj->pBuf;
|
||||
|
||||
ymin *= pObj->w;
|
||||
ymax *= pObj->w;
|
||||
|
||||
#ifdef USE_HW_BLITTER
|
||||
|
||||
pFB = (uint32_t*)&pBuf->pFB[xmin + ymin];
|
||||
|
||||
g_pRegs->pVGA_dst = (uint32_t)pFB;
|
||||
g_pRegs->pVGA_dst_dimx = (uint32_t)pObj->w;
|
||||
g_pRegs->pVGA_nx = (uint32_t)nx;
|
||||
g_pRegs->pVGA_ny = (uint32_t)ny;
|
||||
g_pRegs->pVGA_color = color;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY);
|
||||
|
||||
g_pRegs->pVGA_ctrl |= (SYS_VGA_BIT_BLIT_REQ | SYS_VGA_BIT_BLIT_OP_CONSTCOL);
|
||||
|
||||
|
||||
#else
|
||||
|
||||
xmax8 = xmax - ((xmax-xmin)%8);
|
||||
for (y=ymin; y < ymax; y += pObj->w)
|
||||
{
|
||||
pFB = &pBuf->pFB[xmin + y];
|
||||
pFB_end = &pBuf->pFB[xmax8 + y];
|
||||
while(pFB < pFB_end)
|
||||
{
|
||||
__gfx_block_set_8(pFB, color);
|
||||
pFB += 8;
|
||||
}
|
||||
// Do remainder
|
||||
for (x=xmax8; x < xmax; x++)
|
||||
{
|
||||
pBuf->pFB[x + y] = color;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void GFX_box_draw_bg(gfx_t *pObj, box_t *pBox, uint32_t posx, uint32_t posy, uint32_t color)
|
||||
{
|
||||
uint32_t xmin, xmax, xmax8, ymin, ymax, x, y, nx, ny;
|
||||
uint32_t *pFB, *pFB_end;
|
||||
|
||||
xmin = posx;
|
||||
xmax = pBox->w + posx - 0;
|
||||
if (xmax >= pObj->w)
|
||||
xmax = pObj->w - 0;
|
||||
|
||||
ymin = posy;
|
||||
ymax = pBox->h + posy - 0;
|
||||
if (ymax >= pObj->h)
|
||||
ymax = pObj->h - 0;
|
||||
|
||||
nx = xmax - xmin;
|
||||
ny = ymax - ymin;
|
||||
|
||||
ymin *= pObj->w;
|
||||
ymax *= pObj->w;
|
||||
|
||||
|
||||
#ifdef USE_HW_BLITTER
|
||||
|
||||
pFB = (uint32_t*)&pObj->pBG[xmin + ymin];
|
||||
|
||||
g_pRegs->pVGA_dst = (uint32_t)pFB;
|
||||
g_pRegs->pVGA_dst_dimx = (uint32_t)pObj->w;
|
||||
g_pRegs->pVGA_nx = (uint32_t)nx;
|
||||
g_pRegs->pVGA_ny = (uint32_t)ny;
|
||||
g_pRegs->pVGA_color = color;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY);
|
||||
|
||||
g_pRegs->pVGA_ctrl |= (SYS_VGA_BIT_BLIT_REQ | SYS_VGA_BIT_BLIT_OP_CONSTCOL);
|
||||
|
||||
#else
|
||||
|
||||
xmax8 = xmax - ((xmax-xmin)%8);
|
||||
for (y=ymin; y < ymax; y += pObj->w)
|
||||
{
|
||||
pFB = &pObj->pBG[xmin + y];
|
||||
pFB_end = &pObj->pBG[xmax8 + y];
|
||||
while(pFB < pFB_end)
|
||||
{
|
||||
__gfx_block_set_8(pFB, color);
|
||||
pFB += 8;
|
||||
}
|
||||
// Do remainder
|
||||
for (x=xmax8; x < xmax; x++)
|
||||
{
|
||||
pObj->pBG[x + y] = color;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void GFX_box_blit_bg(gfx_t *pObj, box_t *pBox, uint32_t pos_x_src, uint32_t pos_y_src, uint32_t pos_x_dst, uint32_t pos_y_dst)
|
||||
{
|
||||
|
||||
uint32_t x_src, y_src, xmax8_src;
|
||||
uint32_t x_dst, y_dst, xmax8_dst;
|
||||
uint32_t xmin_src, xmax_src, ymin_src, ymax_src;
|
||||
uint32_t xmin_dst, xmax_dst, ymin_dst, ymax_dst;
|
||||
uint32_t *pDst, *pDst_end;
|
||||
uint32_t *pSrc, *pSrc_end;
|
||||
buf_t *pBuf;
|
||||
pBuf = pObj->pBuf->pNext;
|
||||
|
||||
xmin_src = pos_x_src;
|
||||
xmax_src = pBox->w + pos_x_src - 0;
|
||||
if (xmax_src >= pObj->w)
|
||||
xmax_src = pObj->w - 0;
|
||||
|
||||
ymin_src = pos_y_src;
|
||||
ymax_src = pBox->h + pos_y_src - 0;
|
||||
if (ymax_src >= pObj->h)
|
||||
ymax_src = pObj->h - 0;
|
||||
|
||||
xmin_dst = pos_x_dst;
|
||||
xmax_dst = pBox->w + pos_x_dst - 0;
|
||||
if (xmax_dst >= pObj->w)
|
||||
xmax_dst = pObj->w - 0;
|
||||
|
||||
ymin_dst = pos_y_dst;
|
||||
ymax_dst = pBox->h + pos_y_dst - 0;
|
||||
if (ymax_dst >= pObj->h)
|
||||
ymax_dst = pObj->h - 0;
|
||||
|
||||
// Lopp over all frame buffers, except current back buffer
|
||||
while(pBuf != pObj->pBuf)
|
||||
{
|
||||
GFX_DirtyRectUpdate(pObj, pBuf, xmin_dst, xmax_dst, ymin_dst, ymax_dst);
|
||||
pBuf = pBuf->pNext;
|
||||
|
||||
}
|
||||
pBuf = pObj->pBuf;
|
||||
|
||||
#ifdef USE_HW_BLITTER
|
||||
pSrc = (uint32_t*)&pObj->pBG[xmin_src + ymin_src*pObj->w];
|
||||
pDst = (uint32_t*)&pBuf->pFB[xmin_dst + ymin_dst*pObj->w];
|
||||
|
||||
g_pRegs->pVGA_src0 = (uint32_t)pSrc;
|
||||
g_pRegs->pVGA_src0_dimx = pObj->w;
|
||||
g_pRegs->pVGA_dst = (uint32_t)pDst;
|
||||
g_pRegs->pVGA_dst_dimx = pObj->w;
|
||||
g_pRegs->pVGA_nx = pBox->w;
|
||||
g_pRegs->pVGA_ny = pBox->h;
|
||||
|
||||
while (g_pRegs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY);
|
||||
|
||||
g_pRegs->pVGA_ctrl &= ~SYS_VGA_BIT_BLIT_OP_CONSTCOL;
|
||||
g_pRegs->pVGA_ctrl |= SYS_VGA_BIT_BLIT_REQ;
|
||||
|
||||
#else
|
||||
|
||||
ymin_src *= pObj->w;
|
||||
ymax_src *= pObj->w;
|
||||
ymin_dst *= pObj->w;
|
||||
ymax_dst *= pObj->w;
|
||||
|
||||
y_dst = ymin_dst;
|
||||
xmax8_src = xmax_src - ((xmax_src-xmin_src)%8);
|
||||
xmax8_dst = xmax_dst - ((xmax_dst-xmin_dst)%8);
|
||||
for (y_src=ymin_src; y_src < ymax_src; y_src += pBuf->w)
|
||||
{
|
||||
pSrc = &pObj->pBG[xmin_src + y_src];
|
||||
pSrc_end = &pObj->pBG[xmax8_src + y_src];
|
||||
pDst = &pBuf->pFB[xmin_dst + y_dst];
|
||||
pDst_end = &pBuf->pFB[xmax8_dst + y_dst];
|
||||
while(pDst < pDst_end)
|
||||
{
|
||||
__gfx_block_copy_8(pDst, pSrc);
|
||||
pDst += 8;
|
||||
pSrc += 8;
|
||||
}
|
||||
// Do remainder
|
||||
for (x_src=xmax8_src; x_src < xmax_src; x_src++)
|
||||
{
|
||||
*(pDst++) = *(pSrc++);
|
||||
}
|
||||
y_dst += pBuf->w;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#ifndef GFX_H
|
||||
#define GFX_H
|
||||
|
||||
#include "libsys.h"
|
||||
|
||||
#define GFX_NUM_FRAME_BUFFERS 2
|
||||
#define GFX_FRAME_NOSYNC 0
|
||||
#define GFX_FRAME_SYNC 1
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Types
|
||||
// -------------------------------------------------------------
|
||||
typedef struct _sbox_t
|
||||
{
|
||||
uint32_t w, h;
|
||||
} box_t;
|
||||
|
||||
typedef struct _srect_t
|
||||
{
|
||||
uint32_t xmin, xmax;
|
||||
uint32_t ymin, ymax;
|
||||
} rect_t;
|
||||
|
||||
typedef struct _svga_hw_t
|
||||
{
|
||||
uint32_t volatile pVGA_ctrl; // 0xA0030000 // R/W
|
||||
uint32_t volatile pVGA_ascii; // 0xA0030004 // R/W
|
||||
uint32_t volatile pVGA_posx; // 0xA0030008 // R/W
|
||||
uint32_t volatile pVGA_posy; // 0xA003000C // R/W
|
||||
uint32_t volatile pVGA_cgcol; // 0xA0030010 // R/W
|
||||
uint32_t volatile pVGA_res; // 0xA0030014 // RO
|
||||
uint32_t volatile pVGA_front; // 0xA0030018 // R/W
|
||||
uint32_t volatile pVGA_back; // 0xA003001C // R/W
|
||||
uint32_t volatile pVGA_src0; // 0xA0030020 // R/W
|
||||
uint32_t volatile pVGA_src0_dimx; // 0xA0030024 // R/W
|
||||
uint32_t volatile pVGA_gap0; // 0xA0030028 // R/W
|
||||
uint32_t volatile pVGA_gap1; // 0xA003002C // R/W
|
||||
uint32_t volatile pVGA_src1; // 0xA0030030 // R/W
|
||||
uint32_t volatile pVGA_src1_dimx; // 0xA0030034 // R/W
|
||||
uint32_t volatile pVGA_gap2; // 0xA0030038 // R/W
|
||||
uint32_t volatile pVGA_gap3; // 0xA003003C // R/W
|
||||
uint32_t volatile pVGA_dst; // 0xA0030040 // R/W
|
||||
uint32_t volatile pVGA_dst_dimx; // 0xA0030044 // R/W
|
||||
uint32_t volatile pVGA_gap4; // 0xA0030048 // R/W
|
||||
uint32_t volatile pVGA_gap5; // 0xA003004C // R/W
|
||||
uint32_t volatile pVGA_nx; // 0xA0030050 // R/W
|
||||
uint32_t volatile pVGA_ny; // 0xA0030054 // R/W
|
||||
uint32_t volatile pVGA_color; // 0xA0030058 // R/W
|
||||
|
||||
} vga_hw_t;
|
||||
|
||||
typedef struct _sbuf_t
|
||||
{
|
||||
uint32_t *pFB;
|
||||
struct _sbuf_t *pNext;
|
||||
struct _sbuf_t *pLast;
|
||||
uint32_t is_dirty;
|
||||
rect_t dirty;
|
||||
uint32_t w, h;
|
||||
} buf_t;
|
||||
|
||||
typedef struct _sgfx_t
|
||||
{
|
||||
uint32_t w, h;
|
||||
buf_t *pBuf;
|
||||
uint32_t *pBG;
|
||||
rect_t restore;
|
||||
|
||||
} gfx_t;
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Functions
|
||||
// -------------------------------------------------------------
|
||||
void __gfx_block_set_8(uint32_t* pDst, uint32_t value);
|
||||
void __gfx_block_copy_8(uint32_t* pDst, uint32_t* pSrc);
|
||||
void _GFX_copy32(uint32_t* pDst, uint32_t* pSrc, uint32_t ndwords);
|
||||
void _GFX_copy32_hw(uint32_t* pDst, uint32_t* pSrc, uint32_t ndwords, uint32_t wait_finish);
|
||||
void _GFX_memset32(uint32_t* pDst, uint32_t value, uint32_t ndwords);
|
||||
void _GFX_memset32_hw(uint32_t* pDst, uint32_t value, uint32_t ndwords, uint32_t wait_finish);
|
||||
void _GFX_BLIT_const(uint32_t* pDst, uint32_t xdim_dst, uint32_t xmin, uint32_t ymin, uint32_t xmax, uint32_t ymax, uint32_t value);
|
||||
void _GFX_BLIT_const_hw(uint32_t* pDst, uint32_t xdim_dst, uint32_t xmin, uint32_t ymin, uint32_t xmax, uint32_t ymax, uint32_t value, uint32_t wait_finish);
|
||||
void GFX_init(gfx_t *pObj);
|
||||
void GFX_set_background(gfx_t *pObj, uint32_t *pImage, uint32_t image_nx, uint32_t image_ny, uint32_t image_scale_x, uint32_t image_scale_y);
|
||||
void GFX_frame(gfx_t *pObj, uint32_t sync_mode);
|
||||
void GFX_show(gfx_t *pObj);
|
||||
void GFX_copy_front2back(gfx_t *pObj);
|
||||
void GFX_get_FB_front(gfx_t *pObj, uint32_t **ppFB);
|
||||
void box_create(box_t *pObj, uint32_t w, uint32_t h);
|
||||
void GFX_restore(gfx_t *pObj, box_t *pBox, uint32_t posx, uint32_t posy);
|
||||
void GFX_box_draw_direct(gfx_t *pObj, box_t *pBox, uint32_t posx, uint32_t posy, uint32_t color);
|
||||
void GFX_box_draw(gfx_t *pObj, box_t *pBox, uint32_t posx, uint32_t posy, uint32_t color);
|
||||
void GFX_box_draw_bg(gfx_t *pObj, box_t *pBox, uint32_t posx, uint32_t posy, uint32_t color);
|
||||
void GFX_box_blit_bg(gfx_t *pObj, box_t *pBox, uint32_t pos_x_src, uint32_t pos_y_src, uint32_t pos_x_dst, uint32_t pos_y_dst);
|
||||
|
||||
#endif // GFX_H
|
||||
@@ -0,0 +1,472 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "libsys.h"
|
||||
#include "mips_ps2.h"
|
||||
|
||||
uint32_t ps2_readchar(ps2_if_t *pIF);
|
||||
|
||||
const ps2_if_t ps2_if[2] =
|
||||
{
|
||||
{ps2_type_unknown, (uint32_t*)SYS_PS2_0_STAT, (uint32_t*)SYS_PS2_0_DATA},
|
||||
{ps2_type_unknown, (uint32_t*)SYS_PS2_1_STAT, (uint32_t*)SYS_PS2_1_DATA}
|
||||
};
|
||||
|
||||
uint32_t PS2_get_num_if(void)
|
||||
{
|
||||
return (sizeof(ps2_if)/sizeof(ps2_if_t));
|
||||
}
|
||||
|
||||
int PS2_readchar(void const *pInst)
|
||||
{
|
||||
assert(pInst);
|
||||
ps2_if_t *pIF = (ps2_if_t*)pInst;
|
||||
|
||||
return (int)ps2_readchar(pIF);
|
||||
}
|
||||
|
||||
void PS2_open(void const *pInst)
|
||||
{
|
||||
assert(pInst);
|
||||
ps2_if_t *pIF = (ps2_if_t*)pInst;
|
||||
|
||||
PS2_init(pIF);
|
||||
|
||||
}
|
||||
|
||||
void PS2_close(void const *pInst)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PS2_byte_write(ps2_if_t *pIF, uint8_t byte)
|
||||
{
|
||||
assert(pIF);
|
||||
|
||||
while(!(*pIF->pCTRL & SYS_PS2_BIT_TX_EMPTY));
|
||||
|
||||
*pIF->pDATA = (uint32_t)byte;
|
||||
}
|
||||
|
||||
uint32_t PS2_byte_read(ps2_if_t *pIF, uint32_t timeout_ms)
|
||||
{
|
||||
assert(pIF);
|
||||
|
||||
while(!(*pIF->pCTRL & SYS_PS2_BIT_RX_AVAIL))
|
||||
{
|
||||
timeout_ms--;
|
||||
if (!timeout_ms)
|
||||
return PS2_ERR_TIMEOUT;
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
return (uint32_t)*pIF->pDATA;
|
||||
}
|
||||
|
||||
uint32_t PS2_cmd(ps2_if_t *pIF, uint8_t cmd, uint32_t ack_timeout_ms)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
PS2_byte_write(pIF, cmd);
|
||||
result = PS2_byte_read(pIF, ack_timeout_ms);
|
||||
if (0xFA != result)
|
||||
{
|
||||
printf ("PS2_cmd(%p): no ACK received. Result = %08X\n", pIF->pCTRL, result);
|
||||
return PS2_ERR_PS2_PREFIX | result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PS2_flush(ps2_if_t *pIF)
|
||||
{
|
||||
while (!IS_ERROR(PS2_byte_read(pIF, 10)));
|
||||
}
|
||||
|
||||
uint32_t PS2_init(ps2_if_t *pIF)
|
||||
{
|
||||
int i;
|
||||
uint8_t id[2];
|
||||
|
||||
pIF->type = ps2_type_unknown;
|
||||
|
||||
uint32_t result;
|
||||
|
||||
// Disable RX-interrupt
|
||||
*pIF->pCTRL &= ~SYS_PS2_BIT_RX_INTEN;
|
||||
|
||||
printf ("PS2_init(%p) - Initialize... ", pIF->pCTRL);
|
||||
|
||||
// Flush buffer
|
||||
PS2_flush(pIF);
|
||||
|
||||
// send RESET
|
||||
result = PS2_cmd(pIF, 0xFF, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("Reset error %08X\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read BAT
|
||||
result = PS2_byte_read(pIF, 1000);
|
||||
if (0xAA != result)
|
||||
{
|
||||
printf ("BAT error %08X\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
printf ("Success\n");
|
||||
|
||||
while(1)
|
||||
{
|
||||
// Read ID
|
||||
result = PS2_byte_read(pIF, 10);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
// No ID => keyboard
|
||||
printf ("PS2_init(%p) - Keyboard detected\n", pIF->pCTRL);
|
||||
|
||||
// send Get Device-ID
|
||||
result = PS2_cmd(pIF, 0xF2, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("Get Device-ID error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
id[0] = PS2_byte_read(pIF, 1000);
|
||||
id[1] = PS2_byte_read(pIF, 1000);
|
||||
printf ("PS2_init(%p) - Device-ID: %02X%02X\n", pIF->pCTRL, id[0], id[1]);
|
||||
|
||||
// Get Scan code set (phase 1)
|
||||
result = PS2_cmd(pIF, 0xF0, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("1. Get Scan code error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
// Get Scan code set (phase 2)
|
||||
result = PS2_cmd(pIF, 0x00, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("2. Get Scan code error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
result = PS2_byte_read(pIF, 1000);
|
||||
printf ("PS2_init(%p) - Current scan code set = %d\n", pIF->pCTRL, result);
|
||||
|
||||
// if Scan code SET != 2
|
||||
if (result != 2)
|
||||
{
|
||||
printf ("PS2_init(%p) - Set scan code set = 2\n", pIF->pCTRL);
|
||||
// Set Scan code set (phase 1)
|
||||
result = PS2_cmd(pIF, 0xF0, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("1. Set Scan code error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
// Set Scan code set (phase 2)
|
||||
result = PS2_cmd(pIF, 0x02, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("2. Set Scan code error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Test LEDs
|
||||
for (i=0; i < 4; i++)
|
||||
{
|
||||
result = PS2_cmd(pIF, 0xED, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("1. LED error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
result = PS2_cmd(pIF, 0x02, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("2. LED error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
sleep(100);
|
||||
result = PS2_cmd(pIF, 0xED, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("1. LED error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
result = PS2_cmd(pIF, 0x04, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("2. LED error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
sleep(100);
|
||||
result = PS2_cmd(pIF, 0xED, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("1. LED error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
result = PS2_cmd(pIF, 0x01, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("2. LED error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
sleep(100);
|
||||
}
|
||||
result = PS2_cmd(pIF, 0xED, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("1. LED error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
result = PS2_cmd(pIF, 0x00, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("2. LED error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
|
||||
pIF->type = ps2_type_keyb;
|
||||
result = pIF->type;
|
||||
break;
|
||||
}
|
||||
|
||||
// We got a byte => maybe mouse
|
||||
if (result == 0)
|
||||
{
|
||||
// We got zero => yes, it's a mouse
|
||||
printf ("PS2_init(%p) - Mouse device detected\n", pIF->pCTRL);
|
||||
|
||||
// send Get Device-ID
|
||||
result = PS2_cmd(pIF, 0xF2, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("Get Device-ID error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
id[0] = PS2_byte_read(pIF, 1000);
|
||||
printf ("PS2_init(%p) - Device-ID: %02X\n", pIF->pCTRL, id[0]);
|
||||
printf ("PS2_init(%p) - Enable stream mode...", pIF->pCTRL);
|
||||
result = PS2_cmd(pIF, 0xF4, 1000);
|
||||
if (IS_ERROR(result))
|
||||
{
|
||||
printf ("error %08X\n", result);
|
||||
break;
|
||||
}
|
||||
printf ("Success\n");
|
||||
pIF->type = ps2_type_mouse;
|
||||
result = pIF->type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush buffer
|
||||
PS2_flush(pIF);
|
||||
|
||||
if (IS_ERROR(result))
|
||||
return result;
|
||||
|
||||
// Enable RX-interrupt
|
||||
*pIF->pCTRL |= SYS_PS2_BIT_RX_INTEN;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// BEGIN QUICK AND DIRTY
|
||||
// -------------------------------------------------------------
|
||||
//keymap for the AT keyboard SG layout
|
||||
typedef struct
|
||||
{
|
||||
uint8_t scancode;
|
||||
uint8_t unshifted;
|
||||
uint8_t shifted;
|
||||
uint8_t altered;
|
||||
} libsys_key_entry_t;
|
||||
|
||||
#define SHIFTED (1<<0)
|
||||
#define ALTERED (1<<1)
|
||||
#define CONTROLLED (1<<2)
|
||||
|
||||
static const libsys_key_entry_t __keymap_german[] =
|
||||
{
|
||||
{0x1c, 'a', 'A', 'a'},
|
||||
{0x32, 'b', 'B', 'b'},
|
||||
{0x21, 'c', 'C', 'c'},
|
||||
{0x23, 'd', 'D', 'd'},
|
||||
{0x24, 'e', 'E', '€'},
|
||||
{0x2b, 'f', 'F', 'f'},
|
||||
{0x34, 'g', 'G', 'g'},
|
||||
{0x33, 'h', 'H', 'h'},
|
||||
{0x43, 'i', 'I', 'i'},
|
||||
{0x3b, 'j', 'J', 'j'},
|
||||
{0x42, 'k', 'K', 'k'},
|
||||
{0x4b, 'l', 'L', 'l'},
|
||||
{0x3a, 'm', 'M', 'µ'},
|
||||
{0x31, 'n', 'N', 'n'},
|
||||
{0x44, 'o', 'O', 'o'},
|
||||
{0x4d, 'p', 'P', 'p'},
|
||||
{0x15, 'q', 'Q', '@'},
|
||||
{0x2d, 'r', 'R', 'r'},
|
||||
{0x1b, 's', 'S', 's'},
|
||||
{0x2c, 't', 'T', 't'},
|
||||
{0x3c, 'u', 'U', 'u'},
|
||||
{0x2a, 'v', 'V', 'v'},
|
||||
{0x1d, 'w', 'W', 'w'},
|
||||
{0x22, 'x', 'X', 'x'},
|
||||
{0x1a, 'y', 'Y', 'y'},
|
||||
{0x35, 'z', 'Z', 'z'},
|
||||
{0x16, '1', '!', '1'},
|
||||
{0x1e, '2', '"', '2'},
|
||||
{0x26, '3', '§', '3'},
|
||||
{0x25, '4', '$', '4'},
|
||||
{0x2e, '5', '%', '5'},
|
||||
{0x36, '6', '&', '6'},
|
||||
{0x3d, '7', '/', '{'},
|
||||
{0x3e, '8', '(', '['},
|
||||
{0x46, '9', ')', ']'},
|
||||
{0x45, '0', '=', '}'},
|
||||
{0x4e, 'ß', '?', '\\'},
|
||||
{0x29, ' ', ' ', ' '},
|
||||
{0x41, ',', ';', ','},
|
||||
{0x49, '.', ':', '.'},
|
||||
{0x4a, '-', '_', '-'},
|
||||
{0x52, 'ä', 'Ä', 'ä'},
|
||||
{0x4c, 'ö', 'Ö', 'ö'},
|
||||
{0x54, 'ü', 'Ü', 'ü'},
|
||||
{0x5a, '\n', '\n', '\n'}, //RETURN
|
||||
{0x5b, '+', '*', '~'},
|
||||
{0x5d, '#', '\'', '#'},
|
||||
{0x0e, '^', '°', '^'},
|
||||
{0x61, '<', '>', '|'},
|
||||
{0x66, '\b', '\b', '\b'},
|
||||
{0} //sentinel
|
||||
|
||||
};
|
||||
|
||||
static char __findkey(char scancode, int mode)
|
||||
{
|
||||
const libsys_key_entry_t *p = __keymap_german;
|
||||
while (p->scancode)
|
||||
{
|
||||
if (p->scancode == scancode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case SHIFTED:
|
||||
return p->shifted;
|
||||
case ALTERED:
|
||||
return p->altered;
|
||||
case ALTERED|SHIFTED:
|
||||
default:
|
||||
return p->unshifted;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define RELEASE 0x8000
|
||||
#define SPECIALKEY 0x4000
|
||||
#define EXTENDED 0x2000
|
||||
#define X_CONTROLLED 0x0400
|
||||
#define X_ALTERED 0x0200
|
||||
#define X_SHIFTED 0x0100
|
||||
#define CAPS (SPECIALKEY|0x58)
|
||||
#define F1 (SPECIALKEY|0x05)
|
||||
#define F2 (SPECIALKEY|0x06)
|
||||
#define F3 (SPECIALKEY|0x04)
|
||||
#define F4 (SPECIALKEY|0x0c)
|
||||
#define F5 (SPECIALKEY|0x03)
|
||||
#define F6 (SPECIALKEY|0x0b)
|
||||
#define F7 (SPECIALKEY|0x83)
|
||||
#define F8 (SPECIALKEY|0x0a)
|
||||
#define F9 (SPECIALKEY|0x01)
|
||||
#define F10 (SPECIALKEY|0x09)
|
||||
#define F11 (SPECIALKEY|0x78)
|
||||
#define F12 (SPECIALKEY|0x07)
|
||||
#define ARROW_UP (SPECIALKEY|EXTENDED|0x75)
|
||||
#define ARROW_DOWN (SPECIALKEY|EXTENDED|0x72)
|
||||
#define ARROW_LEFT (SPECIALKEY|EXTENDED|0x6b)
|
||||
#define ARROW_RIGHT (SPECIALKEY|EXTENDED|0x74)
|
||||
|
||||
uint32_t ps2_readchar(ps2_if_t *pIF)
|
||||
{
|
||||
uint8_t c;
|
||||
static char mode = 0;
|
||||
static char nextrelease = 0;
|
||||
static char extended = 0;
|
||||
int flags = 0;
|
||||
int char_valid = 0;
|
||||
uint8_t key;
|
||||
|
||||
while (!(SYS_PS2_BIT_RX_AVAIL & *pIF->pCTRL));
|
||||
key = *pIF->pDATA & 0xFF;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case 0xf0: //release key
|
||||
nextrelease = 1;
|
||||
break;
|
||||
case 0x14: //control key
|
||||
if (nextrelease)
|
||||
{
|
||||
mode &= ~CONTROLLED;
|
||||
} else
|
||||
{
|
||||
mode |= CONTROLLED;
|
||||
}
|
||||
nextrelease = 0;
|
||||
break;
|
||||
case 0x12: //left SHIFT
|
||||
case 0x59: //right SHIFT
|
||||
if (nextrelease)
|
||||
{
|
||||
mode &= ~SHIFTED;
|
||||
} else
|
||||
{
|
||||
mode |= SHIFTED;
|
||||
}
|
||||
nextrelease = 0;
|
||||
break;
|
||||
case 0x11: //left and right ALT (right one also with E0)
|
||||
if (nextrelease)
|
||||
{
|
||||
mode &= ~ALTERED;
|
||||
} else
|
||||
{
|
||||
mode |= ALTERED;
|
||||
}
|
||||
nextrelease = 0;
|
||||
break;
|
||||
case 0xe0: //extended key following
|
||||
extended = 1;
|
||||
break;
|
||||
default:
|
||||
if (nextrelease) flags |= RELEASE;
|
||||
if (extended) flags |= EXTENDED;
|
||||
flags |= mode << 8;
|
||||
c = __findkey(key, mode);
|
||||
char_valid = (c && ((flags & RELEASE) != RELEASE));
|
||||
nextrelease = 0;
|
||||
extended = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (char_valid)
|
||||
{
|
||||
// fprintf(stderr, "c = %c (%d), flags = 0x%08X, mode = 0x%08X\n", c, c, flags, mode);
|
||||
return c;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
// -------------------------------------------------------------
|
||||
// END QUICK AND DIRTY
|
||||
// -------------------------------------------------------------
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef PS2_H
|
||||
#define PS2_H
|
||||
|
||||
#include "libsys.h"
|
||||
|
||||
// --------------------------------------------------
|
||||
// Types
|
||||
// --------------------------------------------------
|
||||
enum
|
||||
{
|
||||
ps2_type_unknown = 0,
|
||||
ps2_type_keyb,
|
||||
ps2_type_mouse
|
||||
};
|
||||
|
||||
typedef struct _sps2_if_t
|
||||
{
|
||||
uint32_t type;
|
||||
volatile uint32_t *pCTRL;
|
||||
volatile uint32_t *pDATA;
|
||||
} ps2_if_t;
|
||||
|
||||
// --------------------------------------------------
|
||||
// Constants
|
||||
// --------------------------------------------------
|
||||
#define PS2_MODULE_PREFIX 0x1000000
|
||||
#define PS2_SUCCESS LSYS_SUCCESS
|
||||
#define PS2_ERROR (LSYS_ERR_BASE | PS2_MODULE_PREFIX)
|
||||
#define PS2_ERR_TIMEOUT (PS2_ERROR | 0x0000001)
|
||||
#define PS2_ERR_PS2_PREFIX (PS2_ERROR | 0x0010000)
|
||||
|
||||
// --------------------------------------------------
|
||||
// Functions
|
||||
// --------------------------------------------------
|
||||
uint32_t PS2_get_num_if(void);
|
||||
uint32_t PS2_init(ps2_if_t *pIF);
|
||||
void PS2_byte_write(ps2_if_t *pIF, uint8_t byte);
|
||||
uint32_t PS2_byte_read(ps2_if_t *pIF, uint32_t timeout_ms);
|
||||
|
||||
int PS2_readchar(void const *pInst);
|
||||
void PS2_open(void const *pInst);
|
||||
void PS2_close(void const *pInst);
|
||||
|
||||
uint32_t PS2_cmd(ps2_if_t *pIF, uint8_t cmd, uint32_t ack_timeout_ms);
|
||||
void PS2_flush(ps2_if_t *pIF);
|
||||
|
||||
#endif // PS2_H
|
||||
Executable
+164
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <board.h>
|
||||
#include "screen.h"
|
||||
|
||||
const vga_if_t vga_if =
|
||||
{
|
||||
(uint32_t*)SYS_VGA_CTRL, (uint32_t*)SYS_VGA_ASCII, (uint32_t*)SYS_VGA_POSX, (uint32_t*)SYS_VGA_POSY
|
||||
};
|
||||
|
||||
void cg_open(void const *pInst)
|
||||
{
|
||||
assert (pInst);
|
||||
|
||||
vga_if_t *pIF = (vga_if_t*)pInst;
|
||||
cg_clr_screen(&vga_if);
|
||||
}
|
||||
|
||||
void cg_close(void const *pInst)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void cg_writechar(void const *pInst, char c)
|
||||
{
|
||||
assert (pInst);
|
||||
|
||||
vga_if_t *pIF = (vga_if_t*)pInst;
|
||||
uint32_t code;
|
||||
|
||||
// Output translation
|
||||
switch(c)
|
||||
{
|
||||
case 'Ä':
|
||||
code = 196;
|
||||
break;
|
||||
|
||||
case 'ä':
|
||||
code = 228;
|
||||
break;
|
||||
|
||||
case 'Ö':
|
||||
code = 214;
|
||||
break;
|
||||
|
||||
case 'ö':
|
||||
code = 246;
|
||||
break;
|
||||
|
||||
case 'Ü':
|
||||
code = 220;
|
||||
break;
|
||||
|
||||
case 'ü':
|
||||
code = 252;
|
||||
break;
|
||||
|
||||
case '&':
|
||||
code = 230;
|
||||
break;
|
||||
|
||||
case '§':
|
||||
code = 167;
|
||||
break;
|
||||
|
||||
case 'ß':
|
||||
code = 223;
|
||||
break;
|
||||
|
||||
case '°':
|
||||
code = 176;
|
||||
break;
|
||||
|
||||
case 'µ':
|
||||
code = 181;
|
||||
break;
|
||||
|
||||
default:
|
||||
code = (uint32_t)c;
|
||||
break;
|
||||
}
|
||||
|
||||
while (!(*pIF->pCTRL & SYS_VGA_BIT_CGRDY));
|
||||
*pIF->pDATA = code;
|
||||
|
||||
if (c == 0x0A)
|
||||
{
|
||||
cg_clr_line(pIF);
|
||||
while (!(*pIF->pCTRL & SYS_VGA_BIT_CGRDY));
|
||||
*pIF->pDATA = 0x0D;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void cg_set_csr_x(vga_if_t const *pIF, uint32_t coord)
|
||||
{
|
||||
assert (pIF);
|
||||
|
||||
// Set cursor
|
||||
while (!(*pIF->pCTRL & SYS_VGA_BIT_CGRDY));
|
||||
*pIF->pCSRX = coord;
|
||||
}
|
||||
|
||||
void cg_set_csr_y(vga_if_t const *pIF, uint32_t coord)
|
||||
{
|
||||
assert (pIF);
|
||||
|
||||
// Set cursor
|
||||
while (!(*pIF->pCTRL & SYS_VGA_BIT_CGRDY));
|
||||
*pIF->pCSRY = coord;
|
||||
}
|
||||
|
||||
void cg_clr_line(vga_if_t const *pIF)
|
||||
{
|
||||
assert (pIF);
|
||||
|
||||
while (!(*pIF->pCTRL & SYS_VGA_BIT_CGRDY));
|
||||
*pIF->pCTRL |= SYS_VGA_BIT_CLRLINE;
|
||||
}
|
||||
|
||||
void cg_clr_screen(vga_if_t const *pIF)
|
||||
{
|
||||
assert (pIF);
|
||||
|
||||
while (!(*pIF->pCTRL & SYS_VGA_BIT_CGRDY));
|
||||
*pIF->pCTRL |= SYS_VGA_BIT_CLRSCR;
|
||||
|
||||
// Cursor home
|
||||
while (!(*pIF->pCTRL & SYS_VGA_BIT_CGRDY));
|
||||
*pIF->pCSRX = 0;
|
||||
|
||||
while (!(*pIF->pCTRL & SYS_VGA_BIT_CGRDY));
|
||||
*pIF->pCSRY = 0;
|
||||
|
||||
}
|
||||
|
||||
uint32_t Screen_get_resx(void)
|
||||
{
|
||||
uint32_t volatile *pVGA_res = (uint32_t*)SYS_VGA_RES;
|
||||
|
||||
return (0xFFF & (*pVGA_res >> 0));
|
||||
}
|
||||
|
||||
uint32_t Screen_get_resy(void)
|
||||
{
|
||||
uint32_t volatile *pVGA_res = (uint32_t*)SYS_VGA_RES;
|
||||
|
||||
return (0xFFF & (*pVGA_res >> 12));
|
||||
}
|
||||
|
||||
uint32_t Screen_get_fps(void)
|
||||
{
|
||||
uint32_t volatile *pVGA_res = (uint32_t*)SYS_VGA_RES;
|
||||
|
||||
return (0xFF & (*pVGA_res >> 24));
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: screen.h
|
||||
* Author: jens
|
||||
*
|
||||
* Created on 8. Januar 2017, 14:22
|
||||
*/
|
||||
|
||||
#ifndef SCREEN_H
|
||||
#define SCREEN_H
|
||||
|
||||
typedef struct _svga_if_t
|
||||
{
|
||||
volatile uint32_t *pCTRL;
|
||||
volatile uint32_t *pDATA;
|
||||
volatile uint32_t *pCSRX;
|
||||
volatile uint32_t *pCSRY;
|
||||
} vga_if_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cg_set_csr_x(vga_if_t const *pIF, uint32_t coord);
|
||||
void cg_set_csr_y(vga_if_t const *pIF, uint32_t coord);
|
||||
void cg_clr_line(vga_if_t const *pIF);
|
||||
void cg_clr_screen(vga_if_t const *pIF);
|
||||
|
||||
uint32_t Screen_get_resx(void);
|
||||
uint32_t Screen_get_resy(void);
|
||||
uint32_t Screen_get_fps(void);
|
||||
|
||||
void cg_writechar(void const *pInst, char c);
|
||||
void cg_open(void const *pInst);
|
||||
void cg_close(void const *pInst);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SCREEN_H */
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#include <stdio.h>
|
||||
#include "libsys.h"
|
||||
#include "xcpt.h"
|
||||
|
||||
/* 10 digits + 1 sign + 1 trailing nul */
|
||||
static char itoa_buf[12];
|
||||
|
||||
char *itoa(int i)
|
||||
{
|
||||
char *pos = itoa_buf + sizeof(itoa_buf) - 1;
|
||||
unsigned int u;
|
||||
int negative = 0;
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
negative = 1;
|
||||
u = ((unsigned int)(-(1+i))) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
u = i;
|
||||
}
|
||||
|
||||
*pos = 0;
|
||||
|
||||
do
|
||||
{
|
||||
*--pos = '0' + (u % 10);
|
||||
u /= 10;
|
||||
} while (u);
|
||||
|
||||
if (negative)
|
||||
{
|
||||
*--pos = '-';
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
int syscalls_handler(struct xcptcontext * xcp)
|
||||
{
|
||||
int syscall_code;
|
||||
char *pStr, buf[33];
|
||||
|
||||
syscall_code = xcp->regs[2];
|
||||
|
||||
switch(syscall_code)
|
||||
{
|
||||
case 1: // print integer
|
||||
sputs(itoa(xcp->regs[4]));
|
||||
break;
|
||||
|
||||
case 4: // print string
|
||||
pStr = (char*)xcp->regs[4];
|
||||
sputs(pStr);
|
||||
break;
|
||||
|
||||
case 5: // read integer
|
||||
pStr = fgets(buf, sizeof(buf), stdin);
|
||||
xcp->regs[2] = atoi(pStr);
|
||||
break;
|
||||
|
||||
case 8: // read string
|
||||
pStr = (char*)xcp->regs[4];
|
||||
fgets(pStr, xcp->regs[5], stdin);
|
||||
break;
|
||||
|
||||
case 10: // exit
|
||||
_exit(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
sputs("\nUnknown syscall (");print_word(syscall_code);sputs(") at ");print_word(xcp->epc);sputs("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
xcp->epc += 4; // set return address to instruction after syscall
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void syscalls_init(void)
|
||||
{
|
||||
xcpt_register(EXC_SYSCALL, syscalls_handler);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef SYSCALLS_H
|
||||
#define SYSCALLS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void syscalls_init(void);
|
||||
|
||||
#endif // SYSCALLS_H
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
#include <board.h>
|
||||
#include "uart.h"
|
||||
|
||||
// ------------------------------------
|
||||
// Low-level I/O
|
||||
// ------------------------------------
|
||||
void UART_setbaud(void const *pInst, uint32_t baudrate)
|
||||
{
|
||||
if (pInst)
|
||||
{
|
||||
uart_if_t *pReg = (uart_if_t*)pInst;
|
||||
*pReg->pBAUD = UART_CALC_BAUD(baudrate);
|
||||
}
|
||||
}
|
||||
|
||||
int UART_readchar(void const *pInst)
|
||||
{
|
||||
if (pInst)
|
||||
{
|
||||
uart_if_t *pReg = (uart_if_t*)pInst;
|
||||
if (SYS_UART_BIT_RX_AVAIL & *pReg->pCTRL)
|
||||
{
|
||||
return (*pReg->pDATA & 0xFF);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void UART_writechar(void const *pInst, char c)
|
||||
{
|
||||
if (pInst)
|
||||
{
|
||||
uart_if_t *pReg = (uart_if_t*)pInst;
|
||||
while((SYS_UART_BIT_TX_HALFFULL & *pReg->pCTRL) != 0);
|
||||
*pReg->pDATA = (uint32_t)c;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: uart.h
|
||||
* Author: jens
|
||||
*
|
||||
* Created on 9. Januar 2017, 08:05
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef UART_H
|
||||
#define UART_H
|
||||
|
||||
#define UART_CALC_BAUD(b) \
|
||||
(((10*CPU_FREQ_HZ)/((16*b) + 5))/10 - 1)
|
||||
|
||||
typedef struct _suart_if_t
|
||||
{
|
||||
volatile uint32_t *pCTRL;
|
||||
volatile uint32_t *pDATA;
|
||||
volatile uint32_t *pBAUD;
|
||||
} uart_if_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int UART_readchar(void const *pInst);
|
||||
void UART_writechar(void const *pInst, char c);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* UART_H */
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
#include <sys/times.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include "libsys.h"
|
||||
#include "xcpt.h"
|
||||
#include "irq.h"
|
||||
|
||||
static fp_xcpt_t g_xcpt_handler[MAX_NUM_XCPT] = {NULL};
|
||||
|
||||
char const * const _xcpt_code_str[MAX_NUM_XCPT] =
|
||||
{
|
||||
"Interrupt", "Mod", "TLBL", "TLBS", "AdEL", "AdES", "IBE", "DBE",
|
||||
"Syscall", "Break", "RI", "CpU", "Ov", "Tr", "NCD/VCEI", "MC/FPE",
|
||||
"Res(16)", "Res(17)", "Res(18)", "Res(19)", "Res(20)", "Res(21)", "Res(22)", "WATCH",
|
||||
"Res(24)", "Res(25)", "Res(26)", "Res(27)", "Res(28)", "Res(29)", "Res(30)", "VCED"
|
||||
};
|
||||
|
||||
|
||||
void xcpt_register(int xcpt_num, fp_xcpt_t fp)
|
||||
{
|
||||
if ((xcpt_num >= EXC_INT) && (xcpt_num <= EXC_VCED))
|
||||
g_xcpt_handler[xcpt_num] = fp;
|
||||
|
||||
}
|
||||
void xcpt_registers_print(struct xcptcontext * xcp)
|
||||
{
|
||||
xcpt_registers_print_with_change(xcp, xcp);
|
||||
}
|
||||
|
||||
void xcpt_registers_print_with_change(struct xcptcontext * xcp, struct xcptcontext * xcp_last)
|
||||
{
|
||||
PRINT_REG_CHG(" Status : ", xcp->sr, xcp_last->sr);
|
||||
PRINT_REG_CHG(" Cause : ", xcp->cr, xcp_last->cr);
|
||||
PRINT_REG_CHG(" EPC : ", xcp->epc, xcp_last->epc);
|
||||
PRINT_REG_CHG("BadAddr : ", xcp->baddr, xcp_last->baddr);
|
||||
sputs("\n");
|
||||
PRINT_REG_CHG(" MDLO : ", xcp->mdlo, xcp_last->mdlo);
|
||||
PRINT_REG_CHG(" MDHI : ", xcp->mdhi, xcp_last->mdhi);
|
||||
|
||||
sputs("\n");
|
||||
|
||||
sputs("Registers:\n");
|
||||
PRINT_REG_CHG(" 0 (ze) : ", xcp->regs[0], xcp_last->regs[0]);
|
||||
PRINT_REG_CHG(" 1 (at) : ", xcp->regs[1], xcp_last->regs[1]);
|
||||
PRINT_REG_CHG(" 2 (v0) : ", xcp->regs[2], xcp_last->regs[2]);
|
||||
PRINT_REG_CHG(" 3 (v1) : ", xcp->regs[3], xcp_last->regs[3]);
|
||||
sputs("\n");
|
||||
PRINT_REG_CHG(" 4 (a0) : ", xcp->regs[4], xcp_last->regs[4]);
|
||||
PRINT_REG_CHG(" 5 (a1) : ", xcp->regs[5], xcp_last->regs[5]);
|
||||
PRINT_REG_CHG(" 6 (a2) : ", xcp->regs[6], xcp_last->regs[6]);
|
||||
PRINT_REG_CHG(" 7 (a3) : ", xcp->regs[7], xcp_last->regs[7]);
|
||||
sputs("\n");
|
||||
PRINT_REG_CHG(" 8 (t0) : ", xcp->regs[8], xcp_last->regs[8]);
|
||||
PRINT_REG_CHG(" 9 (t1) : ", xcp->regs[9], xcp_last->regs[9]);
|
||||
PRINT_REG_CHG("10 (t2) : ", xcp->regs[10], xcp_last->regs[10]);
|
||||
PRINT_REG_CHG("11 (t3) : ", xcp->regs[11], xcp_last->regs[11]);
|
||||
sputs("\n");
|
||||
PRINT_REG_CHG("12 (t4) : ", xcp->regs[12], xcp_last->regs[12]);
|
||||
PRINT_REG_CHG("13 (t5) : ", xcp->regs[13], xcp_last->regs[13]);
|
||||
PRINT_REG_CHG("14 (t6) : ", xcp->regs[14], xcp_last->regs[14]);
|
||||
PRINT_REG_CHG("15 (t7) : ", xcp->regs[15], xcp_last->regs[15]);
|
||||
sputs("\n");
|
||||
PRINT_REG_CHG("16 (s0) : ", xcp->regs[16], xcp_last->regs[16]);
|
||||
PRINT_REG_CHG("17 (s1) : ", xcp->regs[17], xcp_last->regs[17]);
|
||||
PRINT_REG_CHG("18 (s2) : ", xcp->regs[18], xcp_last->regs[18]);
|
||||
PRINT_REG_CHG("19 (s3) : ", xcp->regs[19], xcp_last->regs[19]);
|
||||
sputs("\n");
|
||||
PRINT_REG_CHG("20 (s4) : ", xcp->regs[20], xcp_last->regs[20]);
|
||||
PRINT_REG_CHG("21 (s5) : ", xcp->regs[21], xcp_last->regs[21]);
|
||||
PRINT_REG_CHG("22 (s6) : ", xcp->regs[22], xcp_last->regs[22]);
|
||||
PRINT_REG_CHG("23 (s7) : ", xcp->regs[23], xcp_last->regs[23]);
|
||||
sputs("\n");
|
||||
PRINT_REG_CHG("24 (t8) : ", xcp->regs[24], xcp_last->regs[24]);
|
||||
PRINT_REG_CHG("25 (t9) : ", xcp->regs[25], xcp_last->regs[25]);
|
||||
PRINT_REG_CHG("26 (k0) : ", xcp->regs[26], xcp_last->regs[26]);
|
||||
PRINT_REG_CHG("27 (k1) : ", xcp->regs[27], xcp_last->regs[27]);
|
||||
sputs("\n");
|
||||
PRINT_REG_CHG("28 (gp) : ", xcp->regs[28], xcp_last->regs[28]);
|
||||
PRINT_REG_CHG("29 (sp) : ", xcp->regs[29], xcp_last->regs[29]);
|
||||
PRINT_REG_CHG("30 (fp) : ", xcp->regs[30], xcp_last->regs[30]);
|
||||
PRINT_REG_CHG("31 (ra) : ", xcp->regs[31], xcp_last->regs[31]);
|
||||
sputs("\n");
|
||||
}
|
||||
|
||||
int xcpt_get_type(struct xcptcontext * xcp)
|
||||
{
|
||||
return (xcp->cr >> 2) & 0x1F;
|
||||
}
|
||||
|
||||
void xcpt_exctype_print(struct xcptcontext * xcp)
|
||||
{
|
||||
int exc_code;
|
||||
|
||||
exc_code = xcpt_get_type(xcp);
|
||||
sputs(_xcpt_code_str[exc_code]);
|
||||
|
||||
}
|
||||
|
||||
int _xcpt_dispatch(struct xcptcontext * xcp)
|
||||
{
|
||||
int result;
|
||||
int xcpt_code;
|
||||
|
||||
xcpt_code = (xcp->cr >> 2) & 0x1F;
|
||||
|
||||
result = XCPT_ERR_NOTHANDLED;
|
||||
if (g_xcpt_handler[xcpt_code])
|
||||
{
|
||||
result = (g_xcpt_handler[xcpt_code])(xcp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int _xcpt_deliver(struct xcptcontext * _xcp)
|
||||
{
|
||||
|
||||
int exc_code;
|
||||
volatile int *pInstr;
|
||||
|
||||
/* This function gets called by the low-level exception handler. */
|
||||
if (_xcpt_dispatch(_xcp) == XCPT_ERR_NOTHANDLED)
|
||||
{
|
||||
sputs("\n");
|
||||
xcpt_registers_print(_xcp);
|
||||
sputs("\n");
|
||||
|
||||
exc_code = (_xcp->cr >> 2) & 0x1F;
|
||||
|
||||
if (_xcp->cr & 0x80000000)
|
||||
{
|
||||
pInstr = (int*)(_xcp->epc + 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
pInstr = (int*)(_xcp->epc);
|
||||
}
|
||||
sputs("Unhandled exception <");xcpt_exctype_print(_xcp); sputs("> at PC : ");print_word((int)pInstr);sputs("\n");
|
||||
|
||||
sputs("Instruction at exception address : ");
|
||||
print_word(*pInstr);
|
||||
sputs("\n");
|
||||
|
||||
sputs("Terminate.\n");
|
||||
_exit(exc_code);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef XCPT_H
|
||||
#define XCPT_H
|
||||
|
||||
#define MAX_NUM_XCPT 32
|
||||
#define XCPT_ERR_NOTHANDLED 0x80000000
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EXC_INT = 0, EXC_MOD = 1, EXC_TLBL = 2, EXC_TLBS = 3, EXC_ADEL = 4, EXC_ADES = 5,
|
||||
EXC_IBE = 6, EXC_DBE = 7, EXC_SYSCALL = 8, EXC_BP = 9, EXC_RI = 10, EXC_CPU = 11,
|
||||
EXC_OV = 12, EXC_TRAP = 13, EXC_VCEI = 14, EXC_FPE = 15, EXC_C2E = 16, EXC_WATCH = 23, EXC_VCED = 31
|
||||
|
||||
} EXCEPTION_CODE;
|
||||
|
||||
typedef unsigned int reg_t;
|
||||
|
||||
typedef struct xcptcontext
|
||||
{
|
||||
/* This is the exception context frame that is passed to the exception
|
||||
handlers. It gets filled in by the low-level exception handler in
|
||||
"machine.S". An assembler version of this structure can be found at the
|
||||
bottom of "machine.H".*/
|
||||
reg_t sr; /* Status Register */
|
||||
reg_t cr; /* Cause Register */
|
||||
reg_t epc; /* PC at time of exception. */
|
||||
reg_t baddr;
|
||||
reg_t regs[32]; /* Copy of all general purpose registers */
|
||||
reg_t mdlo; /* HI/LO registers (used for memory management) */
|
||||
reg_t mdhi;
|
||||
reg_t count; /* Timer registers */
|
||||
reg_t compare;
|
||||
struct xcptcontext * prev; /* To link exceptions. (unused for now) */
|
||||
unsigned xclass; /* Priority class of this exception. (unused for now). */
|
||||
|
||||
} EXCEPTION_CONTEXT;
|
||||
|
||||
typedef int (*fp_xcpt_t)(struct xcptcontext * xcp);
|
||||
|
||||
#define PRINT_REG(tag_str, reg) \
|
||||
sputs(tag_str); \
|
||||
print_word(reg); \
|
||||
sputs(" ");
|
||||
|
||||
|
||||
#define PRINT_REG_CHG(tag_str, reg, reg_last) \
|
||||
sputs(tag_str); \
|
||||
print_word(reg); \
|
||||
sputs(reg != reg_last ? "*" : " "); \
|
||||
sputs(" ");
|
||||
|
||||
|
||||
// Public functions
|
||||
void xcpt_register(int xcpt_num, fp_xcpt_t fp);
|
||||
int xcpt_get_type(struct xcptcontext * xcp);
|
||||
void xcpt_registers_print(struct xcptcontext * xcp);
|
||||
void xcpt_registers_print_with_change(struct xcptcontext * xcp, struct xcptcontext * xcp_last);
|
||||
void xcpt_exctype_print(struct xcptcontext * xcp);
|
||||
|
||||
#endif // XCPT_H
|
||||
Reference in New Issue
Block a user