Initial commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
Directory Contents
|
||||
------------------
|
||||
util -> A set of utilities required to make XUM programs.
|
||||
XD* -> XUM MIPS32 single-core demos
|
||||
@@ -0,0 +1,29 @@
|
||||
README for XUM Demo 1 : Hello
|
||||
-----------------------------
|
||||
|
||||
Creator: Grant Ayers (ayers@cs.utah.edu)
|
||||
Date: 25 July 2012
|
||||
|
||||
|
||||
|
||||
DEMONSTRATES
|
||||
------------
|
||||
|
||||
LCD screen, basic hardware functionality test.
|
||||
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Prints the message "It works!" to the LCD screen.
|
||||
|
||||
|
||||
|
||||
BUILDING AND RUNNING
|
||||
--------------------
|
||||
|
||||
To compile, enter the 'bin' directory and update the paths in the Makefile.
|
||||
Then run 'make' from within the same directory. Use the XUM bootloader to
|
||||
send the resulting .xum file to the FPGA.
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# Makefile for XUM
|
||||
#
|
||||
# Compiles code to run on the XUM platform, which
|
||||
# is based on MIPS32 and a GCC cross-compiler toolchain.
|
||||
#
|
||||
# Author: Grant Ayers (ayers@cs.utah.edu)
|
||||
# Date: 3 July 2012
|
||||
#
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
SRC = ../src
|
||||
MIPS_PREFIX = /home/User/XUM/gnu_mips/crosstools
|
||||
MIPS_BIN = $(MIPS_PREFIX)/bin
|
||||
MIPS_LIB = $(MIPS_PREFIX)/mips-elf/lib
|
||||
MIPS_CC = $(MIPS_BIN)/mips-elf-gcc-4.7.1.exe
|
||||
MIPS_AS = $(MIPS_BIN)/mips-elf-as.exe
|
||||
MIPS_LD = $(MIPS_BIN)/mips-elf-ld.exe
|
||||
MIPS_OBJDUMP = $(MIPS_BIN)/mips-elf-objdump.exe
|
||||
MIPS_OBJCOPY = $(MIPS_BIN)/mips-elf-objcopy.exe
|
||||
UTIL_PREFIX = /home/User/XUM/demos/util
|
||||
UTIL_CONVBIN = $(UTIL_PREFIX)/bintohex.exe
|
||||
UTIL_CONVXUM = $(UTIL_PREFIX)/bintoxum.exe
|
||||
|
||||
AS_FLAGS = -march=mips32 -EB -G0
|
||||
LD_FLAGS = -EB -static -Map app.map -T ../src/os/xum.ls
|
||||
LD_LIBS = -lm -lc -lgcc
|
||||
LD_SEARCH = -L$(MIPS_PREFIX)/mips-elf/lib \
|
||||
-L$(MIPS_PREFIX)/lib/gcc/mips-elf/4.7.1
|
||||
LD_DRIVER = $(MIPS_LD) $(LD_FLAGS) $(LD_SEARCH) $(LD_LIBS)
|
||||
CC_FLAGS_ARCH = -march=mips32 -EB -msoft-float -mno-mips16
|
||||
CC_FLAGS_LANG = -Wall -O2 -mgpopt -mxgot -G0
|
||||
CC_FLAGS_INC = -I../src/
|
||||
CC_FLAGS_AS = -Wa,-EB,-mips32,-msoft-float
|
||||
CC_FLAGS_LD = -nostdlib -nostartfiles -static -T ../src/os/xum.ls
|
||||
CC_FLAGS_LIB = -lm -lc -lgcc
|
||||
CC_DRIVER = $(MIPS_CC) $(CC_FLAGS_ARCH) $(CC_FLAGS_LANG) \
|
||||
$(CC_FLAGS_AS) $(CC_FLAGS_INC)
|
||||
|
||||
|
||||
all : app
|
||||
|
||||
app : app.o lcd.o boot.o vectors.o exceptions.o
|
||||
$(LD_DRIVER) $^ -o app.exe
|
||||
@$(MIPS_OBJDUMP) -EB --disassemble app.exe > app.lst
|
||||
@$(MIPS_OBJCOPY) -O binary -j .text app.exe app-code.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .data app.exe app-data1.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .sdata app.exe app-data2.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .sbss app.exe app-data3.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .bss app.exe app-data4.bin
|
||||
@cat app-data1.bin app-data2.bin app-data3.bin app-data4.bin >> app-data.bin
|
||||
@$(UTIL_CONVXUM) -d 4096 app-code.bin app-data.bin app.xum
|
||||
#@$(UTIL_CONVBIN) -c -b app-code.bin app-code.coe
|
||||
$(UTIL_CONVBIN) -c -b app.xum app.coe
|
||||
|
||||
|
||||
|
||||
app.o : $(SRC)/app/app.c
|
||||
$(CC_DRIVER) -c $(SRC)/app/app.c -o app.o
|
||||
|
||||
lcd.o : $(SRC)/drivers/lcd.c $(SRC)/drivers/lcd.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/lcd.c -o lcd.o
|
||||
|
||||
boot.o : $(SRC)/os/boot.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o boot.o $(SRC)/os/boot.asm
|
||||
|
||||
vectors.o : $(SRC)/os/vectors.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o vectors.o $(SRC)/os/vectors.asm
|
||||
|
||||
exceptions.o : $(SRC)/os/exceptions.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o exceptions.o $(SRC)/os/exceptions.asm
|
||||
|
||||
clean :
|
||||
rm -f *.o *.exe *.map *.coe *.bin *.map *.xum *.lst
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,13 @@
|
||||
#include "drivers/lcd.h"
|
||||
|
||||
char *message = "It works!";
|
||||
|
||||
int main(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_setPos(19);
|
||||
LCD_printString(message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
#include "lcd.h"
|
||||
|
||||
static uint8_t LCD_position = 0;
|
||||
static uint8_t LCD_autoIncr = 1;
|
||||
|
||||
static void LCD_incrPos(uint32_t amount)
|
||||
{
|
||||
if (LCD_autoIncr == 0) {
|
||||
return;
|
||||
}
|
||||
while (amount > 32) {
|
||||
amount -= 32;
|
||||
}
|
||||
LCD_position += (uint8_t)amount;
|
||||
if (LCD_position >= 32) {
|
||||
LCD_position -= 32;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCD_clear(void)
|
||||
{
|
||||
volatile uint32_t *LCD;
|
||||
int i;
|
||||
|
||||
LCD = (volatile uint32_t *)LCD_ADDRESS;
|
||||
|
||||
for (i=0; i<8; i++) {
|
||||
LCD[i] = 0x20202020;
|
||||
}
|
||||
LCD_position = 0;
|
||||
}
|
||||
|
||||
void LCD_setPos(uint8_t position)
|
||||
{
|
||||
LCD_position = position;
|
||||
}
|
||||
|
||||
uint8_t LCD_getPos(void)
|
||||
{
|
||||
return LCD_position;
|
||||
}
|
||||
|
||||
void LCD_setAutoIncr(uint8_t incr)
|
||||
{
|
||||
LCD_autoIncr = incr;
|
||||
}
|
||||
|
||||
void LCD_printByte(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
*LCD = byte;
|
||||
LCD_incrPos(1);
|
||||
}
|
||||
|
||||
void LCD_printByteHex(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
uint8_t nibble_h, nibble_l;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
nibble_h = byte >> 4;
|
||||
nibble_l = byte & 0x0f;
|
||||
|
||||
if (nibble_h < 10) {
|
||||
nibble_h += 48;
|
||||
}
|
||||
else {
|
||||
nibble_h += 55;
|
||||
}
|
||||
if (nibble_l < 10) {
|
||||
nibble_l += 48;
|
||||
}
|
||||
else {
|
||||
nibble_h += 55;
|
||||
}
|
||||
*LCD = nibble_h;
|
||||
LCD++;
|
||||
*LCD = nibble_l;
|
||||
LCD_incrPos(2);
|
||||
}
|
||||
|
||||
void LCD_printByteDec(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
uint8_t hundreds, tens, ones;
|
||||
uint32_t n_printed = 1;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
hundreds = tens = ones = 48;
|
||||
|
||||
while (byte >= 100) {
|
||||
hundreds++;
|
||||
byte -= 100;
|
||||
}
|
||||
while (byte >= 10) {
|
||||
tens++;
|
||||
byte -= 10;
|
||||
}
|
||||
while (byte >= 1) {
|
||||
ones++;
|
||||
byte -= 1;
|
||||
}
|
||||
if (hundreds > 48) {
|
||||
*LCD = hundreds;
|
||||
LCD++;
|
||||
n_printed++;
|
||||
}
|
||||
if ((n_printed > 1) || (tens > 48)) {
|
||||
*LCD = tens;
|
||||
LCD++;
|
||||
n_printed++;
|
||||
}
|
||||
*LCD = ones;
|
||||
LCD_incrPos(n_printed);
|
||||
}
|
||||
|
||||
void LCD_printWord(uint32_t word)
|
||||
{
|
||||
volatile uint32_t *LCD;
|
||||
|
||||
LCD = (volatile uint32_t *)(LCD_ADDRESS + LCD_position);
|
||||
*LCD = word;
|
||||
LCD_incrPos(4);
|
||||
}
|
||||
|
||||
void LCD_printString(char *string)
|
||||
{
|
||||
volatile char *LCD;
|
||||
int i = 0;
|
||||
|
||||
LCD = (volatile char *)(LCD_ADDRESS + LCD_position);
|
||||
|
||||
while (string[i] != '\0') {
|
||||
LCD[i] = string[i];
|
||||
i++;
|
||||
}
|
||||
LCD_incrPos(i);
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#ifndef __LCD_H__
|
||||
#define __LCD_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define LCD_ADDRESS 0x80000000
|
||||
|
||||
void LCD_clear(void);
|
||||
void LCD_setPos(uint8_t position);
|
||||
uint8_t LCD_getPos(void);
|
||||
void LCD_setAutoIncr(uint8_t incr);
|
||||
void LCD_printByte(uint8_t byte);
|
||||
void LCD_printByteHex(uint8_t byte);
|
||||
void LCD_printByteDec(uint8_t byte);
|
||||
void LCD_printWord(uint32_t word);
|
||||
void LCD_printString(char *string);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
###############################################################################
|
||||
# TITLE: Boot Up Code
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 19 July 2011
|
||||
# FILENAME: boot.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Initializes the global pointer and stack pointer.
|
||||
# Zeros BSS memory region and jumps to main().
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.global boot
|
||||
.ent boot
|
||||
.set noreorder
|
||||
boot:
|
||||
la $t0, _bss_start # Defined in linker script
|
||||
la $t1, _bss_end
|
||||
la $sp, _sp
|
||||
la $gp, _gp
|
||||
|
||||
$bss_clear:
|
||||
beq $t0, $t1, $cp0_setup # Loop until BSS is cleared
|
||||
nop
|
||||
sb $0, 0($t0)
|
||||
j $bss_clear
|
||||
addiu $t0, $t0, 1
|
||||
|
||||
$cp0_setup:
|
||||
la $26, $run
|
||||
mtc0 $26, $30, 0 # ErrorEPC gets address of $run
|
||||
mfc0 $26, $13, 0 # Load Cause register
|
||||
lui $27, 0x0080 # Use "special" interrupt vector
|
||||
or $26, $26, $27
|
||||
mtc0 $26, $13, 0 # Commit new Cause register
|
||||
mfc0 $26, $12, 0 # Load Status register
|
||||
lui $27, 0x0fff # Disable access to Coprocessors
|
||||
ori $27, $27, 0x00ee # Disable all interrupts,
|
||||
and $26, $26, $27 # and set kernel mode
|
||||
mtc0 $26, $12, 0 # Commit new Status register
|
||||
eret # Return from Reset Exception
|
||||
|
||||
$run:
|
||||
jal main
|
||||
nop
|
||||
|
||||
$done:
|
||||
j $done
|
||||
nop
|
||||
.end boot
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
###############################################################################
|
||||
# TITLE: Exception Vectors
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 23 May 2012
|
||||
# FILENAME: exceptions.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Provides the exception vectors which jump to
|
||||
# exception-handling routines.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.set noreorder
|
||||
.global mips32_exception
|
||||
.ent mips32_exception
|
||||
mips32_exception:
|
||||
j mips32_exception # Loop forever
|
||||
nop
|
||||
.end mips32_exception
|
||||
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
###############################################################################
|
||||
# TITLE: Exception Vectors
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 23 May 2012
|
||||
# FILENAME: exceptions.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Provides the exception vectors which jump to
|
||||
# exception-handling routines.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
# Current setup:
|
||||
# 1. The exception vector begins at address 0x0.
|
||||
# 2. The interrupt vector begins at address 0x8.
|
||||
# 3. Each vector has room for 2 instructions (8 bytes) with which
|
||||
# it must jump to its demultiplexing routine. The demultiplexing
|
||||
# routine calls individual exception-specific handlers.
|
||||
# 4. The linker script must ensure that this code is placed at the
|
||||
# correct address.
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.ent exception_vector
|
||||
.set noreorder
|
||||
exception_vector:
|
||||
j mips32_exception
|
||||
nop
|
||||
.end exception_vector
|
||||
|
||||
|
||||
.ent interrupt_vector
|
||||
interrupt_vector:
|
||||
j mips32_exception
|
||||
nop
|
||||
.end interrupt_vector
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Linker script for MIPS32 (Single Core) FPGA, intended for XUM */
|
||||
|
||||
|
||||
/* Entry Point
|
||||
*
|
||||
* Set it to be the label "boot" (likely in boot.asm)
|
||||
*
|
||||
*/
|
||||
/*ENTRY(boot)*/
|
||||
|
||||
|
||||
/* Memory Section
|
||||
*
|
||||
* The FPGA currently uses one region of Block RAM, which is 592 KB.
|
||||
*
|
||||
* Instruction Memory starts at address 0.
|
||||
*
|
||||
* Data Memory ends 592KB later, at address 0x00094000 (the last
|
||||
* usable word address is 0x00093ffc).
|
||||
*
|
||||
* Instructions : 0x00000000 -> 0x0000fffc ( 64KB)
|
||||
* Data / BSS : 0x00001000 -> 0x00017ffc ( 32KB)
|
||||
* Stack / Heap : 0x00018000 -> 0x00093ffc (496KB)
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* Sections
|
||||
*
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
_sp = 0x00094000;
|
||||
|
||||
. = 0 ;
|
||||
|
||||
.text :
|
||||
{
|
||||
vectors.o(.text)
|
||||
. = 0x10 ;
|
||||
boot.o(.text)
|
||||
exceptions.o(.text)
|
||||
*(.*text*)
|
||||
}
|
||||
|
||||
. = 0x00001000 ;
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.rodata*)
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
_gp = ALIGN(16) + 0x7ff0;
|
||||
|
||||
.got :
|
||||
{
|
||||
*(.got)
|
||||
}
|
||||
|
||||
.sdata :
|
||||
{
|
||||
*(.*sdata*)
|
||||
}
|
||||
|
||||
_bss_start = . ;
|
||||
|
||||
.sbss :
|
||||
{
|
||||
*(.*sbss)
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.*bss)
|
||||
}
|
||||
|
||||
_bss_end = . ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
README for XUM Demo 2 : Timer Interrupt
|
||||
---------------------------------------
|
||||
|
||||
Creator: Grant Ayers (ayers@cs.utah.edu)
|
||||
Date: 26 July 2012
|
||||
|
||||
|
||||
|
||||
DEMONSTRATES
|
||||
------------
|
||||
|
||||
Interrupts, LCD.
|
||||
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Shows a timer interrupting the control flow of the main function, which
|
||||
merely updates a location on the LCD screen as fast as possible.
|
||||
|
||||
|
||||
|
||||
BUILDING AND RUNNING
|
||||
--------------------
|
||||
|
||||
To compile, enter the 'bin' directory and update the paths in the Makefile.
|
||||
Then run 'make' from within the same directory. Use the XUM bootloader to
|
||||
send the resulting .xum file to the FPGA.
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# Makefile for XUM
|
||||
#
|
||||
# Compiles code to run on the XUM platform, which
|
||||
# is based on MIPS32 and a GCC cross-compiler toolchain.
|
||||
#
|
||||
# Author: Grant Ayers (ayers@cs.utah.edu)
|
||||
# Date: 3 July 2012
|
||||
#
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
SRC = ../src
|
||||
MIPS_PREFIX = /home/User/XUM/gnu_mips/crosstools
|
||||
MIPS_BIN = $(MIPS_PREFIX)/bin
|
||||
MIPS_LIB = $(MIPS_PREFIX)/mips-elf/lib
|
||||
MIPS_CC = $(MIPS_BIN)/mips-elf-gcc-4.7.1.exe
|
||||
MIPS_AS = $(MIPS_BIN)/mips-elf-as.exe
|
||||
MIPS_LD = $(MIPS_BIN)/mips-elf-ld.exe
|
||||
MIPS_OBJDUMP = $(MIPS_BIN)/mips-elf-objdump.exe
|
||||
MIPS_OBJCOPY = $(MIPS_BIN)/mips-elf-objcopy.exe
|
||||
UTIL_PREFIX = /home/User/XUM/demos/util
|
||||
UTIL_CONVBIN = $(UTIL_PREFIX)/bintohex.exe
|
||||
UTIL_CONVXUM = $(UTIL_PREFIX)/bintoxum.exe
|
||||
|
||||
AS_FLAGS = -march=mips32 -EB -G0
|
||||
LD_FLAGS = -EB -static -Map app.map -T ../src/os/xum.ls
|
||||
LD_LIBS = -lm -lc -lgcc
|
||||
LD_SEARCH = -L$(MIPS_PREFIX)/mips-elf/lib \
|
||||
-L$(MIPS_PREFIX)/lib/gcc/mips-elf/4.7.1
|
||||
LD_DRIVER = $(MIPS_LD) $(LD_FLAGS) $(LD_SEARCH) $(LD_LIBS)
|
||||
CC_FLAGS_ARCH = -march=mips32 -EB -msoft-float -mno-mips16
|
||||
CC_FLAGS_LANG = -Wall -O2 -mgpopt -mxgot -G0
|
||||
CC_FLAGS_INC = -I../src/
|
||||
CC_FLAGS_AS = -Wa,-EB,-mips32,-msoft-float
|
||||
CC_FLAGS_LD = -nostdlib -nostartfiles -static -T ../src/os/xum.ls
|
||||
CC_FLAGS_LIB = -lm -lc -lgcc
|
||||
CC_DRIVER = $(MIPS_CC) $(CC_FLAGS_ARCH) $(CC_FLAGS_LANG) \
|
||||
$(CC_FLAGS_AS) $(CC_FLAGS_INC)
|
||||
|
||||
|
||||
all : app
|
||||
|
||||
app : lcd.o app.o boot.o vectors.o exceptions.o exception_handler.o piezo.o
|
||||
$(LD_DRIVER) $^ -o app.exe
|
||||
@$(MIPS_OBJDUMP) -EB --disassemble app.exe > app.lst
|
||||
@$(MIPS_OBJCOPY) -O binary -j .text app.exe app-code.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .data app.exe app-data1.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .sdata app.exe app-data2.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .sbss app.exe app-data3.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .bss app.exe app-data4.bin
|
||||
@cat app-data1.bin app-data2.bin app-data3.bin app-data4.bin >> app-data.bin
|
||||
@$(UTIL_CONVXUM) -d 4096 app-code.bin app-data.bin app.xum
|
||||
#@$(UTIL_CONVBIN) -c -b app-code.bin app-code.coe
|
||||
$(UTIL_CONVBIN) -c -b app.xum app.coe
|
||||
|
||||
|
||||
|
||||
app.o : $(SRC)/app/app.c
|
||||
$(CC_DRIVER) -c $(SRC)/app/app.c -o app.o
|
||||
|
||||
i2c.o : $(SRC)/drivers/i2c.c $(SRC)/drivers/i2c.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/i2c.c -o i2c.o
|
||||
|
||||
lcd.o : $(SRC)/drivers/lcd.c $(SRC)/drivers/lcd.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/lcd.c -o lcd.o
|
||||
|
||||
monitor.o : $(SRC)/drivers/monitor.c $(SRC)/drivers/monitor.h i2c.o
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/monitor.c -o monitor.o
|
||||
|
||||
piezo.o : $(SRC)/drivers/piezo.c $(SRC)/drivers/piezo.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/piezo.c -o piezo.o
|
||||
|
||||
exception_handler.o : $(SRC)/os/exception_handler.c $(SRC)/os/exception_handler.h lcd.o piezo.o monitor.o
|
||||
$(CC_DRIVER) -c $(SRC)/os/exception_handler.c -o exception_handler.o
|
||||
|
||||
boot.o : $(SRC)/os/boot.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o boot.o $(SRC)/os/boot.asm
|
||||
|
||||
vectors.o : $(SRC)/os/vectors.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o vectors.o $(SRC)/os/vectors.asm
|
||||
|
||||
exceptions.o : $(SRC)/os/exceptions.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o exceptions.o $(SRC)/os/exceptions.asm
|
||||
|
||||
clean :
|
||||
rm -f *.o *.exe *.map *.coe *.bin *.map *.xum *.lst
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,28 @@
|
||||
#include "drivers/piezo.h"
|
||||
#include "drivers/lcd.h"
|
||||
|
||||
|
||||
char *str_int = "Interrupt\x7e";
|
||||
char *str_main = "Main\x7e";
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static volatile char disp = 0;
|
||||
|
||||
Piezo_play(C5);
|
||||
LCD_clear();
|
||||
LCD_setAutoIncr(0);
|
||||
LCD_setPos(4);
|
||||
LCD_printString(str_int);
|
||||
LCD_setPos(25);
|
||||
LCD_printString(str_main);
|
||||
|
||||
while (1) {
|
||||
LCD_setPos(31);
|
||||
LCD_printByte(disp);
|
||||
disp++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
#include "i2c.h"
|
||||
|
||||
void I2C_clear(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
uint32_t cmd = (1 << 8);
|
||||
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_EnQ(uint8_t byte)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 9) | (uint32_t)byte;
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_transmit(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 10);
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_setReceive(uint8_t bytes)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 12) | (uint32_t)bytes;
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_receive(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 11);
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
uint32_t I2C_DeQ(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t data = *i2c;
|
||||
return data;
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#ifndef __I2C_H__
|
||||
#define __I2C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define I2C_ADDRESS 0x90000000
|
||||
|
||||
void I2C_clear(void);
|
||||
void I2C_EnQ(uint8_t byte);
|
||||
void I2C_transmit(void);
|
||||
void I2C_setReceive(uint8_t bytes);
|
||||
void I2C_receive(void);
|
||||
uint32_t I2C_DeQ(void);
|
||||
|
||||
#endif
|
||||
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
#include "lcd.h"
|
||||
|
||||
static uint8_t LCD_position = 0;
|
||||
static uint8_t LCD_autoIncr = 1;
|
||||
|
||||
static void LCD_incrPos(uint32_t amount)
|
||||
{
|
||||
if (LCD_autoIncr == 0) {
|
||||
return;
|
||||
}
|
||||
while (amount > 32) {
|
||||
amount -= 32;
|
||||
}
|
||||
LCD_position += (uint8_t)amount;
|
||||
if (LCD_position >= 32) {
|
||||
LCD_position -= 32;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCD_clear(void)
|
||||
{
|
||||
volatile uint32_t *LCD;
|
||||
int i;
|
||||
|
||||
LCD = (volatile uint32_t *)LCD_ADDRESS;
|
||||
|
||||
for (i=0; i<8; i++) {
|
||||
LCD[i] = 0x20202020;
|
||||
}
|
||||
LCD_position = 0;
|
||||
}
|
||||
|
||||
void LCD_setPos(uint8_t position)
|
||||
{
|
||||
LCD_position = position;
|
||||
}
|
||||
|
||||
uint8_t LCD_getPos(void)
|
||||
{
|
||||
return LCD_position;
|
||||
}
|
||||
|
||||
void LCD_setAutoIncr(uint8_t incr)
|
||||
{
|
||||
LCD_autoIncr = incr;
|
||||
}
|
||||
|
||||
void LCD_printByte(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
*LCD = byte;
|
||||
LCD_incrPos(1);
|
||||
}
|
||||
|
||||
void LCD_printByteHex(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
uint8_t nibble_h, nibble_l;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
nibble_h = byte >> 4;
|
||||
nibble_l = byte & 0x0f;
|
||||
|
||||
if (nibble_h < 10) {
|
||||
nibble_h += 48;
|
||||
}
|
||||
else {
|
||||
nibble_h += 55;
|
||||
}
|
||||
if (nibble_l < 10) {
|
||||
nibble_l += 48;
|
||||
}
|
||||
else {
|
||||
nibble_h += 55;
|
||||
}
|
||||
*LCD = nibble_h;
|
||||
LCD++;
|
||||
*LCD = nibble_l;
|
||||
LCD_incrPos(2);
|
||||
}
|
||||
|
||||
void LCD_printByteDec(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
uint8_t hundreds, tens, ones;
|
||||
uint32_t n_printed = 1;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
hundreds = tens = ones = 48;
|
||||
|
||||
while (byte >= 100) {
|
||||
hundreds++;
|
||||
byte -= 100;
|
||||
}
|
||||
while (byte >= 10) {
|
||||
tens++;
|
||||
byte -= 10;
|
||||
}
|
||||
while (byte >= 1) {
|
||||
ones++;
|
||||
byte -= 1;
|
||||
}
|
||||
if (hundreds > 48) {
|
||||
*LCD = hundreds;
|
||||
LCD++;
|
||||
n_printed++;
|
||||
}
|
||||
if ((n_printed > 1) || (tens > 48)) {
|
||||
*LCD = tens;
|
||||
LCD++;
|
||||
n_printed++;
|
||||
}
|
||||
*LCD = ones;
|
||||
LCD_incrPos(n_printed);
|
||||
}
|
||||
|
||||
void LCD_printWord(uint32_t word)
|
||||
{
|
||||
volatile uint32_t *LCD;
|
||||
|
||||
LCD = (volatile uint32_t *)(LCD_ADDRESS + LCD_position);
|
||||
*LCD = word;
|
||||
LCD_incrPos(4);
|
||||
}
|
||||
|
||||
void LCD_printString(char *string)
|
||||
{
|
||||
volatile char *LCD;
|
||||
int i = 0;
|
||||
|
||||
LCD = (volatile char *)(LCD_ADDRESS + LCD_position);
|
||||
|
||||
while (string[i] != '\0') {
|
||||
LCD[i] = string[i];
|
||||
i++;
|
||||
}
|
||||
LCD_incrPos(i);
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#ifndef __LCD_H__
|
||||
#define __LCD_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define LCD_ADDRESS 0x80000000
|
||||
|
||||
void LCD_clear(void);
|
||||
void LCD_setPos(uint8_t position);
|
||||
uint8_t LCD_getPos(void);
|
||||
void LCD_setAutoIncr(uint8_t incr);
|
||||
void LCD_printByte(uint8_t byte);
|
||||
void LCD_printByteHex(uint8_t byte);
|
||||
void LCD_printByteDec(uint8_t byte);
|
||||
void LCD_printWord(uint32_t word);
|
||||
void LCD_printString(char *string);
|
||||
|
||||
#endif
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#include "monitor.h"
|
||||
|
||||
void Monitor_start(void)
|
||||
{
|
||||
I2C_clear();
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_EnQ(0x40); // Configuration Register 1
|
||||
I2C_EnQ(0x1); // Enable monitoring
|
||||
I2C_transmit();
|
||||
}
|
||||
|
||||
|
||||
// Node is 0->Remote 1, 1->Local, 2->Remote 2
|
||||
uint32_t Monitor_readTemp(int node)
|
||||
{
|
||||
uint8_t reg = 0x25 + node;
|
||||
uint32_t data;
|
||||
|
||||
// Set the read register
|
||||
I2C_clear();
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_EnQ(reg);
|
||||
I2C_transmit();
|
||||
|
||||
// Receive the register
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_setReceive(1);
|
||||
I2C_receive();
|
||||
data = I2C_DeQ();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
#ifndef __MONITOR_H__
|
||||
#define __MONITOR_H__
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
#define MONITOR_BUS_ADDR 0x2C
|
||||
|
||||
void Monitor_start(void);
|
||||
uint32_t Monitor_readTemp(int node);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#include "piezo.h"
|
||||
|
||||
void Piezo_set(uint32_t count, int enable)
|
||||
{
|
||||
volatile uint32_t *Piezo = (volatile uint32_t *)PIEZO_ADDRESS;
|
||||
|
||||
if (enable) {
|
||||
*Piezo = count | 0x1000000;
|
||||
}
|
||||
else {
|
||||
*Piezo = count & ~0x1000000;
|
||||
}
|
||||
}
|
||||
|
||||
void Piezo_play(uint32_t note)
|
||||
{
|
||||
Piezo_set(note, 1);
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
#ifndef __PIEZO_H__
|
||||
#define __PIEZO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PIEZO_ADDRESS 0xA0000000
|
||||
|
||||
/* Following are defined for a 100 MHz Piezo driver */
|
||||
#define C0 3058104
|
||||
#define C1 1529052
|
||||
|
||||
#define C4 191110
|
||||
#define C4s 180388
|
||||
#define D4f C4s
|
||||
#define D4 170264
|
||||
#define D4s 160705
|
||||
#define E4f D4s
|
||||
#define E4 151685
|
||||
#define F4 143172
|
||||
#define F4s 135138
|
||||
#define G4f F4s
|
||||
#define G4 127551
|
||||
#define G4s 120395
|
||||
#define A4f G4s
|
||||
#define A4 113636
|
||||
#define A4s 107259
|
||||
#define B4f A4s
|
||||
#define B4 101239
|
||||
#define C5 95557
|
||||
#define C5s 90192
|
||||
#define D5f C5s
|
||||
#define D5 85131
|
||||
#define D5s 80354
|
||||
#define E5f D5s
|
||||
#define E5 75843
|
||||
|
||||
#define C8 11945
|
||||
|
||||
|
||||
void Piezo_set(uint32_t count, int enable);
|
||||
void Piezo_play(uint32_t note);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
###############################################################################
|
||||
# TITLE: Boot Up Code
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 19 July 2011
|
||||
# FILENAME: boot.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Initializes the global pointer and stack pointer.
|
||||
# Zeros BSS memory region and jumps to main().
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.global boot
|
||||
.ent boot
|
||||
.set noreorder
|
||||
boot:
|
||||
la $t0, _bss_start # Defined in linker script
|
||||
la $t1, _bss_end
|
||||
la $sp, _sp
|
||||
la $gp, _gp
|
||||
|
||||
$bss_clear:
|
||||
beq $t0, $t1, $cp0_setup # Loop until BSS is cleared
|
||||
nop
|
||||
sb $0, 0($t0)
|
||||
j $bss_clear
|
||||
addiu $t0, $t0, 1
|
||||
|
||||
$cp0_setup:
|
||||
la $26, $run # Load the address of $run into
|
||||
mtc0 $26, $30, 0 # the ErrorEPC
|
||||
mfc0 $26, $13, 0 # Load Cause register
|
||||
lui $27, 0x0080 # Use "special" interrupt vector
|
||||
or $26, $26, $27
|
||||
mtc0 $26, $13, 0 # Commit new Cause register
|
||||
mfc0 $26, $12, 0 # Load Status register
|
||||
lui $27, 0x0fff # Disable access to Coprocessors,
|
||||
ori $27, $27, 0xffef # Base operating mode is Kernel
|
||||
and $26, $26, $27
|
||||
ori $27, $0, 0xff01 # Enable all interrupts
|
||||
or $26, $26, $27
|
||||
mtc0 $26, $12, 0 # Commit new Status register
|
||||
|
||||
#lui $26, 0x0000 # 1ms timer (50 MHz)
|
||||
#ori $26, $26, 0xc350
|
||||
#lui $26, 0x0007 # 10ms timer (50 MHz)
|
||||
#ori $26, $26, 0xa120
|
||||
#lui $26, 0x004c # 100ms timer (50 MHz)
|
||||
#ori $26, $26, 0x4b40
|
||||
lui $26, 0x017d # 500ms timer (50 MHz)
|
||||
ori $26, 0x7840
|
||||
#lui $26, 0x02fa # 1 sec timer (50 MHz)
|
||||
#ori $26, $26, 0xf080
|
||||
mtc0 $26, $11, 0 # Set Compare register to timer value
|
||||
|
||||
eret # Return from Reset Exception
|
||||
|
||||
$run:
|
||||
jal main
|
||||
nop
|
||||
|
||||
$done:
|
||||
j $done
|
||||
nop
|
||||
|
||||
.end boot
|
||||
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
#include "drivers/lcd.h"
|
||||
#include "drivers/piezo.h"
|
||||
|
||||
void dead_loop(void)
|
||||
{
|
||||
for (;;) {}
|
||||
}
|
||||
|
||||
void mips32_handler_AdEL(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("AdEL");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_AdES(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("AdES");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Bp(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Bp");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_CpU(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("CpU");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Ov(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Ov");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_RI(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("RI");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Sys(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Sys");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Tr(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Trap");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
/* Timer */
|
||||
void mips32_handler_HwInt5(void)
|
||||
{
|
||||
static volatile char blink = 0;
|
||||
static volatile char wait = 0;
|
||||
|
||||
if (blink == 0) {
|
||||
blink++;
|
||||
LCD_setPos(15);
|
||||
LCD_printByte(' ');
|
||||
}
|
||||
else {
|
||||
blink--;
|
||||
LCD_setPos(15);
|
||||
LCD_printByte('.');
|
||||
}
|
||||
|
||||
if (wait == 1) {
|
||||
wait++;
|
||||
Piezo_set(0, 0);
|
||||
}
|
||||
else if (wait < 1) {
|
||||
wait++;
|
||||
}
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt4(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt3(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt2(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt1(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
void mips32_handler_HwInt0(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_SwInt1(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_SwInt0(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#ifndef __exception_handler_h__
|
||||
#define __exception_handler_h__
|
||||
|
||||
/* MIPS32 Exception Handlers */
|
||||
void mips32_handler_AdEL(void);
|
||||
void mips32_handler_AdES(void);
|
||||
void mips32_handler_Bp(void);
|
||||
void mips32_handler_CpU(void);
|
||||
void mips32_handler_Ov(void);
|
||||
void mips32_handler_RI(void);
|
||||
void mips32_handler_Sys(void);
|
||||
void mips32_handler_Tr(void);
|
||||
|
||||
/* MIPS32 Interrupt Handlers */
|
||||
void mips32_handler_HwInt5(void);
|
||||
void mips32_handler_HwInt4(void);
|
||||
void mips32_handler_HwInt3(void);
|
||||
void mips32_handler_HwInt2(void);
|
||||
void mips32_handler_HwInt1(void);
|
||||
void mips32_handler_HwInt0(void);
|
||||
void mips32_handler_SwInt1(void);
|
||||
void mips32_handler_SwInt0(void);
|
||||
|
||||
#endif
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
###############################################################################
|
||||
# TITLE: Exception Vectors
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 23 May 2012
|
||||
# FILENAME: exceptions.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Provides the exception vectors which jump to
|
||||
# exception-handling routines.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.set noreorder
|
||||
.set noat
|
||||
|
||||
exc_save:
|
||||
# Save all registers except k0 k1 sp ra
|
||||
addiu $sp, $sp, -112
|
||||
sw $1, 0($sp)
|
||||
sw $2, 4($sp)
|
||||
sw $3, 8($sp)
|
||||
sw $4, 12($sp)
|
||||
sw $5, 16($sp)
|
||||
sw $6, 20($sp)
|
||||
sw $7, 24($sp)
|
||||
sw $8, 28($sp)
|
||||
sw $9, 32($sp)
|
||||
sw $10, 36($sp)
|
||||
sw $11, 40($sp)
|
||||
sw $12, 44($sp)
|
||||
sw $13, 48($sp)
|
||||
sw $14, 52($sp)
|
||||
sw $15, 56($sp)
|
||||
sw $16, 60($sp)
|
||||
sw $17, 64($sp)
|
||||
sw $18, 68($sp)
|
||||
sw $19, 72($sp)
|
||||
sw $20, 76($sp)
|
||||
sw $21, 80($sp)
|
||||
sw $22, 84($sp)
|
||||
sw $23, 88($sp)
|
||||
sw $24, 92($sp)
|
||||
sw $25, 96($sp)
|
||||
sw $28, 100($sp)
|
||||
jr $ra
|
||||
sw $30, 104($sp)
|
||||
|
||||
exc_restore:
|
||||
# Restore all registers except k0 k1 sp ra
|
||||
lw $1, 0($sp)
|
||||
lw $2, 4($sp)
|
||||
lw $3, 8($sp)
|
||||
lw $4, 12($sp)
|
||||
lw $5, 16($sp)
|
||||
lw $6, 20($sp)
|
||||
lw $7, 24($sp)
|
||||
lw $8, 28($sp)
|
||||
lw $9, 32($sp)
|
||||
lw $10, 36($sp)
|
||||
lw $11, 40($sp)
|
||||
lw $12, 44($sp)
|
||||
lw $13, 48($sp)
|
||||
lw $14, 52($sp)
|
||||
lw $15, 56($sp)
|
||||
lw $16, 60($sp)
|
||||
lw $17, 64($sp)
|
||||
lw $18, 68($sp)
|
||||
lw $19, 72($sp)
|
||||
lw $20, 76($sp)
|
||||
lw $21, 80($sp)
|
||||
lw $22, 84($sp)
|
||||
lw $23, 88($sp)
|
||||
lw $24, 92($sp)
|
||||
lw $25, 96($sp)
|
||||
lw $28, 100($sp)
|
||||
lw $30, 104($sp)
|
||||
jr $ra
|
||||
addiu $sp, $sp, 112
|
||||
|
||||
|
||||
.global mips32_general_exception
|
||||
.ent mips32_general_exception
|
||||
mips32_general_exception:
|
||||
or $26, $0, $ra
|
||||
jal exc_save
|
||||
nop
|
||||
mfc0 $27, $13, 0 # Read Cause which has ExcCode bits
|
||||
srl $27, $27, 2 # Extract exception code to $k1
|
||||
andi $27, $27, 0x001f
|
||||
|
||||
la $ra, $end_exception # Jump to the appropriate handler
|
||||
addiu $t0, $0, 4
|
||||
addiu $t1, $0, 5
|
||||
addiu $t2, $0, 8
|
||||
addiu $t3, $0, 9
|
||||
beq $t0, $27, mips32_handler_AdEL
|
||||
addiu $t0, $0, 10
|
||||
beq $t1, $27, mips32_handler_AdES
|
||||
addiu $t1, $0, 11
|
||||
beq $t2, $27, mips32_handler_Sys
|
||||
addiu $t2, $0, 12
|
||||
beq $t3, $27, mips32_handler_Bp
|
||||
addiu $t3, $0, 13
|
||||
beq $t0, $27, mips32_handler_RI
|
||||
nop
|
||||
beq $t1, $27, mips32_handler_CpU
|
||||
nop
|
||||
beq $t2, $27, mips32_handler_Ov
|
||||
nop
|
||||
beq $t3, $27, mips32_handler_Tr
|
||||
nop
|
||||
|
||||
$end_exception:
|
||||
jal exc_restore
|
||||
xor $27, $0, $0
|
||||
or $ra, $0, $26
|
||||
xor $26, $0, $0
|
||||
eret
|
||||
.end mips32_general_exception
|
||||
|
||||
|
||||
|
||||
### "Special" Interrupt Vector: Cause_IV must be set.
|
||||
|
||||
.ent mips32_interrupt_exception
|
||||
.global mips32_interrupt_exception
|
||||
mips32_interrupt_exception:
|
||||
mfc0 $26, $12, 0 # Status register for IM bits
|
||||
mfc0 $27, $13, 0 # Cause register for IP bits
|
||||
and $26, $26, $27 # Extract pending, unmasked interrupts
|
||||
srl $26, $26, 8
|
||||
andi $26, $26, 0x00ff
|
||||
|
||||
addu $27, $0, $ra
|
||||
jal exc_save
|
||||
clz $26, $26
|
||||
la $ra, $end_interrupt # All C functions will return here
|
||||
addiu $t0, $0, 24
|
||||
addiu $t1, $0, 25
|
||||
addiu $t2, $0, 26
|
||||
beq $26, $t0, mips32_handler_HwInt5
|
||||
addiu $t0, $0, 27
|
||||
beq $26, $t1, mips32_handler_HwInt4
|
||||
addiu $t1, $0, 28
|
||||
beq $26, $t2, mips32_handler_HwInt3
|
||||
addiu $t2, $0, 29
|
||||
beq $26, $t0, mips32_handler_HwInt2
|
||||
addiu $t0, $0, 30
|
||||
beq $26, $t1, mips32_handler_HwInt1
|
||||
addiu $t1, $0, 31
|
||||
beq $26, $t2, mips32_handler_HwInt0
|
||||
nop
|
||||
beq $26, $t0, mips32_handler_SwInt1
|
||||
nop
|
||||
beq $26, $t1, mips32_handler_SwInt0
|
||||
nop
|
||||
|
||||
|
||||
$end_interrupt:
|
||||
jal exc_restore
|
||||
mfc0 $26, $9, 0 # Clear HwInt5 if applicable
|
||||
or $ra, $0, $27
|
||||
eret
|
||||
.end mips32_interrupt_exception
|
||||
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
###############################################################################
|
||||
# TITLE: Exception Vectors
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 23 May 2012
|
||||
# FILENAME: exceptions.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Provides the exception vectors which jump to
|
||||
# exception-handling routines.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
# Current setup:
|
||||
# 1. The exception vector begins at address 0x0.
|
||||
# 2. The interrupt vector begins at address 0x8.
|
||||
# 3. Each vector has room for 2 instructions (8 bytes) with which
|
||||
# it must jump to its demultiplexing routine. The demultiplexing
|
||||
# routine calls individual exception-specific handlers.
|
||||
# 4. The linker script must ensure that this code is placed at the
|
||||
# correct address.
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.ent exception_vector
|
||||
.set noreorder
|
||||
exception_vector:
|
||||
j mips32_general_exception
|
||||
nop
|
||||
.end exception_vector
|
||||
|
||||
|
||||
.ent interrupt_vector
|
||||
interrupt_vector:
|
||||
j mips32_interrupt_exception
|
||||
nop
|
||||
.end interrupt_vector
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Linker script for MIPS32 (Single Core) FPGA, intended for XUM */
|
||||
|
||||
|
||||
/* Entry Point
|
||||
*
|
||||
* Set it to be the label "boot" (likely in boot.asm)
|
||||
*
|
||||
*/
|
||||
/*ENTRY(boot)*/
|
||||
|
||||
|
||||
/* Memory Section
|
||||
*
|
||||
* The FPGA currently uses one region of Block RAM, which is 592 KB.
|
||||
*
|
||||
* Instruction Memory starts at address 0.
|
||||
*
|
||||
* Data Memory ends 592KB later, at address 0x00094000 (the last
|
||||
* usable word address is 0x00093ffc).
|
||||
*
|
||||
* Instructions : 0x00000000 -> 0x0000fffc ( 64KB)
|
||||
* Data / BSS : 0x00001000 -> 0x00017ffc ( 32KB)
|
||||
* Stack / Heap : 0x00018000 -> 0x00093ffc (496KB)
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* Sections
|
||||
*
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
_sp = 0x00094000;
|
||||
|
||||
. = 0 ;
|
||||
|
||||
.text :
|
||||
{
|
||||
vectors.o(.text)
|
||||
. = 0x10 ;
|
||||
boot.o(.text)
|
||||
exceptions.o(.text)
|
||||
*(.*text*)
|
||||
}
|
||||
|
||||
. = 0x00001000 ;
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.rodata*)
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
_gp = ALIGN(16) + 0x7ff0;
|
||||
|
||||
.got :
|
||||
{
|
||||
*(.got)
|
||||
}
|
||||
|
||||
.sdata :
|
||||
{
|
||||
*(.*sdata*)
|
||||
}
|
||||
|
||||
_bss_start = . ;
|
||||
|
||||
.sbss :
|
||||
{
|
||||
*(.*sbss)
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.*bss)
|
||||
}
|
||||
|
||||
_bss_end = . ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
README for XUM Demo 3 : I2C
|
||||
---------------------------
|
||||
|
||||
Creator: Grant Ayers (ayers@cs.utah.edu)
|
||||
Date: 26 July 2012
|
||||
|
||||
|
||||
|
||||
DEMONSTRATES
|
||||
------------
|
||||
|
||||
I2C bus, LCD.
|
||||
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Uses the I2C main bus on the XUPV5 FPGA to read and display the temperature
|
||||
from the onboard hardware monitor chip and from the FPGA.
|
||||
|
||||
|
||||
|
||||
BUILDING AND RUNNING
|
||||
--------------------
|
||||
|
||||
To compile, enter the 'bin' directory and update the paths in the Makefile.
|
||||
Then run 'make' from within the same directory. Use the XUM bootloader to
|
||||
send the resulting .xum file to the FPGA.
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
# Makefile for XUM
|
||||
#
|
||||
# Compiles code to run on the XUM platform, which
|
||||
# is based on MIPS32 and a GCC cross-compiler toolchain.
|
||||
#
|
||||
# Author: Grant Ayers (ayers@cs.utah.edu)
|
||||
# Date: 3 July 2012
|
||||
#
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
SRC = ../src
|
||||
MIPS_PREFIX = /home/User/XUM/gnu_mips/crosstools
|
||||
MIPS_BIN = $(MIPS_PREFIX)/bin
|
||||
MIPS_LIB = $(MIPS_PREFIX)/mips-elf/lib
|
||||
MIPS_CC = $(MIPS_BIN)/mips-elf-gcc-4.7.1.exe
|
||||
MIPS_AS = $(MIPS_BIN)/mips-elf-as.exe
|
||||
MIPS_LD = $(MIPS_BIN)/mips-elf-ld.exe
|
||||
MIPS_OBJDUMP = $(MIPS_BIN)/mips-elf-objdump.exe
|
||||
MIPS_OBJCOPY = $(MIPS_BIN)/mips-elf-objcopy.exe
|
||||
UTIL_PREFIX = /home/User/XUM/demos/util
|
||||
UTIL_CONVBIN = $(UTIL_PREFIX)/bintohex.exe
|
||||
UTIL_CONVXUM = $(UTIL_PREFIX)/bintoxum.exe
|
||||
|
||||
AS_FLAGS = -march=mips32 -EB -G0
|
||||
LD_FLAGS = -EB -static -Map app.map -T ../src/os/xum.ls
|
||||
LD_LIBS = -lm -lc -lgcc
|
||||
LD_SEARCH = -L$(MIPS_PREFIX)/mips-elf/lib \
|
||||
-L$(MIPS_PREFIX)/lib/gcc/mips-elf/4.7.1
|
||||
LD_DRIVER = $(MIPS_LD) $(LD_FLAGS) $(LD_SEARCH) $(LD_LIBS)
|
||||
CC_FLAGS_ARCH = -march=mips32 -EB -msoft-float -mno-mips16 -mno-branch-likely \
|
||||
-mgpopt
|
||||
CC_FLAGS_LANG = -Wall -O2
|
||||
CC_FLAGS_INC = -I../src/
|
||||
CC_FLAGS_AS = -Wa,-EB,-mips32,-msoft-float
|
||||
CC_FLAGS_LD = -nostdlib -nostartfiles -static -T ../src/os/xum.ls
|
||||
CC_FLAGS_LIB = -lm -lc -lgcc
|
||||
CC_DRIVER = $(MIPS_CC) $(CC_FLAGS_ARCH) $(CC_FLAGS_LANG) \
|
||||
$(CC_FLAGS_AS) $(CC_FLAGS_INC)
|
||||
|
||||
|
||||
all : app
|
||||
|
||||
app : app.o monitor.o i2c.o lcd.o boot.o vectors.o exceptions.o exception_handler.o piezo.o
|
||||
$(LD_DRIVER) $^ -o app.exe
|
||||
@$(MIPS_OBJDUMP) -EB --disassemble app.exe > app.lst
|
||||
@$(MIPS_OBJCOPY) -O binary -j .text app.exe app-code.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .data app.exe app-data1.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .sdata app.exe app-data2.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .sbss app.exe app-data3.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .bss app.exe app-data4.bin
|
||||
@cat app-data1.bin app-data2.bin app-data3.bin app-data4.bin >> app-data.bin
|
||||
@$(UTIL_CONVXUM) -d 4096 app-code.bin app-data.bin app.xum
|
||||
#@$(UTIL_CONVBIN) -c -b app-code.bin app-code.coe
|
||||
$(UTIL_CONVBIN) -c -b app.xum app.coe
|
||||
|
||||
|
||||
|
||||
app.o : $(SRC)/app/app.c
|
||||
$(CC_DRIVER) -c $(SRC)/app/app.c -o app.o
|
||||
|
||||
uart.o : $(SRC)/drivers/uart.c $(SRC)/drivers/uart.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/uart.c -o uart.o
|
||||
|
||||
i2c.o : $(SRC)/drivers/i2c.c $(SRC)/drivers/i2c.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/i2c.c -o i2c.o
|
||||
|
||||
lcd.o : $(SRC)/drivers/lcd.c $(SRC)/drivers/lcd.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/lcd.c -o lcd.o
|
||||
|
||||
monitor.o : $(SRC)/drivers/monitor.c $(SRC)/drivers/monitor.h i2c.o
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/monitor.c -o monitor.o
|
||||
|
||||
piezo.o : $(SRC)/drivers/piezo.c $(SRC)/drivers/piezo.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/piezo.c -o piezo.o
|
||||
|
||||
exception_handler.o : $(SRC)/os/exception_handler.c $(SRC)/os/exception_handler.h lcd.o piezo.o monitor.o
|
||||
$(CC_DRIVER) -c $(SRC)/os/exception_handler.c -o exception_handler.o
|
||||
|
||||
boot.o : $(SRC)/os/boot.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o boot.o $(SRC)/os/boot.asm
|
||||
|
||||
vectors.o : $(SRC)/os/vectors.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o vectors.o $(SRC)/os/vectors.asm
|
||||
|
||||
exceptions.o : $(SRC)/os/exceptions.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o exceptions.o $(SRC)/os/exceptions.asm
|
||||
|
||||
clean :
|
||||
rm -f *.o *.exe *.map *.coe *.bin *.map *.xum *.lst
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,39 @@
|
||||
#include "drivers/piezo.h"
|
||||
#include "drivers/lcd.h"
|
||||
#include "drivers/monitor.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
uint32_t temperature;
|
||||
|
||||
Piezo_play(C5);
|
||||
Monitor_start();
|
||||
LCD_clear();
|
||||
LCD_setPos(16);
|
||||
LCD_printString("Temp:");
|
||||
|
||||
while (1) {
|
||||
// Get Monitor temperature
|
||||
temperature = Monitor_readTemp(1);
|
||||
LCD_setPos(22);
|
||||
LCD_printByteDec((uint8_t)temperature);
|
||||
LCD_printByte('/');
|
||||
|
||||
// Get CPU temperature
|
||||
temperature = Monitor_readTemp(0);
|
||||
LCD_printByteDec((uint8_t)temperature);
|
||||
LCD_printByte(0xdf); // degree symbol
|
||||
LCD_printByte('C');
|
||||
LCD_printByte(' ');
|
||||
LCD_printByte(' ');
|
||||
|
||||
// Display a rolling value so we know we're alive
|
||||
LCD_setPos(31);
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int foo(int a, int b)
|
||||
{
|
||||
return (a+b);
|
||||
}
|
||||
|
||||
int foo(int a)
|
||||
{
|
||||
return a*2;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return foo(2);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "i2c.h"
|
||||
|
||||
void I2C_clear(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
uint32_t cmd = (1 << 8);
|
||||
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_EnQ(uint8_t byte)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 9) | (uint32_t)byte;
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_transmit(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 10);
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_setReceive(uint8_t bytes)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 12) | (uint32_t)bytes;
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_receive(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 11);
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
uint32_t I2C_DeQ(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t data = *i2c;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef __I2C_H__
|
||||
#define __I2C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define I2C_ADDRESS 0x90000000
|
||||
|
||||
void I2C_clear(void);
|
||||
void I2C_EnQ(uint8_t byte);
|
||||
void I2C_transmit(void);
|
||||
void I2C_setReceive(uint8_t bytes);
|
||||
void I2C_receive(void);
|
||||
uint32_t I2C_DeQ(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
#include "lcd.h"
|
||||
|
||||
static uint8_t LCD_position = 0;
|
||||
static uint8_t LCD_autoIncr = 1;
|
||||
|
||||
static void LCD_incrPos(uint32_t amount)
|
||||
{
|
||||
if (LCD_autoIncr == 0) {
|
||||
return;
|
||||
}
|
||||
while (amount > 32) {
|
||||
amount -= 32;
|
||||
}
|
||||
LCD_position += (uint8_t)amount;
|
||||
if (LCD_position >= 32) {
|
||||
LCD_position -= 32;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCD_clear(void)
|
||||
{
|
||||
volatile uint32_t *LCD;
|
||||
int i;
|
||||
|
||||
LCD = (volatile uint32_t *)LCD_ADDRESS;
|
||||
|
||||
for (i=0; i<8; i++) {
|
||||
LCD[i] = 0x20202020;
|
||||
}
|
||||
LCD_position = 0;
|
||||
}
|
||||
|
||||
void LCD_setPos(uint8_t position)
|
||||
{
|
||||
LCD_position = position;
|
||||
}
|
||||
|
||||
uint8_t LCD_getPos(void)
|
||||
{
|
||||
return LCD_position;
|
||||
}
|
||||
|
||||
void LCD_setAutoIncr(uint8_t incr)
|
||||
{
|
||||
LCD_autoIncr = incr;
|
||||
}
|
||||
|
||||
void LCD_printByte(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
*LCD = byte;
|
||||
LCD_incrPos(1);
|
||||
}
|
||||
|
||||
void LCD_printByteHex(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
uint8_t nibble_h, nibble_l;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
nibble_h = byte >> 4;
|
||||
nibble_l = byte & 0x0f;
|
||||
|
||||
if (nibble_h < 10) {
|
||||
nibble_h += 48;
|
||||
}
|
||||
else {
|
||||
nibble_h += 55;
|
||||
}
|
||||
if (nibble_l < 10) {
|
||||
nibble_l += 48;
|
||||
}
|
||||
else {
|
||||
nibble_h += 55;
|
||||
}
|
||||
*LCD = nibble_h;
|
||||
LCD++;
|
||||
*LCD = nibble_l;
|
||||
LCD_incrPos(2);
|
||||
}
|
||||
|
||||
void LCD_printByteDec(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
uint8_t hundreds, tens, ones;
|
||||
uint32_t n_printed = 1;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
hundreds = tens = ones = 48;
|
||||
|
||||
while (byte >= 100) {
|
||||
hundreds++;
|
||||
byte -= 100;
|
||||
}
|
||||
while (byte >= 10) {
|
||||
tens++;
|
||||
byte -= 10;
|
||||
}
|
||||
while (byte >= 1) {
|
||||
ones++;
|
||||
byte -= 1;
|
||||
}
|
||||
if (hundreds > 48) {
|
||||
*LCD = hundreds;
|
||||
LCD++;
|
||||
n_printed++;
|
||||
}
|
||||
if ((n_printed > 1) || (tens > 48)) {
|
||||
*LCD = tens;
|
||||
LCD++;
|
||||
n_printed++;
|
||||
}
|
||||
*LCD = ones;
|
||||
LCD_incrPos(n_printed);
|
||||
}
|
||||
|
||||
void LCD_printWord(uint32_t word)
|
||||
{
|
||||
volatile uint32_t *LCD;
|
||||
|
||||
LCD = (volatile uint32_t *)(LCD_ADDRESS + LCD_position);
|
||||
*LCD = word;
|
||||
LCD_incrPos(4);
|
||||
}
|
||||
|
||||
void LCD_printString(char *string)
|
||||
{
|
||||
volatile char *LCD;
|
||||
int i = 0;
|
||||
|
||||
LCD = (volatile char *)(LCD_ADDRESS + LCD_position);
|
||||
|
||||
while (string[i] != '\0') {
|
||||
LCD[i] = string[i];
|
||||
i++;
|
||||
}
|
||||
LCD_incrPos(i);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef __LCD_H__
|
||||
#define __LCD_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define LCD_ADDRESS 0x80000000
|
||||
|
||||
void LCD_clear(void);
|
||||
void LCD_setPos(uint8_t position);
|
||||
uint8_t LCD_getPos(void);
|
||||
void LCD_setAutoIncr(uint8_t incr);
|
||||
void LCD_printByte(uint8_t byte);
|
||||
void LCD_printByteHex(uint8_t byte);
|
||||
void LCD_printByteDec(uint8_t byte);
|
||||
void LCD_printWord(uint32_t word);
|
||||
void LCD_printString(char *string);
|
||||
|
||||
#endif
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#include "monitor.h"
|
||||
|
||||
void Monitor_start(void)
|
||||
{
|
||||
I2C_clear();
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_EnQ(0x40); // Configuration Register 1
|
||||
I2C_EnQ(0x1); // Enable monitoring
|
||||
I2C_transmit();
|
||||
}
|
||||
|
||||
|
||||
// Node is 0->Remote 1, 1->Local, 2->Remote 2
|
||||
uint32_t Monitor_readTemp(int node)
|
||||
{
|
||||
uint8_t reg = 0x25 + node;
|
||||
uint32_t data;
|
||||
|
||||
// Set the read register
|
||||
I2C_clear();
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_EnQ(reg);
|
||||
I2C_transmit();
|
||||
|
||||
// Receive the register
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_setReceive(1);
|
||||
I2C_receive();
|
||||
data = I2C_DeQ();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
#ifndef __MONITOR_H__
|
||||
#define __MONITOR_H__
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
#define MONITOR_BUS_ADDR 0x2C
|
||||
|
||||
void Monitor_start(void);
|
||||
uint32_t Monitor_readTemp(int node);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#include "piezo.h"
|
||||
|
||||
void Piezo_set(uint32_t count, int enable)
|
||||
{
|
||||
volatile uint32_t *Piezo = (volatile uint32_t *)PIEZO_ADDRESS;
|
||||
|
||||
if (enable) {
|
||||
*Piezo = count | 0x1000000;
|
||||
}
|
||||
else {
|
||||
*Piezo = count & ~0x1000000;
|
||||
}
|
||||
}
|
||||
|
||||
void Piezo_play(uint32_t note)
|
||||
{
|
||||
Piezo_set(note, 1);
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
#ifndef __PIEZO_H__
|
||||
#define __PIEZO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PIEZO_ADDRESS 0xA0000000
|
||||
|
||||
/* Following are defined for a 100 MHz Piezo driver */
|
||||
#define C0 3058104
|
||||
#define C1 1529052
|
||||
|
||||
#define C4 191110
|
||||
#define C4s 180388
|
||||
#define D4f C4s
|
||||
#define D4 170264
|
||||
#define D4s 160705
|
||||
#define E4f D4s
|
||||
#define E4 151685
|
||||
#define F4 143172
|
||||
#define F4s 135138
|
||||
#define G4f F4s
|
||||
#define G4 127551
|
||||
#define G4s 120395
|
||||
#define A4f G4s
|
||||
#define A4 113636
|
||||
#define A4s 107259
|
||||
#define B4f A4s
|
||||
#define B4 101239
|
||||
#define C5 95557
|
||||
#define C5s 90192
|
||||
#define D5f C5s
|
||||
#define D5 85131
|
||||
#define D5s 80354
|
||||
#define E5f D5s
|
||||
#define E5 75843
|
||||
|
||||
#define C8 11945
|
||||
|
||||
|
||||
void Piezo_set(uint32_t count, int enable);
|
||||
void Piezo_play(uint32_t note);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "uart.h"
|
||||
|
||||
void UART_disableBoot(void)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
uint32_t data;
|
||||
|
||||
data = 0x00000100;
|
||||
|
||||
*uart = data;
|
||||
}
|
||||
|
||||
uint8_t UART_readByte(void)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
uint32_t data;
|
||||
|
||||
data = *uart;
|
||||
|
||||
return (uint8_t)data;
|
||||
}
|
||||
|
||||
uint32_t UART_readMessage(void)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
|
||||
return *uart;
|
||||
}
|
||||
|
||||
void UART_writeByte(uint8_t byte)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
uint32_t data;
|
||||
|
||||
data = (uint32_t)byte;
|
||||
*uart = data;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef __UART_H__
|
||||
#define __UART_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define UART_ADDRESS 0xB0000000
|
||||
|
||||
void UART_disableBoot(void);
|
||||
uint8_t UART_readByte(void);
|
||||
uint32_t UART_readMessage(void);
|
||||
void UART_writeByte(uint8_t byte);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
###############################################################################
|
||||
# TITLE: Boot Up Code
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 19 July 2011
|
||||
# FILENAME: boot.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Initializes the global pointer and stack pointer.
|
||||
# Zeros BSS memory region and jumps to main().
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.global boot
|
||||
.ent boot
|
||||
.set noreorder
|
||||
boot:
|
||||
la $t0, _bss_start # Defined in linker script
|
||||
la $t1, _bss_end
|
||||
la $sp, _sp
|
||||
la $gp, _gp
|
||||
|
||||
$bss_clear:
|
||||
beq $t0, $t1, $cp0_setup # Loop until BSS is cleared
|
||||
nop
|
||||
sb $0, 0($t0)
|
||||
j $bss_clear
|
||||
addiu $t0, $t0, 1
|
||||
|
||||
$cp0_setup:
|
||||
la $26, $run # Load the address of $run into
|
||||
mtc0 $26, $30, 0 # the ErrorEPC
|
||||
mfc0 $26, $13, 0 # Load Cause register
|
||||
lui $27, 0x0080 # Use "special" interrupt vector
|
||||
or $26, $26, $27
|
||||
mtc0 $26, $13, 0 # Commit new Cause register
|
||||
mfc0 $26, $12, 0 # Load Status register
|
||||
lui $27, 0x0fff # Disable access to Coprocessors,
|
||||
ori $27, $27, 0xffef # Base operating mode is Kernel
|
||||
and $26, $26, $27
|
||||
ori $27, $0, 0xff01 # Enable all interrupts
|
||||
or $26, $26, $27
|
||||
mtc0 $26, $12, 0 # Commit new Status register
|
||||
|
||||
#lui $26, 0x0000 # 1ms timer (50 MHz)
|
||||
#ori $26, $26, 0xc350
|
||||
#lui $26, 0x0007 # 10ms timer (50 MHz)
|
||||
#ori $26, $26, 0xa120
|
||||
#lui $26, 0x004c # 100ms timer (50 MHz)
|
||||
#ori $26, $26, 0x4b40
|
||||
lui $26, 0x00be # 250ms timer (50 MHz)
|
||||
ori $26, 0xbc20
|
||||
#lui $26, 0x017d # 500ms timer (50 MHz)
|
||||
#ori $26, 0x7840
|
||||
#lui $26, 0x02fa # 1 sec timer (50 MHz)
|
||||
#ori $26, $26, 0xf080
|
||||
mtc0 $26, $11, 0 # Set Compare register to timer value
|
||||
|
||||
eret # Return from Reset Exception
|
||||
|
||||
$run:
|
||||
jal main
|
||||
nop
|
||||
|
||||
$done:
|
||||
j $done
|
||||
nop
|
||||
|
||||
.end boot
|
||||
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
#include "drivers/lcd.h"
|
||||
#include "drivers/piezo.h"
|
||||
|
||||
void dead_loop(void)
|
||||
{
|
||||
for (;;) {}
|
||||
}
|
||||
|
||||
void mips32_handler_AdEL(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("AdEL");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_AdES(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("AdES");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Bp(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Bp");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_CpU(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("CpU");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Ov(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Ov");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_RI(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("RI");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Sys(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Sys");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Tr(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Trap");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
/* Timer */
|
||||
void mips32_handler_HwInt5(void)
|
||||
{
|
||||
static volatile char wait = 0;
|
||||
|
||||
if (wait == 1) {
|
||||
wait++;
|
||||
Piezo_set(0, 0);
|
||||
}
|
||||
else if (wait < 1) {
|
||||
wait++;
|
||||
}
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt4(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt3(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt2(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt1(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
/* UART */
|
||||
void mips32_handler_HwInt0(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_SwInt1(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_SwInt0(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#ifndef __exception_handler_h__
|
||||
#define __exception_handler_h__
|
||||
|
||||
/* MIPS32 Exception Handlers */
|
||||
void mips32_handler_AdEL(void);
|
||||
void mips32_handler_AdES(void);
|
||||
void mips32_handler_Bp(void);
|
||||
void mips32_handler_CpU(void);
|
||||
void mips32_handler_Ov(void);
|
||||
void mips32_handler_RI(void);
|
||||
void mips32_handler_Sys(void);
|
||||
void mips32_handler_Tr(void);
|
||||
|
||||
/* MIPS32 Interrupt Handlers */
|
||||
void mips32_handler_HwInt5(void);
|
||||
void mips32_handler_HwInt4(void);
|
||||
void mips32_handler_HwInt3(void);
|
||||
void mips32_handler_HwInt2(void);
|
||||
void mips32_handler_HwInt1(void);
|
||||
void mips32_handler_HwInt0(void);
|
||||
void mips32_handler_SwInt1(void);
|
||||
void mips32_handler_SwInt0(void);
|
||||
|
||||
#endif
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
###############################################################################
|
||||
# TITLE: Exception Vectors
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 23 May 2012
|
||||
# FILENAME: exceptions.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Provides the exception vectors which jump to
|
||||
# exception-handling routines.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.set noreorder
|
||||
.set noat
|
||||
|
||||
exc_save:
|
||||
# Save all registers except k0 k1 sp ra
|
||||
addiu $sp, $sp, -112
|
||||
sw $1, 0($sp)
|
||||
sw $2, 4($sp)
|
||||
sw $3, 8($sp)
|
||||
sw $4, 12($sp)
|
||||
sw $5, 16($sp)
|
||||
sw $6, 20($sp)
|
||||
sw $7, 24($sp)
|
||||
sw $8, 28($sp)
|
||||
sw $9, 32($sp)
|
||||
sw $10, 36($sp)
|
||||
sw $11, 40($sp)
|
||||
sw $12, 44($sp)
|
||||
sw $13, 48($sp)
|
||||
sw $14, 52($sp)
|
||||
sw $15, 56($sp)
|
||||
sw $16, 60($sp)
|
||||
sw $17, 64($sp)
|
||||
sw $18, 68($sp)
|
||||
sw $19, 72($sp)
|
||||
sw $20, 76($sp)
|
||||
sw $21, 80($sp)
|
||||
sw $22, 84($sp)
|
||||
sw $23, 88($sp)
|
||||
sw $24, 92($sp)
|
||||
sw $25, 96($sp)
|
||||
sw $28, 100($sp)
|
||||
jr $ra
|
||||
sw $30, 104($sp)
|
||||
|
||||
exc_restore:
|
||||
# Restore all registers except k0 k1 sp ra
|
||||
lw $1, 0($sp)
|
||||
lw $2, 4($sp)
|
||||
lw $3, 8($sp)
|
||||
lw $4, 12($sp)
|
||||
lw $5, 16($sp)
|
||||
lw $6, 20($sp)
|
||||
lw $7, 24($sp)
|
||||
lw $8, 28($sp)
|
||||
lw $9, 32($sp)
|
||||
lw $10, 36($sp)
|
||||
lw $11, 40($sp)
|
||||
lw $12, 44($sp)
|
||||
lw $13, 48($sp)
|
||||
lw $14, 52($sp)
|
||||
lw $15, 56($sp)
|
||||
lw $16, 60($sp)
|
||||
lw $17, 64($sp)
|
||||
lw $18, 68($sp)
|
||||
lw $19, 72($sp)
|
||||
lw $20, 76($sp)
|
||||
lw $21, 80($sp)
|
||||
lw $22, 84($sp)
|
||||
lw $23, 88($sp)
|
||||
lw $24, 92($sp)
|
||||
lw $25, 96($sp)
|
||||
lw $28, 100($sp)
|
||||
lw $30, 104($sp)
|
||||
jr $ra
|
||||
addiu $sp, $sp, 112
|
||||
|
||||
|
||||
.global mips32_general_exception
|
||||
.ent mips32_general_exception
|
||||
mips32_general_exception:
|
||||
or $26, $0, $ra
|
||||
jal exc_save
|
||||
nop
|
||||
mfc0 $27, $13, 0 # Read Cause which has ExcCode bits
|
||||
srl $27, $27, 2 # Extract exception code to $k1
|
||||
andi $27, $27, 0x001f
|
||||
|
||||
la $ra, $end_exception # Jump to the appropriate handler
|
||||
addiu $t0, $0, 4
|
||||
addiu $t1, $0, 5
|
||||
addiu $t2, $0, 8
|
||||
addiu $t3, $0, 9
|
||||
beq $t0, $27, mips32_handler_AdEL
|
||||
addiu $t0, $0, 10
|
||||
beq $t1, $27, mips32_handler_AdES
|
||||
addiu $t1, $0, 11
|
||||
beq $t2, $27, mips32_handler_Sys
|
||||
addiu $t2, $0, 12
|
||||
beq $t3, $27, mips32_handler_Bp
|
||||
addiu $t3, $0, 13
|
||||
beq $t0, $27, mips32_handler_RI
|
||||
nop
|
||||
beq $t1, $27, mips32_handler_CpU
|
||||
nop
|
||||
beq $t2, $27, mips32_handler_Ov
|
||||
nop
|
||||
beq $t3, $27, mips32_handler_Tr
|
||||
nop
|
||||
|
||||
$end_exception:
|
||||
jal exc_restore
|
||||
xor $27, $0, $0
|
||||
or $ra, $0, $26
|
||||
xor $26, $0, $0
|
||||
eret
|
||||
.end mips32_general_exception
|
||||
|
||||
|
||||
|
||||
### "Special" Interrupt Vector: Cause_IV must be set.
|
||||
|
||||
.ent mips32_interrupt_exception
|
||||
.global mips32_interrupt_exception
|
||||
mips32_interrupt_exception:
|
||||
mfc0 $26, $12, 0 # Status register for IM bits
|
||||
mfc0 $27, $13, 0 # Cause register for IP bits
|
||||
and $26, $26, $27 # Extract pending, unmasked interrupts
|
||||
srl $26, $26, 8
|
||||
andi $26, $26, 0x00ff
|
||||
|
||||
addu $27, $0, $ra
|
||||
jal exc_save
|
||||
clz $26, $26
|
||||
la $ra, $end_interrupt # All C functions will return here
|
||||
addiu $t0, $0, 24
|
||||
addiu $t1, $0, 25
|
||||
addiu $t2, $0, 26
|
||||
beq $26, $t0, mips32_handler_HwInt5
|
||||
addiu $t0, $0, 27
|
||||
beq $26, $t1, mips32_handler_HwInt4
|
||||
addiu $t1, $0, 28
|
||||
beq $26, $t2, mips32_handler_HwInt3
|
||||
addiu $t2, $0, 29
|
||||
beq $26, $t0, mips32_handler_HwInt2
|
||||
addiu $t0, $0, 30
|
||||
beq $26, $t1, mips32_handler_HwInt1
|
||||
addiu $t1, $0, 31
|
||||
beq $26, $t2, mips32_handler_HwInt0
|
||||
nop
|
||||
beq $26, $t0, mips32_handler_SwInt1
|
||||
nop
|
||||
beq $26, $t1, mips32_handler_SwInt0
|
||||
nop
|
||||
|
||||
|
||||
$end_interrupt:
|
||||
jal exc_restore
|
||||
mfc0 $26, $9, 0 # Clear HwInt5 if applicable
|
||||
or $ra, $0, $27
|
||||
eret
|
||||
.end mips32_interrupt_exception
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
###############################################################################
|
||||
# TITLE: Exception Vectors
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 23 May 2012
|
||||
# FILENAME: exceptions.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Provides the exception vectors which jump to
|
||||
# exception-handling routines.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
# Current setup:
|
||||
# 1. The exception vector begins at address 0x0.
|
||||
# 2. The interrupt vector begins at address 0x8.
|
||||
# 3. Each vector has room for 2 instructions (8 bytes) with which
|
||||
# it must jump to its demultiplexing routine. The demultiplexing
|
||||
# routine calls individual exception-specific handlers.
|
||||
# 4. The linker script must ensure that this code is placed at the
|
||||
# correct address.
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.ent exception_vector
|
||||
.set noreorder
|
||||
exception_vector:
|
||||
j mips32_general_exception
|
||||
nop
|
||||
.end exception_vector
|
||||
|
||||
|
||||
.ent interrupt_vector
|
||||
interrupt_vector:
|
||||
j mips32_interrupt_exception
|
||||
nop
|
||||
.end interrupt_vector
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Linker script for MIPS32 (Single Core) FPGA, intended for XUM */
|
||||
|
||||
|
||||
/* Entry Point
|
||||
*
|
||||
* Set it to be the label "boot" (likely in boot.asm)
|
||||
*
|
||||
*/
|
||||
/*ENTRY(boot)*/
|
||||
|
||||
|
||||
/* Memory Section
|
||||
*
|
||||
* The FPGA currently uses one region of Block RAM, which is 592 KB.
|
||||
*
|
||||
* Instruction Memory starts at address 0.
|
||||
*
|
||||
* Data Memory ends 592KB later, at address 0x00094000 (the last
|
||||
* usable word address is 0x00093ffc).
|
||||
*
|
||||
* Instructions : 0x00000000 -> 0x0000fffc ( 64KB)
|
||||
* Data / BSS : 0x00001000 -> 0x00017ffc ( 32KB)
|
||||
* Stack / Heap : 0x00018000 -> 0x00093ffc (496KB)
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* Sections
|
||||
*
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
_sp = 0x00094000;
|
||||
|
||||
. = 0 ;
|
||||
|
||||
.text :
|
||||
{
|
||||
vectors.o(.text)
|
||||
. = 0x10 ;
|
||||
boot.o(.text)
|
||||
exceptions.o(.text)
|
||||
*(.*text*)
|
||||
}
|
||||
|
||||
. = 0x00001000 ;
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.rodata*)
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
_gp = ALIGN(16) + 0x7ff0;
|
||||
|
||||
.got :
|
||||
{
|
||||
*(.got)
|
||||
}
|
||||
|
||||
.sdata :
|
||||
{
|
||||
*(.*sdata*)
|
||||
}
|
||||
|
||||
_bss_start = . ;
|
||||
|
||||
.sbss :
|
||||
{
|
||||
*(.*sbss)
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.*bss)
|
||||
}
|
||||
|
||||
_bss_end = . ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
README for XUM Demo 4 : UART (Serial Port)
|
||||
------------------------------------------
|
||||
|
||||
Creator: Grant Ayers (ayers@cs.utah.edu)
|
||||
Date: 26 July 2012
|
||||
|
||||
|
||||
|
||||
DEMONSTRATES
|
||||
------------
|
||||
|
||||
UART, Interrupts, LCD.
|
||||
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Prints text that is received by the serial port to the LCD screen. The
|
||||
screen has a blinking cursor which is toggled by the timer interrupt.
|
||||
The UART utilizes a hardware interrupt to notify the processor of incoming
|
||||
data. The backspace key moves the cursor backward one character.
|
||||
|
||||
Connect to the FPGA using 115200 Baud, 1 stop bit, no parity, and no flow
|
||||
control. Use a program such as Minicom in Linux or Putty in Windows.
|
||||
|
||||
|
||||
|
||||
BUILDING AND RUNNING
|
||||
--------------------
|
||||
|
||||
To compile, enter the 'bin' directory and update the paths in the Makefile.
|
||||
Then run 'make' from within the same directory. Use the XUM bootloader to
|
||||
send the resulting .xum file to the FPGA.
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
# Makefile for XUM
|
||||
#
|
||||
# Compiles code to run on the XUM platform, which
|
||||
# is based on MIPS32 and a GCC cross-compiler toolchain.
|
||||
#
|
||||
# Author: Grant Ayers (ayers@cs.utah.edu)
|
||||
# Date: 3 July 2012
|
||||
#
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
SRC = ../src
|
||||
MIPS_PREFIX = /home/User/XUM/gnu_mips/crosstools
|
||||
MIPS_BIN = $(MIPS_PREFIX)/bin
|
||||
MIPS_LIB = $(MIPS_PREFIX)/mips-elf/lib
|
||||
MIPS_CC = $(MIPS_BIN)/mips-elf-gcc-4.7.1.exe
|
||||
MIPS_AS = $(MIPS_BIN)/mips-elf-as.exe
|
||||
MIPS_LD = $(MIPS_BIN)/mips-elf-ld.exe
|
||||
MIPS_OBJDUMP = $(MIPS_BIN)/mips-elf-objdump.exe
|
||||
MIPS_OBJCOPY = $(MIPS_BIN)/mips-elf-objcopy.exe
|
||||
UTIL_PREFIX = /home/User/XUM/demos/util
|
||||
UTIL_CONVBIN = $(UTIL_PREFIX)/bintohex.exe
|
||||
UTIL_CONVXUM = $(UTIL_PREFIX)/bintoxum.exe
|
||||
|
||||
AS_FLAGS = -march=mips32 -EB -G0
|
||||
LD_FLAGS = -EB -static -Map app.map -T ../src/os/xum.ls
|
||||
LD_LIBS = -lm -lc -lgcc
|
||||
LD_SEARCH = -L$(MIPS_PREFIX)/mips-elf/lib \
|
||||
-L$(MIPS_PREFIX)/lib/gcc/mips-elf/4.7.1
|
||||
LD_DRIVER = $(MIPS_LD) $(LD_FLAGS) $(LD_SEARCH) $(LD_LIBS)
|
||||
CC_FLAGS_ARCH = -march=mips32 -EB -msoft-float -mno-mips16 -mno-branch-likely \
|
||||
-mgpopt
|
||||
CC_FLAGS_LANG = -Wall -O2
|
||||
CC_FLAGS_INC = -I../src/
|
||||
CC_FLAGS_AS = -Wa,-EB,-mips32,-msoft-float
|
||||
CC_FLAGS_LD = -nostdlib -nostartfiles -static -T ../src/os/xum.ls
|
||||
CC_FLAGS_LIB = -lm -lc -lgcc
|
||||
CC_DRIVER = $(MIPS_CC) $(CC_FLAGS_ARCH) $(CC_FLAGS_LANG) \
|
||||
$(CC_FLAGS_AS) $(CC_FLAGS_INC)
|
||||
|
||||
|
||||
all : app
|
||||
|
||||
app : app.o uart.o lcd.o boot.o vectors.o exceptions.o exception_handler.o piezo.o
|
||||
$(LD_DRIVER) $^ -o app.exe
|
||||
@$(MIPS_OBJDUMP) -EB --disassemble app.exe > app.lst
|
||||
@$(MIPS_OBJCOPY) -O binary -j .text app.exe app-code.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .data app.exe app-data1.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .sdata app.exe app-data2.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .sbss app.exe app-data3.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .bss app.exe app-data4.bin
|
||||
@cat app-data1.bin app-data2.bin app-data3.bin app-data4.bin >> app-data.bin
|
||||
@$(UTIL_CONVXUM) -d 4096 app-code.bin app-data.bin app.xum
|
||||
#@$(UTIL_CONVBIN) -c -b app-code.bin app-code.coe
|
||||
$(UTIL_CONVBIN) -c -b app.xum app.coe
|
||||
|
||||
|
||||
|
||||
app.o : $(SRC)/app/app.c
|
||||
$(CC_DRIVER) -c $(SRC)/app/app.c -o app.o
|
||||
|
||||
uart.o : $(SRC)/drivers/uart.c $(SRC)/drivers/uart.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/uart.c -o uart.o
|
||||
|
||||
i2c.o : $(SRC)/drivers/i2c.c $(SRC)/drivers/i2c.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/i2c.c -o i2c.o
|
||||
|
||||
lcd.o : $(SRC)/drivers/lcd.c $(SRC)/drivers/lcd.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/lcd.c -o lcd.o
|
||||
|
||||
monitor.o : $(SRC)/drivers/monitor.c $(SRC)/drivers/monitor.h i2c.o
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/monitor.c -o monitor.o
|
||||
|
||||
piezo.o : $(SRC)/drivers/piezo.c $(SRC)/drivers/piezo.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/piezo.c -o piezo.o
|
||||
|
||||
exception_handler.o : $(SRC)/os/exception_handler.c $(SRC)/os/exception_handler.h lcd.o piezo.o monitor.o
|
||||
$(CC_DRIVER) -c $(SRC)/os/exception_handler.c -o exception_handler.o
|
||||
|
||||
boot.o : $(SRC)/os/boot.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o boot.o $(SRC)/os/boot.asm
|
||||
|
||||
vectors.o : $(SRC)/os/vectors.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o vectors.o $(SRC)/os/vectors.asm
|
||||
|
||||
exceptions.o : $(SRC)/os/exceptions.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o exceptions.o $(SRC)/os/exceptions.asm
|
||||
|
||||
clean :
|
||||
rm -f *.o *.exe *.map *.coe *.bin *.map *.xum *.lst
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
#include "drivers/piezo.h"
|
||||
#include "drivers/lcd.h"
|
||||
#include "drivers/uart.h"
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Piezo_play(C5);
|
||||
LCD_clear();
|
||||
UART_disableBoot();
|
||||
|
||||
while (1) {};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "i2c.h"
|
||||
|
||||
void I2C_clear(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
uint32_t cmd = (1 << 8);
|
||||
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_EnQ(uint8_t byte)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 9) | (uint32_t)byte;
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_transmit(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 10);
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_setReceive(uint8_t bytes)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 12) | (uint32_t)bytes;
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_receive(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 11);
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
uint32_t I2C_DeQ(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t data = *i2c;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef __I2C_H__
|
||||
#define __I2C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define I2C_ADDRESS 0x90000000
|
||||
|
||||
void I2C_clear(void);
|
||||
void I2C_EnQ(uint8_t byte);
|
||||
void I2C_transmit(void);
|
||||
void I2C_setReceive(uint8_t bytes);
|
||||
void I2C_receive(void);
|
||||
uint32_t I2C_DeQ(void);
|
||||
|
||||
#endif
|
||||
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
#include "lcd.h"
|
||||
|
||||
static uint8_t LCD_position = 0;
|
||||
static uint8_t LCD_autoIncr = 1;
|
||||
|
||||
static void LCD_incrPos(uint32_t amount)
|
||||
{
|
||||
if (LCD_autoIncr == 0) {
|
||||
return;
|
||||
}
|
||||
while (amount > 32) {
|
||||
amount -= 32;
|
||||
}
|
||||
LCD_position += (uint8_t)amount;
|
||||
if (LCD_position >= 32) {
|
||||
LCD_position -= 32;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCD_clear(void)
|
||||
{
|
||||
volatile uint32_t *LCD;
|
||||
int i;
|
||||
|
||||
LCD = (volatile uint32_t *)LCD_ADDRESS;
|
||||
|
||||
for (i=0; i<8; i++) {
|
||||
LCD[i] = 0x20202020;
|
||||
}
|
||||
LCD_position = 0;
|
||||
}
|
||||
|
||||
void LCD_setPos(uint8_t position)
|
||||
{
|
||||
LCD_position = position;
|
||||
}
|
||||
|
||||
uint8_t LCD_getPos(void)
|
||||
{
|
||||
return LCD_position;
|
||||
}
|
||||
|
||||
void LCD_setAutoIncr(uint8_t incr)
|
||||
{
|
||||
LCD_autoIncr = incr;
|
||||
}
|
||||
|
||||
void LCD_printByte(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
*LCD = byte;
|
||||
LCD_incrPos(1);
|
||||
}
|
||||
|
||||
void LCD_printByteHex(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
uint8_t nibble_h, nibble_l;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
nibble_h = byte >> 4;
|
||||
nibble_l = byte & 0x0f;
|
||||
|
||||
if (nibble_h < 10) {
|
||||
nibble_h += 48;
|
||||
}
|
||||
else {
|
||||
nibble_h += 55;
|
||||
}
|
||||
if (nibble_l < 10) {
|
||||
nibble_l += 48;
|
||||
}
|
||||
else {
|
||||
nibble_h += 55;
|
||||
}
|
||||
*LCD = nibble_h;
|
||||
LCD++;
|
||||
*LCD = nibble_l;
|
||||
LCD_incrPos(2);
|
||||
}
|
||||
|
||||
void LCD_printByteDec(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
uint8_t hundreds, tens, ones;
|
||||
uint32_t n_printed = 1;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
hundreds = tens = ones = 48;
|
||||
|
||||
while (byte >= 100) {
|
||||
hundreds++;
|
||||
byte -= 100;
|
||||
}
|
||||
while (byte >= 10) {
|
||||
tens++;
|
||||
byte -= 10;
|
||||
}
|
||||
while (byte >= 1) {
|
||||
ones++;
|
||||
byte -= 1;
|
||||
}
|
||||
if (hundreds > 48) {
|
||||
*LCD = hundreds;
|
||||
LCD++;
|
||||
n_printed++;
|
||||
}
|
||||
if ((n_printed > 1) || (tens > 48)) {
|
||||
*LCD = tens;
|
||||
LCD++;
|
||||
n_printed++;
|
||||
}
|
||||
*LCD = ones;
|
||||
LCD_incrPos(n_printed);
|
||||
}
|
||||
|
||||
void LCD_printWord(uint32_t word)
|
||||
{
|
||||
volatile uint32_t *LCD;
|
||||
|
||||
LCD = (volatile uint32_t *)(LCD_ADDRESS + LCD_position);
|
||||
*LCD = word;
|
||||
LCD_incrPos(4);
|
||||
}
|
||||
|
||||
void LCD_printString(char *string)
|
||||
{
|
||||
volatile char *LCD;
|
||||
int i = 0;
|
||||
|
||||
LCD = (volatile char *)(LCD_ADDRESS + LCD_position);
|
||||
|
||||
while (string[i] != '\0') {
|
||||
LCD[i] = string[i];
|
||||
i++;
|
||||
}
|
||||
LCD_incrPos(i);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef __LCD_H__
|
||||
#define __LCD_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define LCD_ADDRESS 0x80000000
|
||||
|
||||
void LCD_clear(void);
|
||||
void LCD_setPos(uint8_t position);
|
||||
uint8_t LCD_getPos(void);
|
||||
void LCD_setAutoIncr(uint8_t incr);
|
||||
void LCD_printByte(uint8_t byte);
|
||||
void LCD_printByteHex(uint8_t byte);
|
||||
void LCD_printByteDec(uint8_t byte);
|
||||
void LCD_printWord(uint32_t word);
|
||||
void LCD_printString(char *string);
|
||||
|
||||
#endif
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#include "monitor.h"
|
||||
|
||||
void Monitor_start(void)
|
||||
{
|
||||
I2C_clear();
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_EnQ(0x40); // Configuration Register 1
|
||||
I2C_EnQ(0x1); // Enable monitoring
|
||||
I2C_transmit();
|
||||
}
|
||||
|
||||
|
||||
// Node is 0->Remote 1, 1->Local, 2->Remote 2
|
||||
uint32_t Monitor_readTemp(int node)
|
||||
{
|
||||
uint8_t reg = 0x25 + node;
|
||||
uint32_t data;
|
||||
|
||||
// Set the read register
|
||||
I2C_clear();
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_EnQ(reg);
|
||||
I2C_transmit();
|
||||
|
||||
// Receive the register
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_setReceive(1);
|
||||
I2C_receive();
|
||||
data = I2C_DeQ();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
#ifndef __MONITOR_H__
|
||||
#define __MONITOR_H__
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
#define MONITOR_BUS_ADDR 0x2C
|
||||
|
||||
void Monitor_start(void);
|
||||
uint32_t Monitor_readTemp(int node);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#include "piezo.h"
|
||||
|
||||
void Piezo_set(uint32_t count, int enable)
|
||||
{
|
||||
volatile uint32_t *Piezo = (volatile uint32_t *)PIEZO_ADDRESS;
|
||||
|
||||
if (enable) {
|
||||
*Piezo = count | 0x1000000;
|
||||
}
|
||||
else {
|
||||
*Piezo = count & ~0x1000000;
|
||||
}
|
||||
}
|
||||
|
||||
void Piezo_play(uint32_t note)
|
||||
{
|
||||
Piezo_set(note, 1);
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
#ifndef __PIEZO_H__
|
||||
#define __PIEZO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PIEZO_ADDRESS 0xA0000000
|
||||
|
||||
/* Following are defined for a 100 MHz Piezo driver */
|
||||
#define C0 3058104
|
||||
#define C1 1529052
|
||||
|
||||
#define C4 191110
|
||||
#define C4s 180388
|
||||
#define D4f C4s
|
||||
#define D4 170264
|
||||
#define D4s 160705
|
||||
#define E4f D4s
|
||||
#define E4 151685
|
||||
#define F4 143172
|
||||
#define F4s 135138
|
||||
#define G4f F4s
|
||||
#define G4 127551
|
||||
#define G4s 120395
|
||||
#define A4f G4s
|
||||
#define A4 113636
|
||||
#define A4s 107259
|
||||
#define B4f A4s
|
||||
#define B4 101239
|
||||
#define C5 95557
|
||||
#define C5s 90192
|
||||
#define D5f C5s
|
||||
#define D5 85131
|
||||
#define D5s 80354
|
||||
#define E5f D5s
|
||||
#define E5 75843
|
||||
|
||||
#define C8 11945
|
||||
|
||||
|
||||
void Piezo_set(uint32_t count, int enable);
|
||||
void Piezo_play(uint32_t note);
|
||||
|
||||
#endif
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#include "uart.h"
|
||||
|
||||
void UART_disableBoot(void)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
uint32_t data;
|
||||
|
||||
data = 0x00000100;
|
||||
|
||||
*uart = data;
|
||||
}
|
||||
|
||||
uint8_t UART_readByte(void)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
uint32_t data;
|
||||
|
||||
data = *uart;
|
||||
|
||||
return (uint8_t)data;
|
||||
}
|
||||
|
||||
uint32_t UART_readMessage(void)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
|
||||
return *uart;
|
||||
}
|
||||
|
||||
void UART_writeByte(uint8_t byte)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
uint32_t data;
|
||||
|
||||
data = (uint32_t)byte;
|
||||
*uart = data;
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#ifndef __UART_H__
|
||||
#define __UART_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define UART_ADDRESS 0xB0000000
|
||||
|
||||
void UART_disableBoot(void);
|
||||
uint8_t UART_readByte(void);
|
||||
uint32_t UART_readMessage(void);
|
||||
void UART_writeByte(uint8_t byte);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
###############################################################################
|
||||
# TITLE: Boot Up Code
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 19 July 2011
|
||||
# FILENAME: boot.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Initializes the global pointer and stack pointer.
|
||||
# Zeros BSS memory region and jumps to main().
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.global boot
|
||||
.ent boot
|
||||
.set noreorder
|
||||
boot:
|
||||
la $t0, _bss_start # Defined in linker script
|
||||
la $t1, _bss_end
|
||||
la $sp, _sp
|
||||
la $gp, _gp
|
||||
|
||||
$bss_clear:
|
||||
beq $t0, $t1, $cp0_setup # Loop until BSS is cleared
|
||||
nop
|
||||
sb $0, 0($t0)
|
||||
j $bss_clear
|
||||
addiu $t0, $t0, 1
|
||||
|
||||
$cp0_setup:
|
||||
la $26, $run # Load the address of $run into
|
||||
mtc0 $26, $30, 0 # the ErrorEPC
|
||||
mfc0 $26, $13, 0 # Load Cause register
|
||||
lui $27, 0x0080 # Use "special" interrupt vector
|
||||
or $26, $26, $27
|
||||
mtc0 $26, $13, 0 # Commit new Cause register
|
||||
mfc0 $26, $12, 0 # Load Status register
|
||||
lui $27, 0x0fff # Disable access to Coprocessors,
|
||||
ori $27, $27, 0xffef # Base operating mode is Kernel
|
||||
and $26, $26, $27
|
||||
ori $27, $0, 0xff01 # Enable all interrupts
|
||||
or $26, $26, $27
|
||||
mtc0 $26, $12, 0 # Commit new Status register
|
||||
|
||||
#lui $26, 0x0000 # 1ms timer (50 MHz)
|
||||
#ori $26, $26, 0xc350
|
||||
#lui $26, 0x0007 # 10ms timer (50 MHz)
|
||||
#ori $26, $26, 0xa120
|
||||
#lui $26, 0x004c # 100ms timer (50 MHz)
|
||||
#ori $26, $26, 0x4b40
|
||||
lui $26, 0x00be # 250ms timer (50 MHz)
|
||||
ori $26, 0xbc20
|
||||
#lui $26, 0x017d # 500ms timer (50 MHz)
|
||||
#ori $26, 0x7840
|
||||
#lui $26, 0x02fa # 1 sec timer (50 MHz)
|
||||
#ori $26, $26, 0xf080
|
||||
mtc0 $26, $11, 0 # Set Compare register to timer value
|
||||
|
||||
eret # Return from Reset Exception
|
||||
|
||||
$run:
|
||||
jal main
|
||||
nop
|
||||
|
||||
$done:
|
||||
j $done
|
||||
nop
|
||||
|
||||
.end boot
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
#include "drivers/lcd.h"
|
||||
#include "drivers/piezo.h"
|
||||
#include "drivers/monitor.h"
|
||||
#include "drivers/uart.h"
|
||||
|
||||
void dead_loop(void)
|
||||
{
|
||||
for (;;) {}
|
||||
}
|
||||
|
||||
void mips32_handler_AdEL(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("AdEL");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_AdES(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("AdES");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Bp(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Bp");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_CpU(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("CpU");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Ov(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Ov");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_RI(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("RI");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Sys(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Sys");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Tr(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Trap");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
/* Timer */
|
||||
void mips32_handler_HwInt5(void)
|
||||
{
|
||||
static volatile char wait = 0;
|
||||
static volatile uint8_t cursor = 0x20;
|
||||
|
||||
if (wait == 1) {
|
||||
wait++;
|
||||
Piezo_set(0, 0);
|
||||
}
|
||||
else if (wait < 1) {
|
||||
wait++;
|
||||
}
|
||||
|
||||
LCD_setAutoIncr(0);
|
||||
LCD_printByte(cursor);
|
||||
LCD_setAutoIncr(1);
|
||||
|
||||
if (cursor == 0x20) {
|
||||
cursor = 0xff;
|
||||
}
|
||||
else {
|
||||
cursor = 0x20;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt4(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt3(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt2(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt1(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
/* UART */
|
||||
void mips32_handler_HwInt0(void)
|
||||
{
|
||||
uint32_t recv_msg;
|
||||
uint32_t bytes_avail;
|
||||
uint8_t read_byte;
|
||||
|
||||
recv_msg = UART_readMessage();
|
||||
read_byte = (uint8_t)recv_msg;
|
||||
bytes_avail = (recv_msg >> 8);
|
||||
|
||||
while (bytes_avail > 0) {
|
||||
if (read_byte == 0x7f) { // delete
|
||||
LCD_setAutoIncr(0);
|
||||
LCD_printByte(0x20);
|
||||
LCD_setPos(LCD_getPos()-1);
|
||||
LCD_setAutoIncr(1);
|
||||
}
|
||||
else {
|
||||
LCD_printByte(read_byte);
|
||||
}
|
||||
bytes_avail--;
|
||||
read_byte = UART_readByte();
|
||||
}
|
||||
}
|
||||
|
||||
void mips32_handler_SwInt1(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_SwInt0(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#ifndef __exception_handler_h__
|
||||
#define __exception_handler_h__
|
||||
|
||||
/* MIPS32 Exception Handlers */
|
||||
void mips32_handler_AdEL(void);
|
||||
void mips32_handler_AdES(void);
|
||||
void mips32_handler_Bp(void);
|
||||
void mips32_handler_CpU(void);
|
||||
void mips32_handler_Ov(void);
|
||||
void mips32_handler_RI(void);
|
||||
void mips32_handler_Sys(void);
|
||||
void mips32_handler_Tr(void);
|
||||
|
||||
/* MIPS32 Interrupt Handlers */
|
||||
void mips32_handler_HwInt5(void);
|
||||
void mips32_handler_HwInt4(void);
|
||||
void mips32_handler_HwInt3(void);
|
||||
void mips32_handler_HwInt2(void);
|
||||
void mips32_handler_HwInt1(void);
|
||||
void mips32_handler_HwInt0(void);
|
||||
void mips32_handler_SwInt1(void);
|
||||
void mips32_handler_SwInt0(void);
|
||||
|
||||
#endif
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
###############################################################################
|
||||
# TITLE: Exception Vectors
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 23 May 2012
|
||||
# FILENAME: exceptions.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Provides the exception vectors which jump to
|
||||
# exception-handling routines.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.set noreorder
|
||||
.set noat
|
||||
|
||||
exc_save:
|
||||
# Save all registers except k0 k1 sp ra
|
||||
addiu $sp, $sp, -112
|
||||
sw $1, 0($sp)
|
||||
sw $2, 4($sp)
|
||||
sw $3, 8($sp)
|
||||
sw $4, 12($sp)
|
||||
sw $5, 16($sp)
|
||||
sw $6, 20($sp)
|
||||
sw $7, 24($sp)
|
||||
sw $8, 28($sp)
|
||||
sw $9, 32($sp)
|
||||
sw $10, 36($sp)
|
||||
sw $11, 40($sp)
|
||||
sw $12, 44($sp)
|
||||
sw $13, 48($sp)
|
||||
sw $14, 52($sp)
|
||||
sw $15, 56($sp)
|
||||
sw $16, 60($sp)
|
||||
sw $17, 64($sp)
|
||||
sw $18, 68($sp)
|
||||
sw $19, 72($sp)
|
||||
sw $20, 76($sp)
|
||||
sw $21, 80($sp)
|
||||
sw $22, 84($sp)
|
||||
sw $23, 88($sp)
|
||||
sw $24, 92($sp)
|
||||
sw $25, 96($sp)
|
||||
sw $28, 100($sp)
|
||||
jr $ra
|
||||
sw $30, 104($sp)
|
||||
|
||||
exc_restore:
|
||||
# Restore all registers except k0 k1 sp ra
|
||||
lw $1, 0($sp)
|
||||
lw $2, 4($sp)
|
||||
lw $3, 8($sp)
|
||||
lw $4, 12($sp)
|
||||
lw $5, 16($sp)
|
||||
lw $6, 20($sp)
|
||||
lw $7, 24($sp)
|
||||
lw $8, 28($sp)
|
||||
lw $9, 32($sp)
|
||||
lw $10, 36($sp)
|
||||
lw $11, 40($sp)
|
||||
lw $12, 44($sp)
|
||||
lw $13, 48($sp)
|
||||
lw $14, 52($sp)
|
||||
lw $15, 56($sp)
|
||||
lw $16, 60($sp)
|
||||
lw $17, 64($sp)
|
||||
lw $18, 68($sp)
|
||||
lw $19, 72($sp)
|
||||
lw $20, 76($sp)
|
||||
lw $21, 80($sp)
|
||||
lw $22, 84($sp)
|
||||
lw $23, 88($sp)
|
||||
lw $24, 92($sp)
|
||||
lw $25, 96($sp)
|
||||
lw $28, 100($sp)
|
||||
lw $30, 104($sp)
|
||||
jr $ra
|
||||
addiu $sp, $sp, 112
|
||||
|
||||
|
||||
.global mips32_general_exception
|
||||
.ent mips32_general_exception
|
||||
mips32_general_exception:
|
||||
or $26, $0, $ra
|
||||
jal exc_save
|
||||
nop
|
||||
mfc0 $27, $13, 0 # Read Cause which has ExcCode bits
|
||||
srl $27, $27, 2 # Extract exception code to $k1
|
||||
andi $27, $27, 0x001f
|
||||
|
||||
la $ra, $end_exception # Jump to the appropriate handler
|
||||
addiu $t0, $0, 4
|
||||
addiu $t1, $0, 5
|
||||
addiu $t2, $0, 8
|
||||
addiu $t3, $0, 9
|
||||
beq $t0, $27, mips32_handler_AdEL
|
||||
addiu $t0, $0, 10
|
||||
beq $t1, $27, mips32_handler_AdES
|
||||
addiu $t1, $0, 11
|
||||
beq $t2, $27, mips32_handler_Sys
|
||||
addiu $t2, $0, 12
|
||||
beq $t3, $27, mips32_handler_Bp
|
||||
addiu $t3, $0, 13
|
||||
beq $t0, $27, mips32_handler_RI
|
||||
nop
|
||||
beq $t1, $27, mips32_handler_CpU
|
||||
nop
|
||||
beq $t2, $27, mips32_handler_Ov
|
||||
nop
|
||||
beq $t3, $27, mips32_handler_Tr
|
||||
nop
|
||||
|
||||
$end_exception:
|
||||
jal exc_restore
|
||||
xor $27, $0, $0
|
||||
or $ra, $0, $26
|
||||
xor $26, $0, $0
|
||||
eret
|
||||
.end mips32_general_exception
|
||||
|
||||
|
||||
|
||||
### "Special" Interrupt Vector: Cause_IV must be set.
|
||||
|
||||
.ent mips32_interrupt_exception
|
||||
.global mips32_interrupt_exception
|
||||
mips32_interrupt_exception:
|
||||
mfc0 $26, $12, 0 # Status register for IM bits
|
||||
mfc0 $27, $13, 0 # Cause register for IP bits
|
||||
and $26, $26, $27 # Extract pending, unmasked interrupts
|
||||
srl $26, $26, 8
|
||||
andi $26, $26, 0x00ff
|
||||
|
||||
addu $27, $0, $ra
|
||||
jal exc_save
|
||||
clz $26, $26
|
||||
la $ra, $end_interrupt # All C functions will return here
|
||||
addiu $t0, $0, 24
|
||||
addiu $t1, $0, 25
|
||||
addiu $t2, $0, 26
|
||||
beq $26, $t0, mips32_handler_HwInt5
|
||||
addiu $t0, $0, 27
|
||||
beq $26, $t1, mips32_handler_HwInt4
|
||||
addiu $t1, $0, 28
|
||||
beq $26, $t2, mips32_handler_HwInt3
|
||||
addiu $t2, $0, 29
|
||||
beq $26, $t0, mips32_handler_HwInt2
|
||||
addiu $t0, $0, 30
|
||||
beq $26, $t1, mips32_handler_HwInt1
|
||||
addiu $t1, $0, 31
|
||||
beq $26, $t2, mips32_handler_HwInt0
|
||||
nop
|
||||
beq $26, $t0, mips32_handler_SwInt1
|
||||
nop
|
||||
beq $26, $t1, mips32_handler_SwInt0
|
||||
nop
|
||||
|
||||
|
||||
$end_interrupt:
|
||||
jal exc_restore
|
||||
mfc0 $26, $9, 0 # Clear HwInt5 if applicable
|
||||
or $ra, $0, $27
|
||||
eret
|
||||
.end mips32_interrupt_exception
|
||||
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
###############################################################################
|
||||
# TITLE: Exception Vectors
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 23 May 2012
|
||||
# FILENAME: exceptions.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Provides the exception vectors which jump to
|
||||
# exception-handling routines.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
# Current setup:
|
||||
# 1. The exception vector begins at address 0x0.
|
||||
# 2. The interrupt vector begins at address 0x8.
|
||||
# 3. Each vector has room for 2 instructions (8 bytes) with which
|
||||
# it must jump to its demultiplexing routine. The demultiplexing
|
||||
# routine calls individual exception-specific handlers.
|
||||
# 4. The linker script must ensure that this code is placed at the
|
||||
# correct address.
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.ent exception_vector
|
||||
.set noreorder
|
||||
exception_vector:
|
||||
j mips32_general_exception
|
||||
nop
|
||||
.end exception_vector
|
||||
|
||||
|
||||
.ent interrupt_vector
|
||||
interrupt_vector:
|
||||
j mips32_interrupt_exception
|
||||
nop
|
||||
.end interrupt_vector
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Linker script for MIPS32 (Single Core) FPGA, intended for XUM */
|
||||
|
||||
|
||||
/* Entry Point
|
||||
*
|
||||
* Set it to be the label "boot" (likely in boot.asm)
|
||||
*
|
||||
*/
|
||||
/*ENTRY(boot)*/
|
||||
|
||||
|
||||
/* Memory Section
|
||||
*
|
||||
* The FPGA currently uses one region of Block RAM, which is 592 KB.
|
||||
*
|
||||
* Instruction Memory starts at address 0.
|
||||
*
|
||||
* Data Memory ends 592KB later, at address 0x00094000 (the last
|
||||
* usable word address is 0x00093ffc).
|
||||
*
|
||||
* Instructions : 0x00000000 -> 0x0000fffc ( 64KB)
|
||||
* Data / BSS : 0x00001000 -> 0x00017ffc ( 32KB)
|
||||
* Stack / Heap : 0x00018000 -> 0x00093ffc (496KB)
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* Sections
|
||||
*
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
_sp = 0x00094000;
|
||||
|
||||
. = 0 ;
|
||||
|
||||
.text :
|
||||
{
|
||||
vectors.o(.text)
|
||||
. = 0x10 ;
|
||||
boot.o(.text)
|
||||
exceptions.o(.text)
|
||||
*(.*text*)
|
||||
}
|
||||
|
||||
. = 0x00001000 ;
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.rodata*)
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
_gp = ALIGN(16) + 0x7ff0;
|
||||
|
||||
.got :
|
||||
{
|
||||
*(.got)
|
||||
}
|
||||
|
||||
.sdata :
|
||||
{
|
||||
*(.*sdata*)
|
||||
}
|
||||
|
||||
_bss_start = . ;
|
||||
|
||||
.sbss :
|
||||
{
|
||||
*(.*sbss)
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.*bss)
|
||||
}
|
||||
|
||||
_bss_end = . ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
README for XUM Demo 5 : Threads
|
||||
-------------------------------
|
||||
|
||||
Creator: Grant Ayers (ayers@cs.utah.edu)
|
||||
Date: 26 July 2012
|
||||
|
||||
|
||||
|
||||
DEMONSTRATES
|
||||
------------
|
||||
|
||||
Atomic locks, threads, LEDs, LCD.
|
||||
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
This demo implements a basic thread scheduler which runs eight separate
|
||||
threads on a single processor. Each thread writes a continuously-changing
|
||||
value to a location on the LCD screen corresponding to its unique thread ID
|
||||
(1 through 8). However, it only changes and updates this value when it holds
|
||||
a lock which is shared among the eight threads. XXX
|
||||
|
||||
Each thread has its own 16 KB stack space, arranged as follows:
|
||||
|
||||
Thread Start End Initial SP
|
||||
--------------------------------------------
|
||||
Kernel 0x90000 0x93ffc 0x94000
|
||||
Thread 1 0x8c000 0x8fffc 0x90000
|
||||
Thread 2 0x88000 0x8bffc 0x8c000
|
||||
Thread 3 0x84000 0x87ffc 0x88000
|
||||
Thread 4 0x80000 0x83ffc 0x84000
|
||||
Thread 5 0x7c000 0x7fffc 0x80000
|
||||
Thread 6 0x78000 0x7bffc 0x7c000
|
||||
Thread 7 0x74000 0x77ffc 0x78000
|
||||
Thread 8 0x70000 0x73ffc 0x74000
|
||||
|
||||
Scheduling decisions are made each time the timer interrupts, and the
|
||||
scheduling policy is a simple round-robin rotation.
|
||||
|
||||
|
||||
|
||||
BUILDING AND RUNNING
|
||||
--------------------
|
||||
|
||||
To compile, enter the 'bin' directory and update the paths in the Makefile.
|
||||
Then run 'make' from within the same directory. Use the XUM bootloader to
|
||||
send the resulting .xum file to the FPGA.
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
# Makefile for XUM
|
||||
#
|
||||
# Compiles code to run on the XUM platform, which
|
||||
# is based on MIPS32 and a GCC cross-compiler toolchain.
|
||||
#
|
||||
# Author: Grant Ayers (ayers@cs.utah.edu)
|
||||
# Date: 3 July 2012
|
||||
#
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
SRC = ../src
|
||||
MIPS_PREFIX = /home/User/XUM/gnu_mips/crosstools
|
||||
MIPS_BIN = $(MIPS_PREFIX)/bin
|
||||
MIPS_LIB = $(MIPS_PREFIX)/mips-elf/lib
|
||||
MIPS_CC = $(MIPS_BIN)/mips-elf-gcc-4.7.1.exe
|
||||
MIPS_AS = $(MIPS_BIN)/mips-elf-as.exe
|
||||
MIPS_LD = $(MIPS_BIN)/mips-elf-ld.exe
|
||||
MIPS_OBJDUMP = $(MIPS_BIN)/mips-elf-objdump.exe
|
||||
MIPS_OBJCOPY = $(MIPS_BIN)/mips-elf-objcopy.exe
|
||||
UTIL_PREFIX = /home/User/XUM/demos/util
|
||||
UTIL_CONVBIN = $(UTIL_PREFIX)/bintohex.exe
|
||||
UTIL_CONVXUM = $(UTIL_PREFIX)/bintoxum.exe
|
||||
|
||||
AS_FLAGS = -march=mips32 -EB -G0
|
||||
LD_FLAGS = -EB -static -Map app.map -T ../src/os/xum.ls
|
||||
LD_LIBS = -lm -lc -lgcc
|
||||
LD_SEARCH = -L$(MIPS_PREFIX)/mips-elf/lib \
|
||||
-L$(MIPS_PREFIX)/lib/gcc/mips-elf/4.7.1
|
||||
LD_DRIVER = $(MIPS_LD) $(LD_FLAGS) $(LD_SEARCH) $(LD_LIBS)
|
||||
CC_FLAGS_ARCH = -march=mips32 -EB -msoft-float -mno-mips16
|
||||
CC_FLAGS_LANG = -Wall -O2 -mgpopt -mxgot
|
||||
CC_FLAGS_INC = -I../src/
|
||||
CC_FLAGS_AS = -Wa,-EB,-mips32,-msoft-float
|
||||
CC_FLAGS_LD = -nostdlib -nostartfiles -static -T ../src/os/xum.ls
|
||||
CC_FLAGS_LIB = -lm -lc -lgcc
|
||||
CC_DRIVER = $(MIPS_CC) $(CC_FLAGS_ARCH) $(CC_FLAGS_LANG) \
|
||||
$(CC_FLAGS_AS) $(CC_FLAGS_INC)
|
||||
|
||||
|
||||
all : app
|
||||
|
||||
app : lcd.o app.o boot.o kernel.o lock.o vectors.o exceptions.o \
|
||||
exception_handler.o piezo.o uart.o led.o
|
||||
$(LD_DRIVER) $^ -o app.exe
|
||||
@$(MIPS_OBJDUMP) -EB --disassemble app.exe > app.lst
|
||||
@$(MIPS_OBJCOPY) -O binary -j .text app.exe app-code.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .data app.exe app-data1.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .sdata app.exe app-data2.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .sbss app.exe app-data3.bin
|
||||
@$(MIPS_OBJCOPY) -O binary -j .bss app.exe app-data4.bin
|
||||
@cat app-data1.bin app-data2.bin app-data3.bin app-data4.bin >> app-data.bin
|
||||
@$(UTIL_CONVXUM) -d 4096 app-code.bin app-data.bin app.xum
|
||||
@$(UTIL_CONVBIN) -c -b app-code.bin app-code.coe
|
||||
|
||||
|
||||
|
||||
app.o : $(SRC)/app/app.c
|
||||
$(CC_DRIVER) -c $(SRC)/app/app.c -o app.o
|
||||
|
||||
uart.o : $(SRC)/drivers/uart.c $(SRC)/drivers/uart.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/uart.c -o uart.o
|
||||
|
||||
i2c.o : $(SRC)/drivers/i2c.c $(SRC)/drivers/i2c.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/i2c.c -o i2c.o
|
||||
|
||||
lcd.o : $(SRC)/drivers/lcd.c $(SRC)/drivers/lcd.h lock.o
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/lcd.c -o lcd.o
|
||||
|
||||
monitor.o : $(SRC)/drivers/monitor.c $(SRC)/drivers/monitor.h i2c.o
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/monitor.c -o monitor.o
|
||||
|
||||
piezo.o : $(SRC)/drivers/piezo.c $(SRC)/drivers/piezo.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/piezo.c -o piezo.o
|
||||
|
||||
led.o : $(SRC)/drivers/led.c $(SRC)/drivers/led.h
|
||||
$(CC_DRIVER) -c $(SRC)/drivers/led.c -o led.o
|
||||
|
||||
exception_handler.o : $(SRC)/os/exception_handler.c $(SRC)/os/exception_handler.h lcd.o piezo.o monitor.o
|
||||
$(CC_DRIVER) -c $(SRC)/os/exception_handler.c -o exception_handler.o
|
||||
|
||||
kernel.o : $(SRC)/os/kernel.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o kernel.o $(SRC)/os/kernel.asm
|
||||
|
||||
lock.o : $(SRC)/os/lock.c $(SRC)/os/lock.h
|
||||
$(CC_DRIVER) -c $(SRC)/os/lock.c -o lock.o
|
||||
|
||||
boot.o : $(SRC)/os/boot.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o boot.o $(SRC)/os/boot.asm
|
||||
|
||||
vectors.o : $(SRC)/os/vectors.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o vectors.o $(SRC)/os/vectors.asm
|
||||
|
||||
exceptions.o : $(SRC)/os/exceptions.asm
|
||||
$(MIPS_AS) $(AS_FLAGS) -o exceptions.o $(SRC)/os/exceptions.asm
|
||||
|
||||
clean :
|
||||
rm -f *.o *.exe *.map *.coe *.bin *.map *.xum *.lst
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,115 @@
|
||||
#include <stdlib.h>
|
||||
#include "drivers/lcd.h"
|
||||
#include "drivers/led.h"
|
||||
#include "os/lock.h"
|
||||
|
||||
static int lock;
|
||||
|
||||
void LED_showTID(int tid);
|
||||
void LED_hideTID(int tid);
|
||||
void delay(void);
|
||||
|
||||
|
||||
/* Each thread will enter at main */
|
||||
int main(void)
|
||||
{
|
||||
int tid = 0;
|
||||
char val = 0;
|
||||
|
||||
|
||||
/* Load unique thread ID which is stored in register k1 */
|
||||
asm (
|
||||
"addu %[tid], $27, $0\n\t"
|
||||
: [tid] "=r"(tid)
|
||||
:
|
||||
:
|
||||
);
|
||||
|
||||
/* Allow a single thread to set up the LCD screen and LEDs*/
|
||||
if (tid == 1) {
|
||||
LED_write(0);
|
||||
LCD_clear();
|
||||
LCD_setPos(0);
|
||||
LCD_printString("Thread: 12345678");
|
||||
LCD_setPos(16);
|
||||
LCD_printString("Work:");
|
||||
}
|
||||
|
||||
/* Loop a critical section in which work is performed */
|
||||
while (1) {
|
||||
Lock(&lock, NULL, NULL);
|
||||
LED_showTID(tid);
|
||||
LCD_setPos(23 + (uint8_t)tid);
|
||||
LCD_printByte(val);
|
||||
val++;
|
||||
LED_hideTID(tid);
|
||||
Unlock(&lock);
|
||||
delay();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* delay:
|
||||
* Create a software delay. Use this to increase or decrease
|
||||
* the probability that the thread holds the lock when the
|
||||
* scheduler swaps it out.
|
||||
*/
|
||||
void delay(void)
|
||||
{
|
||||
/* A higher value of 'c' makes it less likely that
|
||||
* a lock will be held, but also lowers throughput. */
|
||||
volatile unsigned int c = 16; // 0, 2, 8, 14, 16, 18, 500, 507
|
||||
|
||||
while (c != 0) {
|
||||
c--;
|
||||
}
|
||||
}
|
||||
|
||||
/* check_violation:
|
||||
* Checks to see if more than one LED is lit, meaning that more
|
||||
* than one is in the critical section. If this is true, the
|
||||
* Error LED is lit.
|
||||
*/
|
||||
void check_violation(uint8_t led)
|
||||
{
|
||||
int i;
|
||||
int found_high = 0;
|
||||
|
||||
for (i=0; i<8; i++) {
|
||||
found_high += (led & 0x1);
|
||||
if (found_high > 1) {
|
||||
LED_write(LED_read() | LED_ERROR);
|
||||
break;
|
||||
}
|
||||
led >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* LED_showTID:
|
||||
* Shows the thread ID (1->8) as a single lit LED (0->7).
|
||||
*/
|
||||
void LED_showTID(int tid)
|
||||
{
|
||||
uint32_t led;
|
||||
|
||||
led = LED_read();
|
||||
led |= (0x80 >> (tid - 1));
|
||||
LED_write(led);
|
||||
check_violation(led);
|
||||
}
|
||||
|
||||
|
||||
/* LED_hideTID:
|
||||
* Turns off the LED (0->7) corresponding to the thread ID (1->8).
|
||||
*/
|
||||
void LED_hideTID(int tid)
|
||||
{
|
||||
uint32_t led;
|
||||
|
||||
led = LED_read();
|
||||
led &= ~(0x80 >> (tid - 1));
|
||||
LED_write(led);
|
||||
}
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
#include "i2c.h"
|
||||
|
||||
void I2C_clear(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
uint32_t cmd = (1 << 8);
|
||||
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_EnQ(uint8_t byte)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 9) | (uint32_t)byte;
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_transmit(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 10);
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_setReceive(uint8_t bytes)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 12) | (uint32_t)bytes;
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
void I2C_receive(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t cmd = (1 << 11);
|
||||
*i2c = cmd;
|
||||
}
|
||||
|
||||
uint32_t I2C_DeQ(void)
|
||||
{
|
||||
volatile uint32_t *i2c = (volatile uint32_t *)I2C_ADDRESS;
|
||||
|
||||
uint32_t data = *i2c;
|
||||
return data;
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#ifndef __I2C_H__
|
||||
#define __I2C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define I2C_ADDRESS 0x90000000
|
||||
|
||||
void I2C_clear(void);
|
||||
void I2C_EnQ(uint8_t byte);
|
||||
void I2C_transmit(void);
|
||||
void I2C_setReceive(uint8_t bytes);
|
||||
void I2C_receive(void);
|
||||
uint32_t I2C_DeQ(void);
|
||||
|
||||
#endif
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
#include <stdlib.h> /* For definition of 'NULL' */
|
||||
#include "lcd.h"
|
||||
#include "os/lock.h"
|
||||
|
||||
static volatile int LCD_lock_var = 0;
|
||||
static uint8_t LCD_position = 0;
|
||||
static uint8_t LCD_autoIncr = 1;
|
||||
|
||||
static void LCD_incrPos(uint32_t amount)
|
||||
{
|
||||
if (LCD_autoIncr == 0) {
|
||||
return;
|
||||
}
|
||||
while (amount > 32) {
|
||||
amount -= 32;
|
||||
}
|
||||
LCD_position += (uint8_t)amount;
|
||||
if (LCD_position >= 32) {
|
||||
LCD_position -= 32;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCD_clear(void)
|
||||
{
|
||||
volatile uint32_t *LCD;
|
||||
int i;
|
||||
|
||||
LCD = (volatile uint32_t *)LCD_ADDRESS;
|
||||
|
||||
for (i=0; i<8; i++) {
|
||||
LCD[i] = 0x20202020;
|
||||
}
|
||||
LCD_position = 0;
|
||||
}
|
||||
|
||||
void LCD_setPos(uint8_t position)
|
||||
{
|
||||
LCD_position = position;
|
||||
}
|
||||
|
||||
uint8_t LCD_getPos(void)
|
||||
{
|
||||
return LCD_position;
|
||||
}
|
||||
|
||||
void LCD_setAutoIncr(uint8_t incr)
|
||||
{
|
||||
LCD_autoIncr = incr;
|
||||
}
|
||||
|
||||
void LCD_lock(void)
|
||||
{
|
||||
Lock(&LCD_lock_var, NULL, NULL);
|
||||
}
|
||||
|
||||
void LCD_unlock(void)
|
||||
{
|
||||
Unlock(&LCD_lock_var);
|
||||
}
|
||||
|
||||
void LCD_printByte(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
*LCD = byte;
|
||||
LCD_incrPos(1);
|
||||
}
|
||||
|
||||
void LCD_printByteHex(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
uint8_t nibble_h, nibble_l;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
nibble_h = byte >> 4;
|
||||
nibble_l = byte & 0x0f;
|
||||
|
||||
if (nibble_h < 10) {
|
||||
nibble_h += 48;
|
||||
}
|
||||
else {
|
||||
nibble_h += 55;
|
||||
}
|
||||
if (nibble_l < 10) {
|
||||
nibble_l += 48;
|
||||
}
|
||||
else {
|
||||
nibble_h += 55;
|
||||
}
|
||||
*LCD = nibble_h;
|
||||
LCD++;
|
||||
*LCD = nibble_l;
|
||||
LCD_incrPos(2);
|
||||
}
|
||||
|
||||
void LCD_printByteDec(uint8_t byte)
|
||||
{
|
||||
volatile uint8_t *LCD;
|
||||
uint8_t hundreds, tens, ones;
|
||||
uint32_t n_printed = 1;
|
||||
|
||||
LCD = (volatile uint8_t *)(LCD_ADDRESS + LCD_position);
|
||||
hundreds = tens = ones = 48;
|
||||
|
||||
while (byte >= 100) {
|
||||
hundreds++;
|
||||
byte -= 100;
|
||||
}
|
||||
while (byte >= 10) {
|
||||
tens++;
|
||||
byte -= 10;
|
||||
}
|
||||
while (byte >= 1) {
|
||||
ones++;
|
||||
byte -= 1;
|
||||
}
|
||||
if (hundreds > 48) {
|
||||
*LCD = hundreds;
|
||||
LCD++;
|
||||
n_printed++;
|
||||
}
|
||||
if ((n_printed > 1) || (tens > 48)) {
|
||||
*LCD = tens;
|
||||
LCD++;
|
||||
n_printed++;
|
||||
}
|
||||
*LCD = ones;
|
||||
LCD_incrPos(n_printed);
|
||||
}
|
||||
|
||||
void LCD_printWord(uint32_t word)
|
||||
{
|
||||
volatile uint32_t *LCD;
|
||||
|
||||
LCD = (volatile uint32_t *)(LCD_ADDRESS + LCD_position);
|
||||
*LCD = word;
|
||||
LCD_incrPos(4);
|
||||
}
|
||||
|
||||
void LCD_printString(char *string)
|
||||
{
|
||||
volatile char *LCD;
|
||||
int i = 0;
|
||||
|
||||
LCD = (volatile char *)(LCD_ADDRESS + LCD_position);
|
||||
|
||||
while (string[i] != '\0') {
|
||||
LCD[i] = string[i];
|
||||
i++;
|
||||
}
|
||||
LCD_incrPos(i);
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
#ifndef __LCD_H__
|
||||
#define __LCD_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define LCD_ADDRESS 0x80000000
|
||||
|
||||
void LCD_clear(void);
|
||||
void LCD_setPos(uint8_t position);
|
||||
uint8_t LCD_getPos(void);
|
||||
void LCD_setAutoIncr(uint8_t incr);
|
||||
void LCD_lock(void);
|
||||
void LCD_unlock(void);
|
||||
void LCD_printByte(uint8_t byte);
|
||||
void LCD_printByteHex(uint8_t byte);
|
||||
void LCD_printByteDec(uint8_t byte);
|
||||
void LCD_printWord(uint32_t word);
|
||||
void LCD_printString(char *string);
|
||||
|
||||
#endif
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#include "led.h"
|
||||
|
||||
uint32_t LED_read(void)
|
||||
{
|
||||
volatile uint32_t *LED = (volatile uint32_t *)LED_ADDRESS;
|
||||
uint32_t data;
|
||||
|
||||
data = *LED;
|
||||
return data;
|
||||
}
|
||||
|
||||
void LED_write(uint32_t value)
|
||||
{
|
||||
volatile uint32_t *LED = (volatile uint32_t *)LED_ADDRESS;
|
||||
|
||||
*LED = value;
|
||||
}
|
||||
|
||||
void LED_setMode(uint32_t mode)
|
||||
{
|
||||
volatile uint32_t *LED = (volatile uint32_t *)LED_ADDRESS;
|
||||
|
||||
*LED = mode;
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
#ifndef __LED_H__
|
||||
#define __LED_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define LED_ADDRESS 0xC0000000
|
||||
#define LED_MODE_DATA 0x00000000
|
||||
#define LED_MODE_INTR 0x00004000
|
||||
#define LED_CENTER 0x00000100
|
||||
#define LED_WEST 0x00000200
|
||||
#define LED_SOUTH 0x00000400
|
||||
#define LED_EAST 0x00000800
|
||||
#define LED_NORTH 0x00001000
|
||||
#define LED_ERROR 0x00002000
|
||||
|
||||
uint32_t LED_read(void);
|
||||
void LED_write(uint32_t data);
|
||||
void LED_setMode(uint32_t mode);
|
||||
|
||||
#endif
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#include "monitor.h"
|
||||
|
||||
void Monitor_start(void)
|
||||
{
|
||||
I2C_clear();
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_EnQ(0x40); // Configuration Register 1
|
||||
I2C_EnQ(0x1); // Enable monitoring
|
||||
I2C_transmit();
|
||||
}
|
||||
|
||||
|
||||
// Node is 0->Remote 1, 1->Local, 2->Remote 2
|
||||
uint32_t Monitor_readTemp(int node)
|
||||
{
|
||||
uint8_t reg = 0x25 + node;
|
||||
uint32_t data;
|
||||
|
||||
// Set the read register
|
||||
I2C_clear();
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_EnQ(reg);
|
||||
I2C_transmit();
|
||||
|
||||
// Receive the register
|
||||
I2C_EnQ(MONITOR_BUS_ADDR);
|
||||
I2C_setReceive(1);
|
||||
I2C_receive();
|
||||
data = I2C_DeQ();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
#ifndef __MONITOR_H__
|
||||
#define __MONITOR_H__
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
#define MONITOR_BUS_ADDR 0x2C
|
||||
|
||||
void Monitor_start(void);
|
||||
uint32_t Monitor_readTemp(int node);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#include "piezo.h"
|
||||
|
||||
void Piezo_set(uint32_t count, int enable)
|
||||
{
|
||||
volatile uint32_t *Piezo = (volatile uint32_t *)PIEZO_ADDRESS;
|
||||
|
||||
if (enable) {
|
||||
*Piezo = count | 0x1000000;
|
||||
}
|
||||
else {
|
||||
*Piezo = count & ~0x1000000;
|
||||
}
|
||||
}
|
||||
|
||||
void Piezo_play(uint32_t note)
|
||||
{
|
||||
Piezo_set(note, 1);
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
#ifndef __PIEZO_H__
|
||||
#define __PIEZO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PIEZO_ADDRESS 0xA0000000
|
||||
|
||||
/* Following are defined for a 100 MHz Piezo driver */
|
||||
#define C0 3058104
|
||||
#define C1 1529052
|
||||
|
||||
#define C4 191110
|
||||
#define C4s 180388
|
||||
#define D4f C4s
|
||||
#define D4 170264
|
||||
#define D4s 160705
|
||||
#define E4f D4s
|
||||
#define E4 151685
|
||||
#define F4 143172
|
||||
#define F4s 135138
|
||||
#define G4f F4s
|
||||
#define G4 127551
|
||||
#define G4s 120395
|
||||
#define A4f G4s
|
||||
#define A4 113636
|
||||
#define A4s 107259
|
||||
#define B4f A4s
|
||||
#define B4 101239
|
||||
#define C5 95557
|
||||
#define C5s 90192
|
||||
#define D5f C5s
|
||||
#define D5 85131
|
||||
#define D5s 80354
|
||||
#define E5f D5s
|
||||
#define E5 75843
|
||||
|
||||
#define C8 11945
|
||||
|
||||
|
||||
void Piezo_set(uint32_t count, int enable);
|
||||
void Piezo_play(uint32_t note);
|
||||
|
||||
#endif
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#include "uart.h"
|
||||
|
||||
void UART_disableBoot(void)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
uint32_t data;
|
||||
|
||||
data = 0x00000100;
|
||||
|
||||
*uart = data;
|
||||
}
|
||||
|
||||
uint8_t UART_readByte(void)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
uint32_t data;
|
||||
|
||||
data = *uart;
|
||||
|
||||
return (uint8_t)data;
|
||||
}
|
||||
|
||||
uint32_t UART_readMessage(void)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
|
||||
return *uart;
|
||||
}
|
||||
|
||||
void UART_writeByte(uint8_t byte)
|
||||
{
|
||||
volatile uint32_t *uart = (volatile uint32_t *)UART_ADDRESS;
|
||||
uint32_t data;
|
||||
|
||||
data = (uint32_t)byte;
|
||||
*uart = data;
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#ifndef __UART_H__
|
||||
#define __UART_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define UART_ADDRESS 0xB0000000
|
||||
|
||||
void UART_disableBoot(void);
|
||||
uint8_t UART_readByte(void);
|
||||
uint32_t UART_readMessage(void);
|
||||
void UART_writeByte(uint8_t byte);
|
||||
|
||||
#endif
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
###############################################################################
|
||||
# TITLE: Boot Up Code
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 19 July 2011
|
||||
# FILENAME: boot.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Initializes the global pointer and stack pointer.
|
||||
# Zeros BSS memory region and jumps to main().
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.global boot
|
||||
.ent boot
|
||||
.set noreorder
|
||||
boot:
|
||||
la $t0, _bss_start # Defined in linker script
|
||||
la $t1, _bss_end
|
||||
la $sp, _sp
|
||||
la $gp, _gp
|
||||
|
||||
$bss_clear:
|
||||
beq $t0, $t1, $cp0_setup # Loop until BSS is cleared
|
||||
nop
|
||||
sb $0, 0($t0)
|
||||
j $bss_clear
|
||||
addiu $t0, $t0, 1
|
||||
|
||||
$cp0_setup:
|
||||
la $26, $run # Load the address of $run into
|
||||
mtc0 $26, $30, 0 # the ErrorEPC
|
||||
mfc0 $26, $13, 0 # Load Cause register
|
||||
lui $27, 0x0080 # Use "special" interrupt vector
|
||||
or $26, $26, $27
|
||||
mtc0 $26, $13, 0 # Commit new Cause register
|
||||
mfc0 $26, $12, 0 # Load Status register
|
||||
lui $27, 0x0fff # Disable access to Coprocessors
|
||||
ori $27, $27, 0xffff
|
||||
and $26, $26, $27
|
||||
lui $27, 0xffff # Enable, but mask all interrupts
|
||||
ori $27, $27, 0x00ff
|
||||
and $26, $26, $27
|
||||
ori $27, $0, 0x0001 # Base operating mode is Kernel
|
||||
or $26, $26, $27
|
||||
mtc0 $26, $12, 0 # Commit new Status register
|
||||
|
||||
#lui $26, 0x0000 # 1ms timer (50 MHz)
|
||||
#ori $26, $26, 0xc350
|
||||
lui $26, 0x0007 # 10ms timer (50 MHz)
|
||||
ori $26, $26, 0xa120
|
||||
#lui $26, 0x004c # 100ms timer (50 MHz)
|
||||
#ori $26, $26, 0x4b40
|
||||
#lui $26, 0x00be # 250ms timer (50 MHz)
|
||||
#ori $26, 0xbc20
|
||||
#lui $26, 0x017d # 500ms timer (50 MHz)
|
||||
#ori $26, 0x7840
|
||||
#lui $26, 0x02fa # 1 sec timer (50 MHz)
|
||||
#ori $26, $26, 0xf080
|
||||
mtc0 $26, $11, 0 # Set Compare register to timer value
|
||||
|
||||
eret # Return from Reset Exception
|
||||
|
||||
$run:
|
||||
jal kernel
|
||||
nop
|
||||
|
||||
$done:
|
||||
j $done
|
||||
nop
|
||||
|
||||
.end boot
|
||||
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
#include "drivers/lcd.h"
|
||||
#include "drivers/piezo.h"
|
||||
#include "drivers/monitor.h"
|
||||
#include "drivers/uart.h"
|
||||
|
||||
void dead_loop(void)
|
||||
{
|
||||
for (;;) {}
|
||||
}
|
||||
|
||||
void mips32_handler_AdEL(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("AdEL");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_AdES(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("AdES");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Bp(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Bp");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_CpU(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("CpU");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Ov(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Ov");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_RI(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("RI");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Sys(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Sys");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
void mips32_handler_Tr(void)
|
||||
{
|
||||
LCD_clear();
|
||||
LCD_printString("Trap");
|
||||
dead_loop();
|
||||
}
|
||||
|
||||
/* Timer is bypassed to scheduler in this demo */
|
||||
void mips32_handler_HwInt5(void)
|
||||
{
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt4(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt3(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt2(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_HwInt1(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
/* UART */
|
||||
void mips32_handler_HwInt0(void)
|
||||
{
|
||||
uint32_t recv_msg;
|
||||
uint32_t bytes_avail;
|
||||
uint8_t read_byte;
|
||||
|
||||
recv_msg = UART_readMessage();
|
||||
read_byte = (uint8_t)recv_msg;
|
||||
bytes_avail = (recv_msg >> 8);
|
||||
|
||||
while (bytes_avail > 0) {
|
||||
if (read_byte == 0x7f) { // delete
|
||||
LCD_setAutoIncr(0);
|
||||
LCD_printByte(0x20);
|
||||
LCD_setPos(LCD_getPos()-1);
|
||||
LCD_setAutoIncr(1);
|
||||
}
|
||||
else {
|
||||
LCD_printByte(read_byte);
|
||||
}
|
||||
bytes_avail--;
|
||||
read_byte = UART_readByte();
|
||||
}
|
||||
}
|
||||
|
||||
void mips32_handler_SwInt1(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
void mips32_handler_SwInt0(void)
|
||||
{
|
||||
static volatile char count = 0;
|
||||
|
||||
LCD_printByte(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#ifndef __exception_handler_h__
|
||||
#define __exception_handler_h__
|
||||
|
||||
/* MIPS32 Exception Handlers */
|
||||
void mips32_handler_AdEL(void);
|
||||
void mips32_handler_AdES(void);
|
||||
void mips32_handler_Bp(void);
|
||||
void mips32_handler_CpU(void);
|
||||
void mips32_handler_Ov(void);
|
||||
void mips32_handler_RI(void);
|
||||
void mips32_handler_Sys(void);
|
||||
void mips32_handler_Tr(void);
|
||||
|
||||
/* MIPS32 Interrupt Handlers */
|
||||
void mips32_handler_HwInt5(void);
|
||||
void mips32_handler_HwInt4(void);
|
||||
void mips32_handler_HwInt3(void);
|
||||
void mips32_handler_HwInt2(void);
|
||||
void mips32_handler_HwInt1(void);
|
||||
void mips32_handler_HwInt0(void);
|
||||
void mips32_handler_SwInt1(void);
|
||||
void mips32_handler_SwInt0(void);
|
||||
|
||||
#endif
|
||||
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
###############################################################################
|
||||
# TITLE: Exception Vectors
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 23 May 2012
|
||||
# FILENAME: exceptions.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Provides the exception vectors which jump to
|
||||
# exception-handling routines.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.set noreorder
|
||||
|
||||
exc_save:
|
||||
addiu $sp, $sp, -96
|
||||
sw $2, 0($sp)
|
||||
sw $3, 4($sp)
|
||||
sw $4, 8($sp)
|
||||
sw $5, 12($sp)
|
||||
sw $6, 16($sp)
|
||||
sw $7, 20($sp)
|
||||
sw $8, 24($sp)
|
||||
sw $9, 28($sp)
|
||||
sw $10, 32($sp)
|
||||
sw $11, 36($sp)
|
||||
sw $12, 40($sp)
|
||||
sw $13, 44($sp)
|
||||
sw $14, 48($sp)
|
||||
sw $15, 52($sp)
|
||||
sw $16, 56($sp)
|
||||
sw $17, 60($sp)
|
||||
sw $18, 64($sp)
|
||||
sw $19, 68($sp)
|
||||
sw $20, 72($sp)
|
||||
sw $21, 76($sp)
|
||||
sw $22, 80($sp)
|
||||
sw $23, 84($sp)
|
||||
sw $24, 88($sp)
|
||||
jr $ra
|
||||
sw $25, 92($sp)
|
||||
|
||||
exc_restore:
|
||||
lw $2, 0($sp)
|
||||
lw $3, 4($sp)
|
||||
lw $4, 8($sp)
|
||||
lw $5, 12($sp)
|
||||
lw $6, 16($sp)
|
||||
lw $7, 20($sp)
|
||||
lw $8, 24($sp)
|
||||
lw $9, 28($sp)
|
||||
lw $10, 32($sp)
|
||||
lw $11, 36($sp)
|
||||
lw $12, 40($sp)
|
||||
lw $13, 44($sp)
|
||||
lw $14, 48($sp)
|
||||
lw $15, 52($sp)
|
||||
lw $16, 56($sp)
|
||||
lw $17, 60($sp)
|
||||
lw $18, 64($sp)
|
||||
lw $19, 68($sp)
|
||||
lw $20, 72($sp)
|
||||
lw $21, 76($sp)
|
||||
lw $22, 80($sp)
|
||||
lw $23, 84($sp)
|
||||
lw $24, 88($sp)
|
||||
lw $25, 92($sp)
|
||||
jr $ra
|
||||
addiu $sp, $sp, 96
|
||||
|
||||
|
||||
.global mips32_general_exception
|
||||
.ent mips32_general_exception
|
||||
mips32_general_exception:
|
||||
or $26, $0, $ra
|
||||
jal exc_save
|
||||
nop
|
||||
mfc0 $27, $13, 0 # Read Cause which has ExcCode bits
|
||||
srl $27, $27, 2 # Extract exception code to $k1
|
||||
andi $27, $27, 0x001f
|
||||
|
||||
la $ra, $end_exception # Jump to the appropriate handler
|
||||
addiu $t0, $0, 4
|
||||
addiu $t1, $0, 5
|
||||
addiu $t2, $0, 8
|
||||
addiu $t3, $0, 9
|
||||
beq $t0, $27, mips32_handler_AdEL
|
||||
addiu $t0, $0, 10
|
||||
beq $t1, $27, mips32_handler_AdES
|
||||
addiu $t1, $0, 11
|
||||
beq $t2, $27, mips32_handler_Sys
|
||||
addiu $t2, $0, 12
|
||||
beq $t3, $27, mips32_handler_Bp
|
||||
addiu $t3, $0, 13
|
||||
beq $t0, $27, mips32_handler_RI
|
||||
nop
|
||||
beq $t1, $27, mips32_handler_CpU
|
||||
nop
|
||||
beq $t2, $27, mips32_handler_Ov
|
||||
nop
|
||||
beq $t3, $27, mips32_handler_Tr
|
||||
nop
|
||||
|
||||
$end_exception:
|
||||
jal exc_restore
|
||||
xor $27, $0, $0
|
||||
or $ra, $0, $26
|
||||
xor $26, $0, $0
|
||||
eret
|
||||
.end mips32_general_exception
|
||||
|
||||
|
||||
|
||||
### "Special" Interrupt Vector: Cause_IV must be set.
|
||||
|
||||
.ent mips32_interrupt_exception
|
||||
.global mips32_interrupt_exception
|
||||
mips32_interrupt_exception:
|
||||
mfc0 $26, $12, 0 # Status register for IM bits
|
||||
mfc0 $27, $13, 0 # Cause register for IP bits
|
||||
and $26, $26, $27 # Extract pending, unmasked interrupts
|
||||
srl $26, $26, 8
|
||||
andi $26, $26, 0x00ff
|
||||
|
||||
clz $26, $26
|
||||
addiu $27, $0, 24
|
||||
beq $26, $27, scheduler # Hw Int 5 goes directly to scheduler
|
||||
nop
|
||||
|
||||
addu $27, $0, $ra
|
||||
jal exc_save
|
||||
nop
|
||||
la $ra, $end_interrupt
|
||||
addiu $t0, $0, 25
|
||||
addiu $t1, $0, 26
|
||||
addiu $t2, $0, 27
|
||||
beq $26, $t0, mips32_handler_HwInt4
|
||||
addiu $t0, $0, 28
|
||||
beq $26, $t1, mips32_handler_HwInt3
|
||||
addiu $t1, $0, 29
|
||||
beq $26, $t2, mips32_handler_HwInt2
|
||||
addiu $t2, $0, 30
|
||||
beq $26, $t0, mips32_handler_HwInt1
|
||||
addiu $t0, $0, 31
|
||||
beq $26, $t1, mips32_handler_HwInt0
|
||||
nop
|
||||
beq $26, $t2, mips32_handler_SwInt1
|
||||
nop
|
||||
beq $26, $t0, mips32_handler_SwInt0
|
||||
nop
|
||||
|
||||
$end_interrupt:
|
||||
jal exc_restore
|
||||
xor $27, $0, $0
|
||||
or $ra, $0, $26
|
||||
xor $26, $0, $0
|
||||
eret
|
||||
.end mips32_interrupt_exception
|
||||
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
###############################################################################
|
||||
# TITLE: Thread kernel demo
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 30 June 2012
|
||||
# FILENAME: kernel.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Switches between 8 simultaneously-running threads.
|
||||
# Demonstrates interrupts and llsc atomic operations.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.global kernel
|
||||
.ent kernel
|
||||
.set noreorder
|
||||
.set noat
|
||||
kernel:
|
||||
addiu $sp, $sp, -1152 # Room for 9*32 registers
|
||||
|
||||
# Set the stack pointer ($29) for each of 8 threads
|
||||
lui $t0, 0x0007
|
||||
ori $t0, $t0, 0x4000
|
||||
sw $t0, 1140($sp)
|
||||
addiu $t0, $t0, 0x4000
|
||||
sw $t0, 1012($sp)
|
||||
addiu $t0, $t0, 0x4000
|
||||
sw $t0, 884($sp)
|
||||
addiu $t0, $t0, 0x4000
|
||||
sw $t0, 756($sp)
|
||||
addiu $t0, $t0, 0x4000
|
||||
sw $t0, 628($sp)
|
||||
addiu $t0, $t0, 0x4000
|
||||
sw $t0, 500($sp)
|
||||
addiu $t0, $t0, 0x4000
|
||||
sw $t0, 372($sp)
|
||||
addiu $t0, $t0, 0x4000
|
||||
sw $t0, 244($sp)
|
||||
|
||||
# Set the global pointer ($28) for each of 8 threads
|
||||
sw $gp, 240($sp)
|
||||
sw $gp, 368($sp)
|
||||
sw $gp, 496($sp)
|
||||
sw $gp, 624($sp)
|
||||
sw $gp, 752($sp)
|
||||
sw $gp, 880($sp)
|
||||
sw $gp, 1008($sp)
|
||||
sw $gp, 1136($sp)
|
||||
|
||||
# Set the EPC for each of 8 threads to start at main
|
||||
lui $t0, main
|
||||
ori $t0, $t0, main
|
||||
sw $t0, 128($sp)
|
||||
sw $t0, 256($sp)
|
||||
sw $t0, 384($sp)
|
||||
sw $t0, 512($sp)
|
||||
sw $t0, 640($sp)
|
||||
sw $t0, 768($sp)
|
||||
sw $t0, 896($sp)
|
||||
sw $t0, 1024($sp)
|
||||
|
||||
sw $zero, 0($sp) # Current thread stored in 0($sp)
|
||||
mfc0 $k0, $12, 0 # Enable timer interrupt
|
||||
ori $k0, $k0, 0x8000
|
||||
mtc0 $k0, $12, 0
|
||||
|
||||
$wait:
|
||||
j $wait # Wait for interrupt to begin schedule
|
||||
nop
|
||||
.end kernel
|
||||
|
||||
|
||||
|
||||
|
||||
.global scheduler
|
||||
.ent scheduler
|
||||
scheduler:
|
||||
addu $k0, $0, $sp # Recover the kernel stack pointer
|
||||
la $sp, _sp
|
||||
addiu $sp, $sp, -1152
|
||||
sw $25, 4($sp) # Free four registers for use
|
||||
sw $28, 8($sp)
|
||||
sw $30, 12($sp)
|
||||
sw $31, 16($sp)
|
||||
lw $k1, 0($sp) # Current TID to k1
|
||||
beq $k1, $zero, $skip_save # Don't save kernel's registers
|
||||
nop
|
||||
jal save_registers
|
||||
nop
|
||||
$skip_save:
|
||||
lw $t0, 0($sp) # Increment TID
|
||||
addiu $t0, $t0, 1
|
||||
addiu $t1, $zero, 9 # Move TID back to 1 if it reaches 9
|
||||
beq $t0, $t1, $reset_tid
|
||||
nop
|
||||
$tid_done:
|
||||
sw $t0, 0($sp)
|
||||
jal restore_registers # Load registers for next thread
|
||||
nop
|
||||
la $k1, _sp # Recover kernel stack pointer again
|
||||
addiu $k1, $k1, -1152
|
||||
lw $k1, 0($k1) # Load TID to k1 for main function
|
||||
mfc0 $26, $9, 0 # Read Count to clear timer interrupt
|
||||
eret # Run thread
|
||||
$reset_tid:
|
||||
addiu $t0, $zero, 1
|
||||
j $tid_done
|
||||
nop
|
||||
.end scheduler
|
||||
|
||||
|
||||
save_registers:
|
||||
# Requires: k0 hold thread stack pointer
|
||||
# k1 holds TID
|
||||
# sp points to kernel stack
|
||||
# Destroys:
|
||||
|
||||
# Find offset for register table in kernel space
|
||||
addiu $25, $zero, 128
|
||||
mul $25, $25, $k1
|
||||
addu $25, $25, $sp
|
||||
|
||||
# Store thread stack pointer
|
||||
sw $k0, 116($25)
|
||||
addu $k0, $0, $25
|
||||
|
||||
# Store EPC from CP0
|
||||
mfc0 $25, $14, 0
|
||||
sw $25, 0($k0)
|
||||
|
||||
# Store remaining registers
|
||||
sw $1, 4($k0)
|
||||
sw $2, 8($k0)
|
||||
sw $3, 12($k0)
|
||||
sw $4, 16($k0)
|
||||
sw $5, 20($k0)
|
||||
sw $6, 24($k0)
|
||||
sw $7, 28($k0)
|
||||
sw $8, 32($k0)
|
||||
sw $9, 36($k0)
|
||||
sw $10, 40($k0)
|
||||
sw $11, 44($k0)
|
||||
sw $12, 48($k0)
|
||||
sw $13, 52($k0)
|
||||
sw $14, 56($k0)
|
||||
sw $15, 60($k0)
|
||||
sw $16, 64($k0)
|
||||
sw $17, 68($k0)
|
||||
sw $18, 72($k0)
|
||||
sw $19, 76($k0)
|
||||
sw $20, 80($k0)
|
||||
sw $21, 84($k0)
|
||||
sw $22, 88($k0)
|
||||
sw $23, 92($k0)
|
||||
sw $24, 96($k0)
|
||||
lw $25, 4($sp)
|
||||
sw $25, 100($k0)
|
||||
lw $28, 8($sp)
|
||||
sw $28, 112($k0)
|
||||
lw $30, 12($sp)
|
||||
sw $30, 120($k0)
|
||||
addu $k1, $0, $31
|
||||
lw $31, 16($sp)
|
||||
sw $31, 124($k0)
|
||||
jr $k1
|
||||
nop
|
||||
|
||||
|
||||
restore_registers:
|
||||
# Requires: t0 specifies which thread (1-8)
|
||||
# sp points to kernel stack
|
||||
# Destroys: All registers
|
||||
|
||||
# Find offset for register table in kernel space
|
||||
addiu $k1, $zero, 128
|
||||
mul $k0, $t0, $k1
|
||||
addu $k0, $k0, $sp
|
||||
|
||||
|
||||
# Load EPC to CP0
|
||||
lw $k1, 0($k0)
|
||||
mtc0 $k1, $14, 0
|
||||
# Load remaining registers
|
||||
lw $1, 4($k0)
|
||||
lw $2, 8($k0)
|
||||
lw $3, 12($k0)
|
||||
lw $4, 16($k0)
|
||||
lw $5, 20($k0)
|
||||
lw $6, 24($k0)
|
||||
lw $7, 28($k0)
|
||||
lw $8, 32($k0)
|
||||
lw $9, 36($k0)
|
||||
lw $10, 40($k0)
|
||||
lw $11, 44($k0)
|
||||
lw $12, 48($k0)
|
||||
lw $13, 52($k0)
|
||||
lw $14, 56($k0)
|
||||
lw $15, 60($k0)
|
||||
lw $16, 64($k0)
|
||||
lw $17, 68($k0)
|
||||
lw $18, 72($k0)
|
||||
lw $19, 76($k0)
|
||||
lw $20, 80($k0)
|
||||
lw $21, 84($k0)
|
||||
lw $22, 88($k0)
|
||||
lw $23, 92($k0)
|
||||
lw $24, 96($k0)
|
||||
lw $25, 100($k0)
|
||||
lw $28, 112($k0)
|
||||
lw $29, 116($k0)
|
||||
lw $30, 120($k0)
|
||||
addu $k1, $0, $31
|
||||
lw $31, 124($k0)
|
||||
jr $k1
|
||||
nop
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#include <stdlib.h> /* only for NULL */
|
||||
#include "lock.h"
|
||||
|
||||
void Lock(volatile int *lock, int *load_count, int *store_count)
|
||||
{
|
||||
int l_tries = 0;
|
||||
int s_tries = 0;
|
||||
|
||||
asm volatile(
|
||||
".set noreorder\n\t"
|
||||
"addiu $8, $0, 1\n\t"
|
||||
"addu %[l_tries], $0, $0\n\t"
|
||||
"addu %[s_tries], $0, $0\n\t"
|
||||
"1:\n\t"
|
||||
"ll $9, %[lock]\n\t"
|
||||
"bne $9, $0, 1b\n\t"
|
||||
"addiu %[l_tries], %[l_tries], 1\n\t"
|
||||
"sc $8, %[lock]\n\t"
|
||||
"beq $8, $0, 1b\n\t"
|
||||
"addiu %[s_tries], %[s_tries], 1\n\t"
|
||||
".set reorder\n\t"
|
||||
: [l_tries] "=&r"(l_tries), [s_tries] "=&r"(s_tries),
|
||||
[lock] "+m"(*lock)
|
||||
:
|
||||
: "$8", "$9", "memory"
|
||||
);
|
||||
|
||||
if (load_count != NULL) {
|
||||
*load_count = l_tries;
|
||||
}
|
||||
if (store_count != NULL) {
|
||||
*store_count = s_tries;
|
||||
}
|
||||
}
|
||||
|
||||
void LockAlmost(volatile int *lock, int *load_count, int *store_count)
|
||||
{
|
||||
int l_tries = 0;
|
||||
int s_tries = 0;
|
||||
|
||||
asm volatile(
|
||||
".set noreorder\n\t"
|
||||
"addiu $8, $0, 1\n\t"
|
||||
"addu %[l_tries], $0, $0\n\t"
|
||||
"addu %[s_tries], $0, $0\n\t"
|
||||
"1:\n\t"
|
||||
"ll $9, %[lock]\n\t"
|
||||
"bne $9, $0, 1b\n\t"
|
||||
"addiu %[l_tries], %[l_tries], 1\n\t"
|
||||
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
|
||||
"sc $8, %[lock]\n\t"
|
||||
"addiu %[s_tries], %[s_tries], 1\n\t"
|
||||
".set reorder\n\t"
|
||||
: [l_tries] "=&r"(l_tries), [s_tries] "=&r"(s_tries),
|
||||
[lock] "+m"(*lock)
|
||||
:
|
||||
: "$8", "$9", "memory"
|
||||
);
|
||||
|
||||
if (load_count != NULL) {
|
||||
*load_count = l_tries;
|
||||
}
|
||||
if (store_count != NULL) {
|
||||
*store_count = s_tries;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LockNull(volatile int *lock, int *load_count, int *store_count)
|
||||
{
|
||||
if (load_count != NULL) {
|
||||
*load_count = 1;
|
||||
}
|
||||
if (store_count != NULL) {
|
||||
*store_count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Unlock(volatile int *lock)
|
||||
{
|
||||
*lock = 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef __LOCK_H__
|
||||
#define __LOCK_H__
|
||||
|
||||
void Lock(volatile int *lock, int *load_count, int *store_count);
|
||||
void LockAlmost(volatile int *lock, int *load_count, int *store_count);
|
||||
void LockNull(volatile int *lock, int *load_count, int *store_count);
|
||||
void Unlock(volatile int *lock);
|
||||
|
||||
#endif
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
###############################################################################
|
||||
# TITLE: Exception Vectors
|
||||
# AUTHOR: Grant Ayers (ayers@cs.utah.edu)
|
||||
# DATE: 23 May 2012
|
||||
# FILENAME: exceptions.asm
|
||||
# PROJECT: University of Utah XUM Single Core
|
||||
# DESCRIPTION:
|
||||
# Provides the exception vectors which jump to
|
||||
# exception-handling routines.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
# Current setup:
|
||||
# 1. The exception vector begins at address 0x0.
|
||||
# 2. The interrupt vector begins at address 0x8.
|
||||
# 3. Each vector has room for 2 instructions (8 bytes) with which
|
||||
# it must jump to its demultiplexing routine. The demultiplexing
|
||||
# routine calls individual exception-specific handlers.
|
||||
# 4. The linker script must ensure that this code is placed at the
|
||||
# correct address.
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.ent exception_vector
|
||||
.set noreorder
|
||||
exception_vector:
|
||||
j mips32_general_exception
|
||||
nop
|
||||
.end exception_vector
|
||||
|
||||
|
||||
.ent interrupt_vector
|
||||
interrupt_vector:
|
||||
j mips32_interrupt_exception
|
||||
nop
|
||||
.end interrupt_vector
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Linker script for MIPS32 (Single Core) FPGA, intended for XUM */
|
||||
|
||||
|
||||
/* Entry Point
|
||||
*
|
||||
* Set it to be the label "boot" (likely in boot.asm)
|
||||
*
|
||||
*/
|
||||
/*ENTRY(boot)*/
|
||||
|
||||
|
||||
/* Memory Section
|
||||
*
|
||||
* The FPGA currently uses one region of Block RAM, which is 592 KB.
|
||||
*
|
||||
* Instruction Memory starts at address 0.
|
||||
*
|
||||
* Data Memory ends 592KB later, at address 0x00094000 (the last
|
||||
* usable word address is 0x00093ffc).
|
||||
*
|
||||
* Instructions : 0x00000000 -> 0x0000fffc ( 64KB)
|
||||
* Data / BSS : 0x00001000 -> 0x00017ffc ( 32KB)
|
||||
* Stack / Heap : 0x00018000 -> 0x00093ffc (496KB)
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* Sections
|
||||
*
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
_sp = 0x00094000;
|
||||
|
||||
. = 0 ;
|
||||
|
||||
.text :
|
||||
{
|
||||
vectors.o(.text)
|
||||
. = 0x10 ;
|
||||
boot.o(.text)
|
||||
exceptions.o(.text)
|
||||
*(.*text*)
|
||||
}
|
||||
|
||||
. = 0x00001000 ;
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.rodata*)
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
_gp = ALIGN(16) + 0x7ff0;
|
||||
|
||||
.got :
|
||||
{
|
||||
*(.got)
|
||||
}
|
||||
|
||||
.sdata :
|
||||
{
|
||||
*(.*sdata*)
|
||||
}
|
||||
|
||||
_bss_start = . ;
|
||||
|
||||
.sbss :
|
||||
{
|
||||
*(.*sbss)
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.*bss)
|
||||
}
|
||||
|
||||
_bss_end = . ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* File : bintohex.c
|
||||
* Project : University of Utah, XUM Project
|
||||
* Creator(s) : Grant Ayers (ayers@cs.utah.edu)
|
||||
*
|
||||
* Modification History:
|
||||
* Rev Date Initials Description of Change
|
||||
* 1.0 4-1-2011 GEA Initial design.
|
||||
*
|
||||
* Standards/Formatting:
|
||||
* C, 8 hard tab, 80 column
|
||||
*
|
||||
* Description:
|
||||
* Converts binary data into human-readable hex data.
|
||||
* This is useful for FPGA block RAM initialization data,
|
||||
* which is typically read in from a file in hex format.
|
||||
* For block RAM cores, a .COE file is required, which is
|
||||
* basically a hex file with some additional syntax. This
|
||||
* utility will output in either format and can pad with
|
||||
* zeros to a certain length.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
void usage(void);
|
||||
unsigned int doEndian(unsigned int val, int bigEndian);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *file;
|
||||
char *i_name, *o_name;
|
||||
int i_size;
|
||||
unsigned int *input;
|
||||
unsigned int data = 0;
|
||||
int pad_length = 0;
|
||||
int endian = -1;
|
||||
int coe = 0;
|
||||
int ch, i;
|
||||
|
||||
while ((ch = getopt(argc, argv, "chbp:")) != -1)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'c':
|
||||
coe = 1;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case 'b':
|
||||
endian = 1;
|
||||
break;
|
||||
case 'p':
|
||||
pad_length = (int)strtol(optarg,
|
||||
(char **)NULL, 10);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
usage();
|
||||
}
|
||||
|
||||
i_name = argv[0];
|
||||
o_name = argv[1];
|
||||
|
||||
|
||||
/* Read the input file */
|
||||
file = fopen(i_name, "rb");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Error: Could not open \"%s\".\n", i_name);
|
||||
exit(1);
|
||||
}
|
||||
fseek(file, 0L, SEEK_END);
|
||||
i_size = (int)ftell(file);
|
||||
if ((i_size < 0) || (ftell(file) > (long)i_size)) {
|
||||
fprintf(stderr, "Error: Input file is too large.\n");
|
||||
exit(1);
|
||||
}
|
||||
fseek(file, 0L, SEEK_SET);
|
||||
input = (unsigned int*)malloc(i_size);
|
||||
if (input == NULL) {
|
||||
fprintf(stderr, "Error: Could not allocate %d bytes of "
|
||||
"memory.\n", i_size);
|
||||
exit(1);
|
||||
}
|
||||
if (fread(input, 1, i_size, file) != i_size) {
|
||||
fprintf(stderr, "Error reading input file.\n");
|
||||
exit(1);
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
/* Write the output file */
|
||||
file = fopen(o_name, "wb+");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Error: Could not open \"%s\" for "
|
||||
"writing.\n", o_name);
|
||||
exit(1);
|
||||
}
|
||||
if (coe) {
|
||||
fprintf(file, "memory_initialization_radix=16;\n"
|
||||
"memory_initialization_vector=\n");
|
||||
}
|
||||
for (i=0; i<(i_size/4); i++) {
|
||||
if (i != 0) {
|
||||
if (coe) {
|
||||
fprintf(file, ",\n");
|
||||
}
|
||||
else {
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
}
|
||||
fprintf(file, "%08x", doEndian(input[i], endian));
|
||||
}
|
||||
if (coe) {
|
||||
fprintf(file, ";\n");
|
||||
}
|
||||
else {
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
for (i=((i_size/4)*4); i<(i_size); i++) {
|
||||
if (endian < 0) {
|
||||
data <<= 8;
|
||||
data |= (0x000000FF & ((char*)input)[i]);
|
||||
}
|
||||
else {
|
||||
data >>= 8;
|
||||
data |= (0xFF000000 & (((char*)input)[i] << 24));
|
||||
}
|
||||
}
|
||||
if ((i_size%4) != 0) {
|
||||
if (coe) {
|
||||
fprintf(file, "%08x;\n", data);
|
||||
}
|
||||
else {
|
||||
fprintf(file, "%08x\n", data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pad the output for non-COE files */
|
||||
if ((pad_length > 0) && !coe) {
|
||||
ch = (i_size/4) + (((i_size%4) != 0) ? 1 : 0);
|
||||
for (i=ch; i<pad_length; i++) {
|
||||
fprintf(file, "00000000\n");
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("Usage: bintohex [-p <pad length>] [-b (Big Endian)] "
|
||||
"[-c (Make COE file)] <input> <output>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
unsigned int doEndian(unsigned int val, int bigEndian)
|
||||
{
|
||||
if (bigEndian == 1) {
|
||||
return (((val >> 24)&0xff) | ((val<<8)&0xff0000) |
|
||||
((val>>8)&0xff00) | ((val<<24)&0xff000000));
|
||||
}
|
||||
else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* File : bintoxum.c
|
||||
* Project : University of Utah, XUM Project
|
||||
* Creator(s) : Grant Ayers (ayers@cs.utah.edu)
|
||||
*
|
||||
* Modification History:
|
||||
* Rev Date Initials Description of Change
|
||||
* 1.0 7-3-2012 GEA Initial Design.
|
||||
*
|
||||
* Standards/Formatting:
|
||||
* C, 8 hard tab, 80 column
|
||||
*
|
||||
* Description:
|
||||
* Combines the text (instruction) and data sections of an
|
||||
* executable into one file. You can think of this as a very
|
||||
* simple version of ELF or a.out files.
|
||||
*
|
||||
* The XUM processor has a simple flat physical address space
|
||||
* which contains instructions and data. The output file from
|
||||
* this utility is directly loadable into this memory, byte-for-byte,
|
||||
* without using any kind of "intelligent" loader. It takes two
|
||||
* binary input files, the instructions and data, and an offset
|
||||
* address (decimal) for the data segment to begin, and outputs
|
||||
* a file which can be sent directly to hardware via the XUM
|
||||
* bootloader or other means.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void usage(void);
|
||||
void read_file(char *name, int *size, char **buf);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *file;
|
||||
char *it_name, *id_name, *o_name;
|
||||
int it_size, id_size;
|
||||
char *it_buf, *id_buf;
|
||||
int data_start_addr;
|
||||
int pad;
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, argv, "d:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
data_start_addr = (int)strtol(optarg,
|
||||
(char **)NULL, 10);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 3) {
|
||||
usage();
|
||||
}
|
||||
|
||||
it_name = argv[0];
|
||||
id_name = argv[1];
|
||||
o_name = argv[2];
|
||||
|
||||
read_file(it_name, &it_size, &it_buf);
|
||||
read_file(id_name, &id_size, &id_buf);
|
||||
|
||||
/* Open the output file */
|
||||
file = fopen(o_name, "wb+");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Error: Could not open \"%s\" for "
|
||||
"writing.\n", o_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Copy text segment directly to output file */
|
||||
if (fwrite((void *)it_buf, 1, it_size, file) != it_size) {
|
||||
fprintf(stderr, "Error writing to output file.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Pad until the data segment */
|
||||
it_buf[0] = 0;
|
||||
while (it_size < data_start_addr) {
|
||||
if (fwrite((void *)it_buf, 1, 1, file) != 1) {
|
||||
fprintf(stderr, "Error writing to output file.\n");
|
||||
exit(1);
|
||||
}
|
||||
it_size++;
|
||||
}
|
||||
|
||||
/* Copy data segment to output file */
|
||||
if (fwrite((void *)id_buf, 1, id_size, file) != id_size) {
|
||||
fprintf(stderr, "Error writing to output file.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Pad the data section to word length if needed */
|
||||
/* NOTE: Assumes only padding needed would be at the end. */
|
||||
pad = ((id_size % 4) != 0) ? 4 - (id_size % 4) : 0;
|
||||
if (pad != 0) {
|
||||
memset((void *)id_buf, 0, 4);
|
||||
if (fwrite((void *)id_buf, 1, pad, file) != pad) {
|
||||
fprintf(stderr, "Error writing to output file.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: bintoxum [-d data start address] "
|
||||
"<text file> <data file> <output file>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void read_file(char *name, int *size, char **buf)
|
||||
{
|
||||
FILE *file;
|
||||
|
||||
file = fopen(name, "rb");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Error: Could not open \"%s\".\n", name);
|
||||
exit(1);
|
||||
}
|
||||
fseek(file, 0L, SEEK_END);
|
||||
*size = (int)ftell(file);
|
||||
if ((*size < 0) || (ftell(file) > (long)*size)) {
|
||||
fprintf(stderr, "Error: Input file is too large.\n");
|
||||
exit(1);
|
||||
}
|
||||
fseek(file, 0L, SEEK_SET);
|
||||
*buf = (char *)malloc(*size);
|
||||
if (*buf == NULL) {
|
||||
fprintf(stderr, "Error: Could not allocate %d bytes "
|
||||
"of memory.\n", *size);
|
||||
exit(1);
|
||||
}
|
||||
if (fread(*buf, 1, *size, file) != *size) {
|
||||
fprintf(stderr, "Error reading input file.\n");
|
||||
exit(1);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* File : ram_image.c
|
||||
* Project : University of Utah, XUM Project
|
||||
* Creator(s) : Grant Ayers (ayers@cs.utah.edu)
|
||||
*
|
||||
* Modification History:
|
||||
* Rev Date Initials Description of Change
|
||||
* 1.0 7-8-2011 GEA Initial design.
|
||||
*
|
||||
* Standards/Formatting:
|
||||
* C, 8 hard tab, 80 column
|
||||
*
|
||||
* Description:
|
||||
* Fills a specific type of Verilog file which contains a
|
||||
* Block RAM primitive with the initialization vectors from
|
||||
* 'code.txt' and outputs 'imem_filled.v'.
|
||||
*
|
||||
* This utility is useful for filling simple and small block
|
||||
* RAMs, especially for basic simulations. However it is no
|
||||
* longer used for the production XUM project.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void quit(int val);
|
||||
int inject(char* vectors, char* output);
|
||||
|
||||
FILE* verilog;
|
||||
FILE* vectors;
|
||||
FILE* output;
|
||||
char* out_buf = NULL;
|
||||
char* vec_buf = NULL;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int verilog_size, vectors_size;
|
||||
int inst_written;
|
||||
|
||||
|
||||
if (argc < 4)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s: <in.v> <in_code.txt> <out.v>\n", argv[0]);
|
||||
fprintf(stderr, "Usage: %s: ram_xilinx.v code.txt ram_image.v\n", argv[0]);
|
||||
quit(1);
|
||||
}
|
||||
|
||||
/* Open the Verilog source file and copy it into a buffer */
|
||||
verilog = fopen(argv[1], "rb");
|
||||
if (!verilog)
|
||||
{
|
||||
fprintf(stderr, "Could not open \"%s\".\n", argv[1]);
|
||||
quit(1);
|
||||
}
|
||||
fseek(verilog, 0L, SEEK_END);
|
||||
verilog_size = ftell(verilog);
|
||||
fseek(verilog, 0L, SEEK_SET);
|
||||
if (verilog_size == 0)
|
||||
{
|
||||
fprintf(stderr, "Error: Empty verilog input file.\n");
|
||||
quit(1);
|
||||
}
|
||||
out_buf = malloc(verilog_size);
|
||||
if (!out_buf)
|
||||
{
|
||||
fprintf(stderr, "Error allocating memory.\n");
|
||||
quit(1);
|
||||
}
|
||||
if (fread(out_buf, 1, verilog_size, verilog) != verilog_size)
|
||||
{
|
||||
fprintf(stderr, "Error reading input file.\n");
|
||||
quit(1);
|
||||
}
|
||||
|
||||
|
||||
/* Open code vectors and copy them into a buffer */
|
||||
vectors = fopen(argv[2], "rb");
|
||||
if (!vectors)
|
||||
{
|
||||
fprintf(stderr, "Could not open \"%s\".\n", argv[2]);
|
||||
quit(1);
|
||||
}
|
||||
fseek(vectors, 0L, SEEK_END);
|
||||
vectors_size = ftell(vectors);
|
||||
fseek(vectors, 0L, SEEK_SET);
|
||||
if (vectors_size == 0)
|
||||
{
|
||||
fprintf(stderr, "Error: Empty vectors file.\n");
|
||||
quit(1);
|
||||
}
|
||||
//printf("Vectors size is %d bytes.\n", vectors_size);
|
||||
vec_buf = malloc(vectors_size+1);
|
||||
if (!vec_buf)
|
||||
{
|
||||
fprintf(stderr, "Error allocating memory.\n");
|
||||
quit(1);
|
||||
}
|
||||
if (fread(vec_buf, 1, vectors_size, vectors) != vectors_size)
|
||||
{
|
||||
fprintf(stderr, "Error reading vectors file.\n");
|
||||
quit(1);
|
||||
}
|
||||
vec_buf[vectors_size] = '\0';
|
||||
|
||||
/* Inject code */
|
||||
inst_written = inject(vec_buf, out_buf);
|
||||
printf("Wrote %d instructions.\n", inst_written);
|
||||
|
||||
/* Write output file */
|
||||
output = fopen(argv[3], "wb");
|
||||
if (output == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error writing %s!\n", argv[3]);
|
||||
quit(1);
|
||||
}
|
||||
fwrite(out_buf, 1, verilog_size, output);
|
||||
fclose(output);
|
||||
|
||||
|
||||
// Exit
|
||||
quit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int inject(char* vectors, char* output)
|
||||
{
|
||||
const char* delimeters = " \t\r\n";
|
||||
char row_key[15]; // ".INIT_XX(256'h"
|
||||
char* token;
|
||||
char* position;
|
||||
int row = 0;
|
||||
int col = 7;
|
||||
int total = 0;
|
||||
|
||||
token = strtok(vectors, delimeters);
|
||||
snprintf(row_key, 14, ".INIT_%02X(256'h", row);
|
||||
while ((token != NULL) && (row < 128))
|
||||
{
|
||||
//printf("Got a token: \"%s\"\n", token);
|
||||
if (strlen(token) != 8)
|
||||
{
|
||||
fprintf(stderr, "Error: Vector \"%s\" is not "
|
||||
"a 32-bit hexadecimal number.\n", token);
|
||||
quit(1);
|
||||
}
|
||||
position = strstr(output, row_key);
|
||||
if (position == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: Could not find initialization "
|
||||
"row %02X (hex) in the Block RAM. Check that "
|
||||
"it has sufficient memory.\n", row);
|
||||
printf("\n\n\nDEBUG\n%s\n", output);
|
||||
quit(1);
|
||||
}
|
||||
//position += (14 + col + (8 * col));
|
||||
position += (14 + (8 * col));
|
||||
memcpy(position, token, 8);
|
||||
total++;
|
||||
col--;
|
||||
if (col < 0)
|
||||
{
|
||||
col = 7;
|
||||
row++;
|
||||
snprintf(row_key, 14, ".INIT_%02X(256'h", row);
|
||||
}
|
||||
//printf("Col is %d row is %d\n", col, row);
|
||||
token = strtok(NULL, delimeters);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
void quit(int val)
|
||||
{
|
||||
if (verilog) {
|
||||
fclose(verilog);
|
||||
}
|
||||
if (vectors) {
|
||||
fclose(vectors);
|
||||
}
|
||||
if (output) {
|
||||
fclose(output);
|
||||
}
|
||||
if (out_buf) {
|
||||
free(out_buf);
|
||||
}
|
||||
if (vec_buf) {
|
||||
free(vec_buf);
|
||||
}
|
||||
|
||||
if (val != 0) {
|
||||
exit(val);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user