forked from cores/microwatt
				
			Merge remote-tracking branch 'remotes/origin/master'
						commit
						102b304db7
					
				
											
												Binary file not shown.
											
										
									
								@ -0,0 +1,3 @@
 | 
			
		||||
Test 0:PASS
 | 
			
		||||
Test 1:PASS
 | 
			
		||||
Test 2:PASS
 | 
			
		||||
@ -0,0 +1,5 @@
 | 
			
		||||
TEST=xics
 | 
			
		||||
 | 
			
		||||
include ../Makefile.test
 | 
			
		||||
 | 
			
		||||
xics.o : xics.h
 | 
			
		||||
@ -0,0 +1,186 @@
 | 
			
		||||
/* Copyright 2013-2014 IBM Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * 	http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
 * implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define STACK_TOP 0x4000
 | 
			
		||||
 | 
			
		||||
/* Load an immediate 64-bit value into a register */
 | 
			
		||||
#define LOAD_IMM64(r, e)			\
 | 
			
		||||
	lis     r,(e)@highest;			\
 | 
			
		||||
	ori     r,r,(e)@higher;			\
 | 
			
		||||
	rldicr  r,r, 32, 31;			\
 | 
			
		||||
	oris    r,r, (e)@h;			\
 | 
			
		||||
	ori     r,r, (e)@l;
 | 
			
		||||
 | 
			
		||||
	.section ".head","ax"
 | 
			
		||||
 | 
			
		||||
	/* Microwatt currently enters in LE mode at 0x0 */
 | 
			
		||||
	. = 0
 | 
			
		||||
.global _start
 | 
			
		||||
_start:
 | 
			
		||||
	LOAD_IMM64(%r12, 0x000000000ffffff)
 | 
			
		||||
	mtdec	%r12
 | 
			
		||||
	LOAD_IMM64(%r12, 0x9000000000008003)
 | 
			
		||||
	mtmsrd	%r12	// EE on
 | 
			
		||||
	/* setup stack */
 | 
			
		||||
	LOAD_IMM64(%r1, STACK_TOP - 0x100)
 | 
			
		||||
	LOAD_IMM64(%r12, main)
 | 
			
		||||
	mtctr	%r12
 | 
			
		||||
	bctrl
 | 
			
		||||
	attn // terminate on exit
 | 
			
		||||
	b .
 | 
			
		||||
 | 
			
		||||
#define EXCEPTION(nr)		\
 | 
			
		||||
	.= nr			;\
 | 
			
		||||
	b	.
 | 
			
		||||
 | 
			
		||||
	/* More exception stubs */
 | 
			
		||||
	EXCEPTION(0x300)
 | 
			
		||||
	EXCEPTION(0x380)
 | 
			
		||||
	EXCEPTION(0x400)
 | 
			
		||||
	EXCEPTION(0x480)
 | 
			
		||||
	. = 0x500
 | 
			
		||||
	b	__isr
 | 
			
		||||
 | 
			
		||||
	EXCEPTION(0x600)
 | 
			
		||||
	EXCEPTION(0x700)
 | 
			
		||||
	EXCEPTION(0x800)
 | 
			
		||||
	EXCEPTION(0x900)
 | 
			
		||||
	EXCEPTION(0x980)
 | 
			
		||||
	EXCEPTION(0xa00)
 | 
			
		||||
	EXCEPTION(0xb00)
 | 
			
		||||
	EXCEPTION(0xc00)
 | 
			
		||||
	EXCEPTION(0xd00)
 | 
			
		||||
 | 
			
		||||
//  ISR data
 | 
			
		||||
 | 
			
		||||
#define REDZONE_SIZE    (512)
 | 
			
		||||
#define REG_SAVE_SIZE	((32 + 5)*8)
 | 
			
		||||
#define STACK_FRAME_C_MINIMAL   64
 | 
			
		||||
 | 
			
		||||
#define SAVE_NIA	(32*8)
 | 
			
		||||
#define SAVE_LR		(33*8)
 | 
			
		||||
#define SAVE_CTR	(34*8)
 | 
			
		||||
#define SAVE_CR		(35*8)
 | 
			
		||||
#define SAVE_SRR1	(36*8)
 | 
			
		||||
 | 
			
		||||
__isr:
 | 
			
		||||
