Initial commit

This commit is contained in:
muellerlu
2026-05-29 10:19:13 +02:00
commit fedfd92270
726 changed files with 542654 additions and 0 deletions
+4
View File
@@ -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
@@ -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;
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
}
@@ -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
@@ -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;
}
@@ -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
@@ -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);
}
@@ -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
@@ -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++;
}
@@ -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
@@ -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,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
@@ -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;
}
@@ -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
@@ -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);
}
@@ -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
@@ -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++;
}
@@ -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
@@ -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
@@ -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
@@ -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;
}
@@ -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
@@ -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);
}
@@ -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
@@ -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++;
}
@@ -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
@@ -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,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
@@ -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);
}
@@ -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,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);
}
@@ -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
@@ -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;
}
@@ -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
@@ -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;
}
@@ -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
@@ -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);
}
@@ -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,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
@@ -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++;
}
@@ -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
@@ -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
@@ -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
@@ -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