2 Commits

Author SHA1 Message Date
Serge Vakulenko
b0705e54ab Virtualmips modified to allow access to SRSCtl register.
When only one GPR set supported, opcodes RDPGPR and WRPGPR
behave like MOVE instruction.
2014-05-15 10:48:33 -07:00
Serge Vakulenko
459e3f09ea Kernel startup code modified to support MZ processor.
Based on official MIPS application note
"Boot-CPS: Example Boot Code for MIPS® Cores".
2014-05-14 21:22:48 -07:00
4 changed files with 552 additions and 279 deletions

View File

@@ -1,8 +1,9 @@
#
# Startup code for Microchip PIC32 microcontrollers.
# Using HID bootloader.
# Based on the MIPS application note:
# "Boot-CPS: Example Boot Code for MIPS® Cores".
#
# Copyright (C) 2010 Serge Vakulenko, <serge@vak.ru>
# Copyright (C) 2010-2014 Serge Vakulenko, <serge@vak.ru>
#
# Permission to use, copy, modify, and distribute this software
# and its documentation for any purpose and without fee is hereby
@@ -26,6 +27,43 @@
#define UBASE 0x7f008000 /* User space base address */
/*
* MIPS Coprocessor 0 register numbers
*/
#define C0_INDEX $0
#define C0_ENTRYLO0 $2
#define C0_ENTRYLO1 $3
#define C0_PAGEMASK $5
#define C0_WIRED $6
#define C0_COUNT $9
#define C0_ENTRYHI $10
#define C0_COMPARE $11
#define C0_STATUS $12
#define C0_SRSCTL $12,2
#define C0_CAUSE $13
#define C0_EPC $14
#define C0_CONFIG $16
#define C0_CONFIG1 $16,1
#define C0_CONFIG7 $16,7
#define C0_WATCHLO $18
#define C0_WATCHHI $19
#define C0_DEBUG $23
#define C0_DEPC $24
#define C0_ITAGLO $28
#define C0_DTAGLO $28,2
#define C0_ERRPC $30
/*
* MIPS Config1 register
*/
#define CFG1_MMUSSHIFT 25 // mmu size - 1
#define CFG1_ISSHIFT 22 // icache lines 64<<n
#define CFG1_ILSHIFT 19 // icache line size 2<<n
#define CFG1_IASHIFT 16 // icache ways - 1
#define CFG1_DSSHIFT 13 // dcache lines 64<<n
#define CFG1_DLSHIFT 10 // dcache line size 2<<n
#define CFG1_DASHIFT 7 // dcache ways - 1
.set noreorder
.set mips32r2
.set nomips16
@@ -45,52 +83,279 @@
_reset_vector_: .globl _reset_vector_
.set noat
move $1, $zero # Clear all regs
move $2, $zero
move $3, $zero
move $4, $zero
move $5, $zero
move $6, $zero
move $7, $zero
move $8, $zero
move $9, $zero
move $10, $zero
move $11, $zero
move $12, $zero
move $13, $zero
move $14, $zero
move $15, $zero
move $16, $zero
move $17, $zero
move $18, $zero
move $19, $zero
move $20, $zero
move $21, $zero
move $22, $zero
move $23, $zero
move $24, $zero
move $25, $zero
move $26, $zero
move $27, $zero
move $28, $zero
move $29, $zero
move $30, $zero
move $31, $zero
mtlo $zero
mthi $zero
.set at
mtc0 $0, C0_COUNT # Clear cp0 Count (Used to measure boot time.)
#if 0
//
// Check for NMI exception.
//
check_nmi: # Check whether we are here due to a reset or NMI.
mfc0 $s1, C0_STATUS # Read Status
ext $s1, $s1, 19, 1 # extract NMI
beqz $s1, init_gpr # Branch if this is NOT an NMI exception.
nop
# Call nmi_exception().
la $sp, _stack-16 # Set up stack base.
la $gp, _gp # GP register value defined by linker script.
la $s1, nmi_exception # Call user-defined NMI handler.
jalr $s1
nop
#endif
//
// Set all GPRs of all register sets to predefined state.
//
init_gpr:
li $1, 0xdeadbeef # 0xdeadbeef stands out, kseg2 mapped, odd.
# Determine how many shadow sets are implemented (in addition to the base register set.)
# the first time thru the loop it will initialize using $1 set above.
# At the bottom og the loop, 1 is subtract from $30
# and loop back to next_shadow_set to start the next loop and the next lowest set number.
mfc0 $29, C0_SRSCTL # read SRSCtl
ext $30, $29, 26, 4 # extract HSS
next_shadow_set: # set PSS to shadow set to be initialized
ins $29, $30, 6, 4 # insert PSS
mtc0 $29, C0_SRSCTL # write SRSCtl
wrpgpr $1, $1
wrpgpr $2, $1
wrpgpr $3, $1
wrpgpr $4, $1
wrpgpr $5, $1
wrpgpr $6, $1
wrpgpr $7, $1
wrpgpr $8, $1
wrpgpr $9, $1
wrpgpr $10, $1
wrpgpr $11, $1
wrpgpr $12, $1
wrpgpr $13, $1
wrpgpr $14, $1
wrpgpr $15, $1
wrpgpr $16, $1
wrpgpr $17, $1
wrpgpr $18, $1
wrpgpr $19, $1
wrpgpr $20, $1
wrpgpr $21, $1
wrpgpr $22, $1
wrpgpr $23, $1
wrpgpr $24, $1
wrpgpr $25, $1
wrpgpr $26, $1
wrpgpr $27, $1
wrpgpr $28, $1
beqz $30, init_cp0
wrpgpr $29, $1
wrpgpr $30, $1
wrpgpr $31, $1
b next_shadow_set
add $30, -1 # Decrement to the next lower number
//
// Init CP0 Status, Count, Compare, Watch*, and Cause.
//
init_cp0:
# Initialize Status
li $v1, 0x00400404 # (M_StatusIM | M_StatusERL | M_StatusBEV)
mtc0 $v1, C0_STATUS # write Status
# Initialize Watch registers if implemented.
mfc0 $v0, C0_CONFIG1 # read Config1
ext $v1, $v0, 3, 1 # extract bit 3 WR (Watch registers implemented)
beq $v1, $zero, done_wr
li $v1, 0x7 # (M_WatchHiI | M_WatchHiR | M_WatchHiW)
# Clear Watch Status bits and disable watch exceptions
mtc0 $v1, C0_WATCHHI # write WatchHi0
mfc0 $v0, C0_WATCHHI # read WatchHi0
bgez $v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 $zero, C0_WATCHLO # clear WatchLo0
mtc0 $v1, C0_WATCHHI, 1 # write WatchHi1
mfc0 $v0, C0_WATCHHI, 1 # read WatchHi1
bgez $v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 $zero, C0_WATCHLO, 1 # clear WatchLo1
mtc0 $v1, C0_WATCHHI, 2 # write WatchHi2
mfc0 $v0, C0_WATCHHI, 2 # read WatchHi2
bgez $v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 $zero, C0_WATCHLO, 2 # clear WatchLo2
mtc0 $v1, C0_WATCHHI, 3 # write WatchHi3
mfc0 $v0, C0_WATCHHI, 3 # read WatchHi3
bgez $v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 $zero, C0_WATCHLO, 3 # clear WatchLo3
mtc0 $v1, C0_WATCHHI, 4 # write WatchHi4
mfc0 $v0, C0_WATCHHI, 4 # read WatchHi4
bgez $v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 $zero, C0_WATCHLO, 4 # clear WatchLo4
mtc0 $v1, C0_WATCHHI, 5 # write WatchHi5
mfc0 $v0, C0_WATCHHI, 5 # read WatchHi5
bgez $v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 $zero, C0_WATCHLO, 5 # clear WatchLo5
mtc0 $v1, C0_WATCHHI, 6 # write WatchHi6
mfc0 $v0, C0_WATCHHI, 6 # read WatchHi6
bgez $v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 $zero, C0_WATCHLO, 6 # clear WatchLo6
mtc0 $v1, C0_WATCHHI, 7 # write WatchHi7
mtc0 $zero, C0_WATCHLO, 7 # clear WatchLo7
done_wr:
# Clear WP bit to avoid watch exception upon user code entry, IV, and software interrupts.
mtc0 $zero, C0_CAUSE # clear Cause: init AFTER init of WatchHi/Lo registers.
# Clear timer interrupt. (Count was cleared at the reset vector to allow timing boot.)
b init_tlb # Jump over exception vectors
mtc0 $zero, C0_COMPARE # clear Compare
//
// Clear TLB: generate unique EntryHi contents per entry pair.
//
init_tlb:
# Determine if we have a TLB
mfc0 $v1, C0_CONFIG # read Config
ext $v1, $v1, 7, 3 # extract MT field
li $a3, 0x1 # load a 1 to check against
bne $v1, $a3, init_icache
# Config1MMUSize == Number of TLB entries - 1
mfc0 $v0, C0_CONFIG1 # Config1
ext $v1, $v0, CFG1_MMUSSHIFT, 6 # extract MMU Size
mtc0 $zero, C0_ENTRYLO0 # clear EntryLo0
mtc0 $zero, C0_ENTRYLO1 # clear EntryLo1
mtc0 $zero, C0_PAGEMASK # clear PageMask
mtc0 $zero, C0_WIRED # clear Wired
li $a0, 0x80000000
next_tlb_entry:
mtc0 $v1, C0_INDEX # write Index
mtc0 $a0, C0_ENTRYHI # write EntryHi
ehb
tlbwi
add $a0, 2<<13 # Add 8K to the address to avoid TLB conflict with previous entry
bne $v1, $zero, next_tlb_entry
add $v1, -1
//
// Clear L1 instruction cache.
//
init_icache:
# Determine how big the I-cache is
mfc0 $v0, C0_CONFIG1 # read Config1
ext $v1, $v0, CFG1_ILSHIFT, 3 # extract I-cache line size
beq $v1, $zero, done_icache # Skip ahead if no I-cache
nop
mfc0 $s1, C0_CONFIG7 # Read Config7
ext $s1, $s1, 18, 1 # extract HCI
bnez $s1, done_icache # Skip when Hardware Cache Initialization bit set
li $a2, 2
sllv $v1, $a2, $v1 # Now have true I-cache line size in bytes
ext $a0, $v0, CFG1_ISSHIFT, 3 # extract IS
li $a2, 64
sllv $a0, $a2, $a0 # I-cache sets per way
ext $a1, $v0, CFG1_IASHIFT, 3 # extract I-cache Assoc - 1
add $a1, 1
mul $a0, $a0, $a1 # Total number of sets
lui $a2, 0x8000 # Get a KSeg0 address for cacheops
mtc0 $zero, C0_ITAGLO # Clear ITagLo register
move $a3, $a0
next_icache_tag:
# Index Store Tag Cache Op
# Will invalidate the tag entry, clear the lock bit, and clear the LRF bit
cache 0x8, 0($a2) # ICIndexStTag
add $a3, -1 # Decrement set counter
bne $a3, $zero, next_icache_tag
add $a2, $v1 # Get next line address
done_icache:
//
// Enable cacheability of kseg0 segment.
// Need to switch to kseg1, modify kseg0 CCA, then switch back.
//
la $a2, enable_k0_cache
li $a1, 0xf
ins $a2, $a1, 29, 1 # changed to KSEG1 address by setting bit 29
jr $a2
nop
enable_k0_cache:
# Set CCA for kseg0 to cacheable.
# NOTE! This code must be executed in KSEG1 (not KSEG0 uncached)
mfc0 $v0, C0_CONFIG # read C0_Config
li $v1, 3 # CCA for single-core processors
ins $v0, $v1, 0, 3 # instert K0
mtc0 $v0, C0_CONFIG # write C0_Config
la $a2, init_dcache
jr $a2 # switch back to KSEG0
ehb
//
// Initialize the L1 data cache
//
init_dcache:
mfc0 $v0, C0_CONFIG1 # read C0_Config1
ext $v1, $v0, CFG1_DLSHIFT, 3 # extract D-cache line size
beq $v1, $zero, done_dcache # Skip ahead if no D-cache
nop
mfc0 $s1, C0_CONFIG7 # Read Config7
ext $s1, $s1, 18, 1 # extract HCI
bnez $s1, done_dcache # Skip when Hardware Cache Initialization bit set
li $a2, 2
sllv $v1, $a2, $v1 # Now have true D-cache line size in bytes
ext $a0, $v0, CFG1_DSSHIFT, 3 # extract DS
li $a2, 64
sllv $a0, $a2, $a0 # D-cache sets per way
ext $a1, $v0, CFG1_DASHIFT, 3 # extract D-cache Assoc - 1
add $a1, 1
mul $a0, $a0, $a1 # Get total number of sets
lui $a2, 0x8000 # Get a KSeg0 address for cacheops
mtc0 $zero, C0_ITAGLO # Clear ITagLo/DTagLo registers
mtc0 $zero, C0_DTAGLO
move $a3, $a0
next_dcache_tag:
# Index Store Tag Cache Op
# Will invalidate the tag entry, clear the lock bit, and clear the LRF bit
cache 0x9, 0($a2) # DCIndexStTag
add $a3, -1 # Decrement set counter
bne $a3, $zero, next_dcache_tag
add $a2, $v1 # Get next line address
done_dcache:
//
// Call main() function.
//
la $sp, u_end - 16 # Stack at end of U area
la $a0, main
jalr $a0 # Jump to main()
lui $gp, 0x8000 # Set global pointer (delay slot)
la $k0, UBASE
mtc0 $k0, $C0_EPC # Entry to user code.
mtc0 $k0, C0_EPC # Entry to user code.
mfc0 $k0, $C0_STATUS
mfc0 $k0, C0_STATUS
ori $k0, $k0, ST_UM | ST_EXL | ST_IE # Set user mode and enable interrupts
mtc0 $k0, $C0_STATUS # Put SR back
mtc0 $k0, C0_STATUS # Put SR back
ehb
eret # PC <= EPC; EXL <= 0
nop # just to be safe
@@ -116,7 +381,7 @@ _entry_vector_: .globl _entry_vector_
.type _exception_vector_, @function
_exception_vector_: .globl _exception_vector_
mfc0 $k0, $C0_STATUS
mfc0 $k0, C0_STATUS
andi $k1, $k0, ST_UM # Check user mode
beqz $k1, kernel_exception
move $k1, $sp
@@ -172,7 +437,7 @@ save_regs:
mflo $k0
sw $k0, (16+FRAME_LO*4) ($sp)
mfc0 $k0, $C0_EPC
mfc0 $k0, C0_EPC
sw $k0, (16+FRAME_PC*4) ($sp)
move $a0, $sp
@@ -225,11 +490,11 @@ restore_regs:
# Do not use k0/k1 here, as interrupts are still enabled
lw $31, (16+FRAME_STATUS*4) ($sp) # K0 = saved status
ori $31, ST_EXL # Set EXL
mtc0 $31, $C0_STATUS # put SR back: disable interrupts
mtc0 $31, C0_STATUS # put SR back: disable interrupts
ehb
lw $k0, (16+FRAME_PC*4) ($sp) # K0 = EPC
mtc0 $k0, $C0_EPC # put PC in EPC
mtc0 $k0, C0_EPC # put PC in EPC
ext $k1, $31, 27, 1 # get RP bit: single-step request
lw $31, (16+FRAME_RA*4) ($sp)
@@ -249,39 +514,39 @@ debug_request:
.type _debug_vector_, @function
_debug_vector_: .globl _debug_vector_
mfc0 $k0, $C0_DEPC
mfc0 $k0, C0_DEPC
la $k1, debug_request
bne $k0, $k1, single_step_done
nop
# single step request
mfc0 $k0, $C0_DEBUG
mfc0 $k0, C0_DEBUG
ori $k0, DB_SST # set SST bit
mtc0 $k0, $C0_DEBUG
mtc0 $k0, C0_DEBUG
mfc0 $k1, $C0_EPC
mtc0 $k1, $C0_DEPC # DEPC <= EPC
mfc0 $k0, $C0_STATUS
mfc0 $k1, C0_EPC
mtc0 $k1, C0_DEPC # DEPC <= EPC
mfc0 $k0, C0_STATUS
xori $k0, ST_EXL # Clear EXL
mtc0 $k0, $C0_STATUS
mtc0 $k0, C0_STATUS
ehb
deret # PC <= DEPC; DM <= 0
single_step_done:
mtc0 $k0, $C0_EPC # EPC <= DEPC
mtc0 $k0, C0_EPC # EPC <= DEPC
la $k1, _exception_vector_
mtc0 $k1, $C0_DEPC # DEPC <= exception handler
mtc0 $k1, C0_DEPC # DEPC <= exception handler
mfc0 $k0, $C0_DEBUG
mfc0 $k0, C0_DEBUG
sw $k0, c0_debug # save Debug register
ori $k0, DB_SST
xori $k0, DB_SST # clear SST bit
mtc0 $k0, $C0_DEBUG
mtc0 $k0, C0_DEBUG
mfc0 $k1, $C0_STATUS
mfc0 $k1, C0_STATUS
ori $k1, ST_EXL # Set EXL
mtc0 $k1, $C0_STATUS
mtc0 $k1, C0_STATUS
ehb
deret # PC <= DEPC; DM <= 0