/*
 | 
			
		||||
 * Assume where we are coming from has a stack and can save there.
 | 
			
		||||
 * We save the full register set. Since we are calling out to C, we
 | 
			
		||||
 * could just save the ABI volatile registers
 | 
			
		||||
 */
 | 
			
		||||
	stdu	%r1,-(REG_SAVE_SIZE+REDZONE_SIZE)(%r1)
 | 
			
		||||
	std	%r0,   1*8(%r1)
 | 
			
		||||
//	std	%r1,   1*8(%r1)
 | 
			
		||||
	std	%r2,   2*8(%r1)
 | 
			
		||||
	std	%r3,   3*8(%r1)
 | 
			
		||||
	std	%r4,   4*8(%r1)
 | 
			
		||||
	std	%r5,   5*8(%r1)
 | 
			
		||||
	std	%r6,   6*8(%r1)
 | 
			
		||||
	std	%r7,   7*8(%r1)
 | 
			
		||||
	std	%r8,   8*8(%r1)
 | 
			
		||||
	std	%r9,   9*8(%r1)
 | 
			
		||||
	std	%r10, 10*8(%r1)
 | 
			
		||||
	std	%r11, 11*8(%r1)
 | 
			
		||||
	std	%r12, 12*8(%r1)
 | 
			
		||||
	std	%r13, 13*8(%r1)
 | 
			
		||||
	std	%r14, 14*8(%r1)
 | 
			
		||||
	std	%r15, 15*8(%r1)
 | 
			
		||||
	std	%r16, 16*8(%r1)
 | 
			
		||||
	std	%r17, 17*8(%r1)
 | 
			
		||||
	std	%r18, 18*8(%r1)
 | 
			
		||||
	std	%r19, 19*8(%r1)
 | 
			
		||||
	std	%r20, 20*8(%r1)
 | 
			
		||||
	std	%r21, 21*8(%r1)
 | 
			
		||||
	std	%r22, 22*8(%r1)
 | 
			
		||||
	std	%r23, 23*8(%r1)
 | 
			
		||||
	std	%r24, 24*8(%r1)
 | 
			
		||||
	std	%r25, 25*8(%r1)
 | 
			
		||||
	std	%r26, 26*8(%r1)
 | 
			
		||||
	std	%r27, 27*8(%r1)
 | 
			
		||||
	std	%r28, 28*8(%r1)
 | 
			
		||||
	std	%r29, 29*8(%r1)
 | 
			
		||||
	std	%r30, 30*8(%r1)
 | 
			
		||||
	std	%r31, 31*8(%r1)
 | 
			
		||||
	mfsrr0	%r0
 | 
			
		||||
	std	%r0,  SAVE_NIA*8(%r1)
 | 
			
		||||
	mflr	%r0
 | 
			
		||||
	std	%r0,  SAVE_LR*8(%r1)
 | 
			
		||||
	mfctr	%r0
 | 
			
		||||
	std	%r0,  SAVE_CTR*8(%r1)
 | 
			
		||||
	mfcr	%r0
 | 
			
		||||
	std	%r0,  SAVE_CR*8(%r1)
 | 
			
		||||
	mfsrr1	%r0
 | 
			
		||||
	std	%r0,  SAVE_SRR1*8(%r1)
 | 
			
		||||
 | 
			
		||||
	stdu	%r1,-STACK_FRAME_C_MINIMAL(%r1)
 | 
			
		||||
	LOAD_IMM64(%r3, isr)
 | 
			
		||||
	mtctr	%r3,
 | 
			
		||||
	bctrl
 | 
			
		||||
	nop
 | 
			
		||||
	ld	%r1, 0(%r1)
 | 
			
		||||
 | 
			
		||||
	ld	%r0,   1*8(%r1)
 | 
			
		||||
//	ld	%r1,   1*8(%r1) // do this at rfid
 | 
			
		||||
	ld	%r2,   2*8(%r1)
 | 
			
		||||