View File

@@ -27,6 +27,7 @@
/*--------------------------------------
* Coprocessor 0 registers.
*/
#ifndef __ASSEMBLER__
#define C0_HWRENA 7 /* Enable RDHWR in non-privileged mode */
#define C0_BADVADDR 8 /* Virtual address of last exception */
#define C0_COUNT 9 /* Processor cycle count */
@@ -47,6 +48,7 @@
#define C0_DEPC 24 /* Program counter at last debug exception */
#define C0_ERROREPC 30 /* Program counter at last error */
#define C0_DESAVE 31 /* Debug handler scratchpad register */
#endif
/*
* Status register.

View File

@@ -1684,7 +1684,8 @@ static int rdpgpr_op (cpu_mips_t * cpu, mips_insn_t insn)
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
printf ("%08x: unsupported RDPGPR $%u,$%u instruction.\n", cpu->pc, rd, rt);
/* Only one GPR set supported: RDPGPR works as move. */
cpu->reg_set (cpu, rd, cpu->gpr[rt]);
return (0);
}
@@ -1693,7 +1694,8 @@ static int wrpgpr_op (cpu_mips_t * cpu, mips_insn_t insn)
int rt = bits (insn, 16, 20);
int rd = bits (insn, 11, 15);
printf ("%08x: unsupported WRPGPR $%u,$%u instruction.\n", cpu->pc, rd, rt);
/* Only one GPR set supported: WRPGPR works as move. */
cpu->reg_set (cpu, rd, cpu->gpr[rt]);
return (0);
}

View File

@@ -93,6 +93,8 @@ unimpl: fprintf (stderr,
return cp0->reg[cp0_reg];
case 1: /* IntCtl */
return cp0->intctl_reg;
case 2: /* SRSCtl */
return 0;
}
goto unimpl;
@@ -172,6 +174,8 @@ void mips_cp0_set_reg (cpu_mips_t * cpu, u_int cp0_reg, u_int sel,
case 1: /* IntCtl */
cp0->intctl_reg = val;
break;
case 2: /* SRSCtl */
break;
default:
goto unimpl;
}