//	ld	%r3,   3*8(%r1) // do this at rfid
 | 
			
		||||
	ld	%r4,   4*8(%r1)
 | 
			
		||||
	ld	%r5,   5*8(%r1)
 | 
			
		||||
	ld	%r6,   6*8(%r1)
 | 
			
		||||
	ld	%r7,   7*8(%r1)
 | 
			
		||||
	ld	%r8,   8*8(%r1)
 | 
			
		||||
	ld	%r9,   9*8(%r1)
 | 
			
		||||
	ld	%r10, 10*8(%r1)
 | 
			
		||||
	ld	%r11, 11*8(%r1)
 | 
			
		||||
	ld	%r12, 12*8(%r1)
 | 
			
		||||
	ld	%r13, 13*8(%r1)
 | 
			
		||||
	ld	%r14, 14*8(%r1)
 | 
			
		||||
	ld	%r15, 15*8(%r1)
 | 
			
		||||
	ld	%r16, 16*8(%r1)
 | 
			
		||||
	ld	%r17, 17*8(%r1)
 | 
			
		||||
	ld	%r18, 18*8(%r1)
 | 
			
		||||
	ld	%r19, 19*8(%r1)
 | 
			
		||||
	ld	%r20, 20*8(%r1)
 | 
			
		||||
	ld	%r21, 21*8(%r1)
 | 
			
		||||
	ld	%r22, 22*8(%r1)
 | 
			
		||||
	ld	%r23, 23*8(%r1)
 | 
			
		||||
	ld	%r24, 24*8(%r1)
 | 
			
		||||
	ld	%r25, 25*8(%r1)
 | 
			
		||||
	ld	%r26, 26*8(%r1)
 | 
			
		||||
	ld	%r27, 27*8(%r1)
 | 
			
		||||
	ld	%r28, 28*8(%r1)
 | 
			
		||||
	ld	%r29, 29*8(%r1)
 | 
			
		||||
	ld	%r30, 30*8(%r1)
 | 
			
		||||
	ld	%r31, 31*8(%r1)
 | 
			
		||||
 | 
			
		||||
	ld	%r3, SAVE_LR*8(%r1)
 | 
			
		||||
	mtlr	%r3
 | 
			
		||||
	ld	%r3, SAVE_CTR*8(%r1)
 | 
			
		||||
	mtctr	%r3
 | 
			
		||||
	ld	%r3, SAVE_CR*8(%r1)
 | 
			
		||||
	mtcr	%r3
 | 
			
		||||
	ld	%r3, SAVE_SRR1*8(%r1)
 | 
			
		||||
	mtsrr1	%r3
 | 
			
		||||
	ld	%r3, SAVE_NIA*8(%r1)
 | 
			
		||||
	mtsrr0	%r3
 | 
			
		||||
 | 
			
		||||
	/* restore %r3 */
 | 
			
		||||
	ld	%r3, 3*8(%r1)
 | 
			
		||||
 | 
			
		||||
	/* do final fixup r1 */
 | 
			
		||||
	ld	%r1, 0*8(%r1)
 | 
			
		||||
 | 
			
		||||
	rfid
 | 
			
		||||
@ -0,0 +1,13 @@
 | 
			
		||||
SECTIONS
 | 
			
		||||
{
 | 
			
		||||
	_start = .;
 | 
			
		||||
	. = 0;
 | 
			
		||||
	.head : {
 | 
			
		||||
		KEEP(*(.head))
 | 
			
		||||
	}
 | 
			
		||||
	. = 0x1000;
 | 
			
		||||
	.text : { *(.text) }
 | 
			
		||||
	. = 0x3000;
 | 
			
		||||
	.data : { *(.data) }
 | 
			
		||||
	.bss : { *(.bss) }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,262 @@
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
#include "console.h"
 | 
			
		||||
#include "xics.h"
 | 
			
		||||
 | 
			
		||||
#undef DEBUG
 | 
			
		||||
//#define DEBUG 1
 | 
			
		||||
 | 
			
		||||
void print_number(unsigned int i) // only for i = 0-999
 | 
			
		||||
{
 | 
			
		||||
	unsigned int j, k, m;
 | 
			
		||||
	bool zeros = false;
 | 
			
		||||
 | 
			
		||||
	k = 1000000000;
 | 
			
		||||
 | 
			
		||||
	for (m = 0; m < 10 ; m++) {
 | 
			
		||||
		j = i/k;
 | 
			
		||||
		if (m == 9) zeros = true;
 | 
			
		||||
		if (zeros || (j != 0)) {
 | 
			
		||||
		    putchar(48 + j);
 | 
			
		||||
		    zeros = true;
 | 
			
		||||
		}
 | 
			
		||||
		i = i % k;
 | 
			
		||||
		k = k / 10;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
#define DEBUG_STR "\r\nDEBUG: "
 | 
			
		||||
void debug_print(int i)
 | 
			
		||||
{
 | 
			
		||||
	putstr(DEBUG_STR, strlen(DEBUG_STR));
 | 
			
		||||
	print_number(i);
 | 
			
		||||
	putstr("\r\n", 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define debug_putstr(a, b) putstr(a,b)
 | 
			
		||||
#else
 | 
			
		||||
#define debug_putstr(a, b)
 | 
			
		||||
#define debug_print(i)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define ASSERT_FAIL "() ASSERT_FAILURE!\r\n "
 | 
			
		||||
#define assert(cond)	\
 | 
			
		||||
	if (!(cond))  { \
 | 
			
		||||
		putstr(__FILE__, strlen(__FILE__)); \
 | 
			
		||||
		putstr(":", 1);	    \
 | 
			
		||||
		print_number(__LINE__);	\
 | 
			
		||||
		putstr(":", 1);	    \
 | 
			
		||||
		putstr(__FUNCTION__, strlen(__FUNCTION__));\
 | 
			
		||||
		putstr(ASSERT_FAIL, strlen(ASSERT_FAIL)); \
 | 
			
		||||
		__asm__ ("attn"); \
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
volatile uint64_t isrs_run;
 | 
			
		||||
 | 
			
		||||
#define ISR_IPI      0x0000000000000001
 | 
			
		||||
#define ISR_UART     0x0000000000000002
 | 
			
		||||
#define ISR_SPURIOUS 0x0000000000000004
 | 
			
		||||
 | 
			
		||||
#define IPI "IPI\r\n"
 | 
			
		||||
void ipi_isr(void) {
 | 
			
		||||
	debug_putstr(IPI, strlen(IPI));
 | 
			
		||||
 | 
			
		||||
	isrs_run |= ISR_IPI;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define UART "UART\r\n"
 | 
			
		||||
void uart_isr(void) {
 | 
			
		||||
	debug_putstr(UART, strlen(UART));
 | 
			
		||||
 | 
			
		||||
	potato_uart_irq_dis(); // disable interrupt to ack it
 | 
			
		||||
 | 
			
		||||
	isrs_run |= ISR_UART;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The hardware doesn't support this but it's part of XICS so add it.
 | 
			
		||||
#define SPURIOUS "SPURIOUS\r\n"
 | 
			
		||||
void spurious_isr(void) {
 | 
			
		||||
	debug_putstr(SPURIOUS, strlen(SPURIOUS));
 | 
			
		||||
 | 
			
		||||
	isrs_run |= ISR_SPURIOUS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct isr_op {
 | 
			
		||||
	void (*func)(void);
 | 
			
		||||
	int source_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct isr_op isr_table[] = {
 | 
			
		||||
	{ .func = ipi_isr,  .source_id = 2 },
 | 
			
		||||
	{ .func = uart_isr, .source_id = 16 },
 | 
			
		||||
	{ .func = spurious_isr,  .source_id = 0 },
 | 
			
		||||
	{ .func = NULL, .source_id = 0 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
bool ipi_running;
 | 
			
		||||
 | 
			
		||||
#define ISR "ISR XISR="
 | 
			
		||||
void isr(void)
 | 
			
		||||
{
 | 
			
		||||
	struct isr_op *op;
 | 
			
		||||
	uint32_t xirr;
 | 
			
		||||
 | 
			
		||||
	assert(!ipi_running); // check we aren't reentrant
 | 
			
		||||
	ipi_running = true;
 | 
			
		||||
 | 
			
		||||
	xirr = xics_read32(XICS_XIRR); // read hardware irq source
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
	putstr(ISR, strlen(ISR));
 | 
			
		||||
	print_number(xirr & 0xff);
 | 
			
		||||
	putstr("\r\n", 2);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	op = isr_table;
 | 
			
		||||
	while (1) {
 | 
			
		||||
		assert(op->func); // didn't find isr
 | 
			
		||||
		if (op->source_id == (xirr & 0x00ffffff)) {
 | 
			
		||||
		    op->func();
 | 
			
		||||
		    break;
 | 
			
		||||
		}
 | 
			
		||||
		op++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	xics_write32(XICS_XIRR, xirr); // EOI
 | 
			
		||||
 | 
			
		||||
	ipi_running = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*****************************************/
 | 
			
		||||
 | 
			
		||||
int xics_test_0(void)
 | 
			
		||||
{
 | 
			
		||||
	// setup
 | 
			
		||||
	xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
			
		||||
	isrs_run = 0;
 | 
			
		||||
 | 
			
		||||
	xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
			
		||||
 | 
			
		||||
	// trigger two interrupts
 | 
			
		||||
	potato_uart_irq_en(); // cause 0x500 interrupt
 | 
			
		||||
	xics_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
 | 
			
		||||
 | 
			
		||||
	// still masked, so shouldn't happen yet
 | 
			
		||||
	assert(isrs_run == 0);
 | 
			
		||||
 | 
			
		||||
	// unmask IPI only
 | 
			
		||||
	xics_write8(XICS_XIRR, 0x40);
 | 
			
		||||
	assert(isrs_run == ISR_IPI);
 | 
			
		||||
 | 
			
		||||
	// unmask UART
 | 
			
		||||
	xics_write8(XICS_XIRR, 0xc0);
 | 
			
		||||
	assert(isrs_run == (ISR_IPI | ISR_UART));
 | 
			
		||||
 | 
			
		||||
	// cleanup
 | 
			
		||||
	xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
			
		||||
	isrs_run = 0;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int xics_test_1(void)
 | 
			
		||||
{
 | 
			
		||||
	// setup
 | 
			
		||||
	xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
			
		||||
	isrs_run = 0;
 | 
			
		||||
 | 
			
		||||
	xics_write8(XICS_XIRR, 0xff); // allow all interrupts
 | 
			
		||||
 | 
			
		||||
	// should be none pending
 | 
			
		||||
	assert(isrs_run == 0);
 | 
			
		||||
 | 
			
		||||
	// trigger both
 | 
			
		||||
	potato_uart_irq_en(); // cause 0x500 interrupt
 | 
			
		||||
	xics_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
 | 
			
		||||
 | 
			
		||||
	assert(isrs_run == (ISR_IPI | ISR_UART));
 | 
			
		||||
 | 
			
		||||
	// cleanup
 | 
			
		||||
	xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
			
		||||
	isrs_run = 0;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mtmsrd(uint64_t val)
 | 
			
		||||
{
 | 
			
		||||
	__asm__ volatile("mtmsrd %0" : : "r" (val));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int xics_test_2(void)
 | 
			
		||||
{
 | 
			
		||||
	// setup
 | 
			
		||||
	xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
			
		||||
	isrs_run = 0;
 | 
			
		||||
 | 
			
		||||
	// trigger interrupts with MSR[EE]=0 and show they are not run
 | 
			
		||||
	mtmsrd(0x9000000000000003); // EE off
 | 
			
		||||
 | 
			
		||||
	xics_write8(XICS_XIRR, 0xff); // allow all interrupts
 | 
			
		||||
 | 
			
		||||
	// trigger an IPI
 | 
			
		||||
	xics_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
 | 
			
		||||
 | 
			
		||||
	assert(isrs_run == 0);
 | 
			
		||||
 | 
			
		||||
	mtmsrd(0x9000000000008003); // EE on
 | 
			
		||||
	assert(isrs_run == ISR_IPI);
 | 
			
		||||
 | 
			
		||||
	// cleanup
 | 
			
		||||
	xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
			
		||||
	isrs_run = 0;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define TEST "Test "
 | 
			
		||||
#define PASS "PASS\r\n"
 | 
			
		||||
#define FAIL "FAIL\r\n"
 | 
			
		||||
 | 
			
		||||
int (*tests[])(void) = {
 | 
			
		||||
	xics_test_0,
 | 
			
		||||
	xics_test_1,
 | 
			
		||||
	xics_test_2,
 | 
			
		||||
	NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int main(void)
 | 
			
		||||
{
 | 
			
		||||
	int fail = 0;
 | 
			
		||||
	int i = 0;
 | 
			
		||||
	int (*t)(void);
 | 
			
		||||
 | 
			
		||||
	potato_uart_init();
 | 
			
		||||
	ipi_running = false;
 | 
			
		||||
 | 
			
		||||
	/* run the tests */
 | 
			
		||||
	while (1) {
 | 
			
		||||
		t = tests[i];
 | 
			
		||||
		if (!t)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		putstr(TEST, strlen(TEST));
 | 
			
		||||
		print_number(i);
 | 
			
		||||
		putstr(": ", 1);
 | 
			
		||||
		if (t() != 0) {
 | 
			
		||||
			fail = 1;
 | 
			
		||||
			putstr(FAIL, strlen(FAIL));
 | 
			
		||||
		} else
 | 
			
		||||
			putstr(PASS, strlen(PASS));
 | 
			
		||||
 | 
			
		||||
		i++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fail;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,36 @@
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#define XICS_BASE 0xc0004000
 | 
			
		||||
 | 
			
		||||
static uint64_t xics_base = XICS_BASE;
 | 
			
		||||
 | 
			
		||||
#define XICS_XIRR_POLL 0x0
 | 
			
		||||
#define XICS_XIRR      0x4
 | 
			
		||||
#define XICS_RESV      0x8
 | 
			
		||||
#define XICS_MFRR      0xC
 | 
			
		||||
 | 
			
		||||
uint8_t xics_read8(int offset)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t val;
 | 
			
		||||
 | 
			
		||||
	__asm__ volatile("lbzcix %0,%1,%2" : "=r" (val) : "b" (xics_base), "r" (offset));
 | 
			
		||||
	return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void xics_write8(int offset, uint8_t val)
 | 
			
		||||
{
 | 
			
		||||
	__asm__ volatile("stbcix %0,%1,%2" : : "r" (val), "b" (xics_base), "r" (offset));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t xics_read32(int offset)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t val;
 | 
			
		||||
 | 
			
		||||
	__asm__ volatile("lwzcix %0,%1,%2" : "=r" (val) : "b" (xics_base), "r" (offset));
 | 
			
		||||
	return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void xics_write32(int offset, uint32_t val)
 | 
			
		||||
{
 | 
			
		||||
	__asm__ volatile("stwcix %0,%1,%2" : : "r" (val), "b" (xics_base), "r" (offset));
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,207 @@
 | 
			
		||||
--
 | 
			
		||||
-- This is a simple XICS compliant interrupt controller.  This is a
 | 
			
		||||
-- Presenter (ICP) and Source (ICS) in a single unit with no routing
 | 
			
		||||
-- layer.
 | 
			
		||||
--
 | 
			
		||||
-- The sources have a fixed IRQ priority set by HW_PRIORITY. The
 | 
			
		||||
-- source id starts at 16 for int_level_in(0) and go up from
 | 
			
		||||
-- there (ie int_level_in(1) is source id 17).
 | 
			
		||||
--
 | 
			
		||||
-- The presentation layer will pick an interupt that is more
 | 
			
		||||
-- favourable than the current CPPR and present it via the XISR and
 | 
			
		||||
-- send an interrpt to the processor (via e_out). This may not be the
 | 
			
		||||
-- highest priority interrupt currently presented (which is allowed
 | 
			
		||||
-- via XICS)
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
library ieee;
 | 
			
		||||
use ieee.std_logic_1164.all;
 | 
			
		||||
use ieee.numeric_std.all;
 | 
			
		||||
 | 
			
		||||
library work;
 | 
			
		||||
use work.common.all;
 | 
			
		||||
use work.wishbone_types.all;
 | 
			
		||||
 | 
			
		||||
entity xics is
 | 
			
		||||
    generic (
 | 
			
		||||
        LEVEL_NUM : positive := 16
 | 
			
		||||
        );
 | 
			
		||||
    port (
 | 
			
		||||
        clk          : in std_logic;
 | 
			
		||||
        rst          : in std_logic;
 | 
			
		||||
 | 
			
		||||
        wb_in   : in wishbone_master_out;
 | 
			
		||||
        wb_out  : out wishbone_slave_out;
 | 
			
		||||
 | 
			
		||||
	int_level_in : in std_ulogic_vector(LEVEL_NUM - 1 downto 0);
 | 
			
		||||
 | 
			
		||||
	e_out : out XicsToExecute1Type
 | 
			
		||||
        );
 | 
			
		||||
end xics;
 | 
			
		||||
 | 
			
		||||
architecture behaviour of xics is
 | 
			
		||||
    type reg_internal_t is record
 | 
			
		||||
	xisr : std_ulogic_vector(23 downto 0);
 | 
			
		||||
	cppr : std_ulogic_vector(7 downto 0);
 | 
			
		||||
	pending_priority : std_ulogic_vector(7 downto 0);
 | 
			
		||||
	mfrr : std_ulogic_vector(7 downto 0);
 | 
			
		||||
	mfrr_pending : std_ulogic;
 | 
			
		||||
	irq : std_ulogic;
 | 
			
		||||
	wb_rd_data : wishbone_data_type;
 | 
			
		||||
	wb_ack : std_ulogic;
 | 
			
		||||
    end record;
 | 
			
		||||
    constant reg_internal_init : reg_internal_t :=
 | 
			
		||||
	(wb_ack => '0',
 | 
			
		||||
	 mfrr_pending => '0',
 | 
			
		||||
	 mfrr => x"00", -- mask everything on reset
 | 
			
		||||
	 irq => '0',
 | 
			
		||||
	 others => (others => '0'));
 | 
			
		||||
 | 
			
		||||
    signal r, r_next : reg_internal_t;
 | 
			
		||||
 | 
			
		||||
    -- hardwire the hardware IRQ priority
 | 
			
		||||
    constant HW_PRIORITY : std_ulogic_vector(7 downto 0) := x"80";
 | 
			
		||||
 | 
			
		||||
    -- 32 bit offsets for each presentation
 | 
			
		||||
    constant XIRR_POLL : std_ulogic_vector(31 downto 0) := x"00000000";
 | 
			
		||||
    constant XIRR      : std_ulogic_vector(31 downto 0) := x"00000004";
 | 
			
		||||
    constant RESV0     : std_ulogic_vector(31 downto 0) := x"00000008";
 | 
			
		||||
    constant MFRR      : std_ulogic_vector(31 downto 0) := x"0000000c";
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
 | 
			
		||||
    regs : process(clk)
 | 
			
		||||
    begin
 | 
			
		||||
	if rising_edge(clk) then
 | 
			
		||||
	    r <= r_next;
 | 
			
		||||
	end if;
 | 
			
		||||
    end process;
 | 
			
		||||
 | 
			
		||||
    wb_out.dat <= r.wb_rd_data;
 | 
			
		||||
    wb_out.ack <= r.wb_ack;
 | 
			
		||||
    wb_out.stall <= '0'; -- never stall wishbone
 | 
			
		||||
    e_out.irq <= r.irq;
 | 
			
		||||
 | 
			
		||||
    comb : process(all)
 | 
			
		||||
	variable v : reg_internal_t;
 | 
			
		||||
	variable xirr_accept_rd : std_ulogic;
 | 
			
		||||
	variable irq_eoi : std_ulogic;
 | 
			
		||||
    begin
 | 
			
		||||
	v := r;
 | 
			
		||||
 | 
			
		||||
	v.wb_ack := '0';
 | 
			
		||||
 | 
			
		||||
	xirr_accept_rd := '0';
 | 
			
		||||
	irq_eoi := '0';
 | 
			
		||||
 | 
			
		||||
	if wb_in.cyc = '1' and wb_in.stb = '1' then
 | 
			
		||||
	    -- wishbone addresses we get are 64 bit alligned, so we
 | 
			
		||||
	    -- need to use the sel bits to get 32 bit chunks.
 | 
			
		||||
	    v.wb_ack := '1'; -- always ack
 | 
			
		||||
	    if wb_in.we = '1' then -- write
 | 
			
		||||
		-- writes to both XIRR are the same
 | 
			
		||||
		if wb_in.adr = XIRR_POLL then
 | 
			
		||||
		    report "XICS XIRR_POLL/XIRR write";
 | 
			
		||||
		    if wb_in.sel = x"0f" then -- 4 bytes
 | 
			
		||||
			v.cppr := wb_in.dat(31 downto 24);
 | 
			
		||||
		    elsif wb_in.sel = x"f0"  then -- 4 byte
 | 
			
		||||
			v.cppr := wb_in.dat(63 downto 56);
 | 
			
		||||
			irq_eoi := '1';
 | 
			
		||||
		    elsif wb_in.sel = x"01"  then -- 1 byte
 | 
			
		||||
			v.cppr := wb_in.dat(7 downto 0);
 | 
			
		||||
		    elsif wb_in.sel = x"10"  then -- 1 byte
 | 
			
		||||
			v.cppr := wb_in.dat(39 downto 32);
 | 
			
		||||
		    end if;
 | 
			
		||||
 | 
			
		||||
		elsif wb_in.adr = RESV0 then
 | 
			
		||||
		    report "XICS MFRR write";
 | 
			
		||||
		    if wb_in.sel = x"f0" then -- 4 bytes
 | 
			
		||||
			v.mfrr_pending := '1';
 | 
			
		||||
			v.mfrr := wb_in.dat(63 downto 56);
 | 
			
		||||
		    elsif wb_in.sel = x"10" then -- 1 byte
 | 
			
		||||
			v.mfrr_pending := '1';
 | 
			
		||||
			v.mfrr := wb_in.dat(39 downto 32);
 | 
			
		||||
		    end if;
 | 
			
		||||
 | 
			
		||||
		end if;
 | 
			
		||||
 | 
			
		||||
	    else -- read
 | 
			
		||||
		v.wb_rd_data := (others => '0');
 | 
			
		||||
 | 
			
		||||
		if wb_in.adr = XIRR_POLL then
 | 
			
		||||
		    report "XICS XIRR_POLL/XIRR read";
 | 
			
		||||
		    if wb_in.sel = x"0f" then
 | 
			
		||||
			v.wb_rd_data(23 downto  0) := r.xisr;
 | 
			
		||||
			v.wb_rd_data(31 downto 24) := r.cppr;
 | 
			
		||||
		    elsif wb_in.sel = x"f0" then
 | 
			
		||||
			v.wb_rd_data(55 downto 32) := r.xisr;
 | 
			
		||||
			v.wb_rd_data(63 downto 56) := r.cppr;
 | 
			
		||||
			xirr_accept_rd := '1';
 | 
			
		||||
		    elsif wb_in.sel = x"01" then
 | 
			
		||||
			v.wb_rd_data(7 downto  0) := r.cppr;
 | 
			
		||||
		    elsif wb_in.sel = x"10" then
 | 
			
		||||
			v.wb_rd_data(39 downto 32) := r.cppr;
 | 
			
		||||
		    end if;
 | 
			
		||||
 | 
			
		||||
		elsif wb_in.adr = RESV0 then
 | 
			
		||||
		    report "XICS MFRR read";
 | 
			
		||||
		    if wb_in.sel = x"f0" then -- 4 bytes
 | 
			
		||||
			v.wb_rd_data(63 downto 56) := r.mfrr;
 | 
			
		||||
		    elsif wb_in.sel = x"10" then -- 1 byte
 | 
			
		||||
			v.wb_rd_data( 7 downto  0) := r.mfrr;
 | 
			
		||||
		    end if;
 | 
			
		||||
		end if;
 | 
			
		||||
	    end if;
 | 
			
		||||
	end if;
 | 
			
		||||
 | 
			
		||||
	-- generate interrupt
 | 
			
		||||
	if r.irq = '0' then
 | 
			
		||||
	    -- Here we just present any interrupt that's valid and
 | 
			
		||||
	    -- below cppr. For ordering, we ignore hardware
 | 
			
		||||
	    -- priorities.
 | 
			
		||||
	    if unsigned(HW_PRIORITY) < unsigned(r.cppr) then --
 | 
			
		||||
		-- lower HW sources are higher priority
 | 
			
		||||
		for i in LEVEL_NUM - 1 downto 0 loop
 | 
			
		||||
		    if int_level_in(i) = '1' then
 | 
			
		||||
			v.irq := '1';
 | 
			
		||||
			v.xisr := std_ulogic_vector(to_unsigned(16 + i, 24));
 | 
			
		||||
			v.pending_priority := HW_PRIORITY; -- hardware HW IRQs
 | 
			
		||||
		    end if;
 | 
			
		||||
		end loop;
 | 
			
		||||
	    end if;
 | 
			
		||||
 | 
			
		||||
	    -- Do mfrr as a higher priority so mfrr_pending is cleared
 | 
			
		||||
	    if unsigned(r.mfrr) < unsigned(r.cppr) then --
 | 
			
		||||
		report "XICS: MFRR INTERRUPT";
 | 
			
		||||
		-- IPI
 | 
			
		||||
		if r.mfrr_pending = '1' then
 | 
			
		||||
		    v.irq := '1';
 | 
			
		||||
		    v.xisr := x"000002"; -- special XICS MFRR IRQ source number
 | 
			
		||||
		    v.pending_priority := r.mfrr;
 | 
			
		||||
		    v.mfrr_pending := '0';
 | 
			
		||||
		end if;
 | 
			
		||||
	    end if;
 | 
			
		||||
	end if;
 | 
			
		||||
 | 
			
		||||
	-- Accept the interrupt
 | 
			
		||||
	if xirr_accept_rd = '1' then
 | 
			
		||||
	    report "XICS: ACCEPT" &
 | 
			
		||||
		" cppr:" &  to_hstring(r.cppr) &
 | 
			
		||||
		" xisr:" & to_hstring(r.xisr) &
 | 
			
		||||
		" mfrr:" & to_hstring(r.mfrr);
 | 
			
		||||
	    v.cppr := r.pending_priority;
 | 
			
		||||
	end if;
 | 
			
		||||
 | 
			
		||||
	if irq_eoi = '1' then
 | 
			
		||||
	    v.irq := '0';
 | 
			
		||||
	end if;
 | 
			
		||||
 | 
			
		||||
	if rst = '1' then
 | 
			
		||||
	    v := reg_internal_init;
 | 
			
		||||
	end if;
 | 
			
		||||
 | 
			
		||||
	r_next <= v;
 | 
			
		||||
 | 
			
		||||
    end process;
 | 
			
		||||
 | 
			
		||||
end architecture behaviour;
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue