URL
https://opencores.org/ocsvn/eco32/eco32/trunk
Subversion Repositories eco32
Compare Revisions
- This comparison shows the changes necessary to convert path
/eco32/trunk
- from Rev 17 to Rev 18
- ↔ Reverse comparison
Rev 17 → Rev 18
/stdalone/shpart/iolib.c
0,0 → 1,329
/* |
* iolib.c -- I/O library |
*/ |
|
|
#include "types.h" |
#include "stdarg.h" |
#include "iolib.h" |
#include "biolib.h" |
|
|
/**************************************************************/ |
|
/* string functions */ |
|
|
int strlen(char *str) { |
int i; |
|
i = 0; |
while (*str++ != '\0') { |
i++; |
} |
return i; |
} |
|
|
void strcpy(char *dst, char *src) { |
while ((*dst++ = *src++) != '\0') ; |
} |
|
|
void memcpy(unsigned char *dst, unsigned char *src, unsigned int cnt) { |
while (cnt--) { |
*dst++ = *src++; |
} |
} |
|
|
/**************************************************************/ |
|
/* terminal I/O */ |
|
|
char getchar(void) { |
return getc(); |
} |
|
|
void putchar(char c) { |
if (c == '\n') { |
putchar('\r'); |
} |
putc(c); |
} |
|
|
void putString(char *s) { |
while (*s != '\0') { |
putchar(*s++); |
} |
} |
|
|
/**************************************************************/ |
|
/* get a line from the terminal */ |
|
|
void getLine(char *prompt, char *line, int max) { |
int index; |
char c; |
|
putString(prompt); |
putString(line); |
index = strlen(line); |
while (1) { |
c = getchar(); |
switch (c) { |
case '\r': |
putchar('\n'); |
line[index] = '\0'; |
return; |
case '\b': |
case 0x7F: |
if (index == 0) { |
break; |
} |
putchar('\b'); |
putchar(' '); |
putchar('\b'); |
index--; |
break; |
default: |
if (c == '\t') { |
c = ' '; |
} |
if (c < 0x20 || c > 0x7E) { |
break; |
} |
putchar(c); |
line[index++] = c; |
break; |
} |
} |
} |
|
|
/**************************************************************/ |
|
/* scaled-down version of printf */ |
|
|
/* |
* Count the number of characters needed to represent |
* a given number in base 10. |
*/ |
int countPrintn(long n) { |
long a; |
int res; |
|
res = 0; |
if (n < 0) { |
res++; |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
res += countPrintn(a); |
} |
return res + 1; |
} |
|
|
/* |
* Output a number in base 10. |
*/ |
void printn(long n) { |
long a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
/* |
* Count the number of characters needed to represent |
* a given number in a given base. |
*/ |
int countPrintu(unsigned long n, unsigned long b) { |
unsigned long a; |
int res; |
|
res = 0; |
a = n / b; |
if (a != 0) { |
res += countPrintu(a, b); |
} |
return res + 1; |
} |
|
|
/* |
* Output a number in a given base. |
*/ |
void printu(unsigned long n, unsigned long b, Bool upperCase) { |
unsigned long a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b, upperCase); |
} |
if (upperCase) { |
putchar("0123456789ABCDEF"[n % b]); |
} else { |
putchar("0123456789abcdef"[n % b]); |
} |
} |
|
|
/* |
* Output a number of filler characters. |
*/ |
void fill(int numFillers, char filler) { |
while (numFillers-- > 0) { |
putchar(filler); |
} |
} |
|
|
/* |
* Formatted output with a variable argument list. |
*/ |
void vprintf(char *fmt, va_list ap) { |
char c; |
int n; |
long ln; |
unsigned int u; |
unsigned long lu; |
char *s; |
Bool negFlag; |
char filler; |
int width, count; |
|
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == '-') { |
negFlag = TRUE; |
c = *fmt++; |
} else { |
negFlag = FALSE; |
} |
if (c == '0') { |
filler = '0'; |
c = *fmt++; |
} else { |
filler = ' '; |
} |
width = 0; |
while (c >= '0' && c <= '9') { |
width *= 10; |
width += c - '0'; |
c = *fmt++; |
} |
if (c == 'd') { |
n = va_arg(ap, int); |
count = countPrintn(n); |
if (width > 0 && !negFlag) { |
fill(width - count, filler); |
} |
printn(n); |
if (width > 0 && negFlag) { |
fill(width - count, filler); |
} |
} else |
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') { |
u = va_arg(ap, int); |
count = countPrintu(u, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10)); |
if (width > 0 && !negFlag) { |
fill(width - count, filler); |
} |
printu(u, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10), |
c == 'X'); |
if (width > 0 && negFlag) { |
fill(width - count, filler); |
} |
} else |
if (c == 'l') { |
c = *fmt++; |
if (c == 'd') { |
ln = va_arg(ap, long); |
count = countPrintn(ln); |
if (width > 0 && !negFlag) { |
fill(width - count, filler); |
} |
printn(ln); |
if (width > 0 && negFlag) { |
fill(width - count, filler); |
} |
} else |
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') { |
lu = va_arg(ap, long); |
count = countPrintu(lu, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10)); |
if (width > 0 && !negFlag) { |
fill(width - count, filler); |
} |
printu(lu, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10), |
c == 'X'); |
if (width > 0 && negFlag) { |
fill(width - count, filler); |
} |
} else { |
putchar('l'); |
putchar(c); |
} |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
count = strlen(s); |
if (width > 0 && !negFlag) { |
fill(width - count, filler); |
} |
while ((c = *s++) != '\0') { |
putchar(c); |
} |
if (width > 0 && negFlag) { |
fill(width - count, filler); |
} |
} else |
if (c == 'c') { |
c = va_arg(ap, char); |
putchar(c); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/* |
* Formatted output. |
* This is a scaled-down version of the C library's |
* printf. Used to print diagnostic information on |
* the console (and optionally to a logfile). |
*/ |
void printf(char *fmt, ...) { |
va_list ap; |
|
va_start(ap, fmt); |
vprintf(fmt, ap); |
va_end(ap); |
} |
/stdalone/shpart/biolib.c
0,0 → 1,26
/* |
* biolib.c -- basic I/O library |
*/ |
|
|
#include "biolib.h" |
|
|
char getc(void) { |
unsigned int *base; |
char c; |
|
base = (unsigned int *) 0xF0300000; |
while ((*(base + 0) & 1) == 0) ; |
c = *(base + 1); |
return c; |
} |
|
|
void putc(char c) { |
unsigned int *base; |
|
base = (unsigned int *) 0xF0300000; |
while ((*(base + 2) & 1) == 0) ; |
*(base + 3) = c; |
} |
/stdalone/shpart/start.h
0,0 → 1,21
/* |
* start.h -- startup code |
*/ |
|
|
#ifndef _START_H_ |
#define _START_H_ |
|
|
typedef int (*ISR)(int irq); |
|
|
void enable(void); |
void disable(void); |
int getMask(void); |
void setMask(int mask); |
ISR getISR(int irq); |
void setISR(int irq, ISR isr); |
|
|
#endif /* _START_H_ */ |
/stdalone/shpart/iolib.h
0,0 → 1,21
/* |
* iolib.h -- I/O library |
*/ |
|
|
#ifndef _IOLIB_H_ |
#define _IOLIB_H_ |
|
|
int strlen(char *str); |
void strcpy(char *dst, char *src); |
void memcpy(unsigned char *dst, unsigned char *src, unsigned int cnt); |
char getchar(void); |
void putchar(char c); |
void putString(char *s); |
void getLine(char *prompt, char *line, int max); |
void vprintf(char *fmt, va_list ap); |
void printf(char *fmt, ...); |
|
|
#endif /* _IOLIB_H_ */ |
/stdalone/shpart/main.c
0,0 → 1,229
/* |
* main.c -- show partitions on a disk |
*/ |
|
|
#include "types.h" |
#include "stdarg.h" |
#include "iolib.h" |
#include "start.h" |
#include "idedsk.h" |
|
|
#define NPE (SECTOR_SIZE / sizeof(PartEntry)) |
#define DESCR_SIZE 20 |
|
|
typedef struct { |
unsigned long type; |
unsigned long start; |
unsigned long size; |
char descr[DESCR_SIZE]; |
} PartEntry; |
|
PartEntry ptr[NPE]; |
|
|
/**************************************************************/ |
|
|
void error(char *fmt, ...) { |
va_list ap; |
|
va_start(ap, fmt); |
printf("Error: "); |
vprintf(fmt, ap); |
printf(", halting...\n"); |
va_end(ap); |
while (1) ; |
} |
|
|
/**************************************************************/ |
|
|
unsigned long getNumber(unsigned char *p) { |
return (unsigned long) *(p + 0) << 24 | |
(unsigned long) *(p + 1) << 16 | |
(unsigned long) *(p + 2) << 8 | |
(unsigned long) *(p + 3) << 0; |
} |
|
|
void convertPartitionTable(PartEntry *e, int n) { |
int i; |
unsigned char *p; |
|
for (i = 0; i < n; i++) { |
p = (unsigned char *) &e[i]; |
e[i].type = getNumber(p + 0); |
e[i].start = getNumber(p + 4); |
e[i].size = getNumber(p + 8); |
} |
} |
|
|
/**************************************************************/ |
|
|
static char *exceptionCause[32] = { |
/* 00 */ "terminal 0 transmitter interrupt", |
/* 01 */ "terminal 0 receiver interrupt", |
/* 02 */ "terminal 1 transmitter interrupt", |
/* 03 */ "terminal 1 receiver interrupt", |
/* 04 */ "keyboard interrupt", |
/* 05 */ "unknown interrupt", |
/* 06 */ "unknown interrupt", |
/* 07 */ "unknown interrupt", |
/* 08 */ "disk interrupt", |
/* 09 */ "unknown interrupt", |
/* 10 */ "unknown interrupt", |
/* 11 */ "unknown interrupt", |
/* 12 */ "unknown interrupt", |
/* 13 */ "unknown interrupt", |
/* 14 */ "timer interrupt", |
/* 15 */ "unknown interrupt", |
/* 16 */ "bus timeout exception", |
/* 17 */ "illegal instruction exception", |
/* 18 */ "privileged instruction exception", |
/* 19 */ "divide instruction exception", |
/* 20 */ "trap instruction exception", |
/* 21 */ "TLB miss exception", |
/* 22 */ "TLB write exception", |
/* 23 */ "TLB invalid exception", |
/* 24 */ "illegal address exception", |
/* 25 */ "privileged address exception", |
/* 26 */ "unknown exception", |
/* 27 */ "unknown exception", |
/* 28 */ "unknown exception", |
/* 29 */ "unknown exception", |
/* 30 */ "unknown exception", |
/* 31 */ "unknown exception" |
}; |
|
|
int defaultISR(int irq) { |
printf("\n%s\n", exceptionCause[irq]); |
return 0; /* do not skip any instruction */ |
} |
|
|
void initInterrupts(void) { |
int i; |
|
for (i = 0; i < 32; i++) { |
setISR(i, defaultISR); |
} |
} |
|
|
/**************************************************************/ |
|
|
Bool checkDiskReady(void) { |
int tries; |
int i; |
|
for (tries = 0; tries < 10; tries++) { |
for (i = 0; i < 500000; i++) { |
if ((*DISK_CTRL & DISK_CTRL_READY) != 0) { |
return TRUE; |
} |
} |
printf("."); |
} |
return FALSE; |
} |
|
|
unsigned long getDiskSize(void) { |
return *DISK_CAP; |
} |
|
|
Bool readDisk(unsigned long sector, |
unsigned int count, |
unsigned int *addr) { |
unsigned int n; |
unsigned int *p; |
unsigned int i; |
|
while (count != 0) { |
n = count > 8 ? 8 : count; |
*DISK_SCT = sector; |
*DISK_CNT = n; |
*DISK_CTRL = DISK_CTRL_STRT; |
while ((*DISK_CTRL & DISK_CTRL_DONE) == 0) ; |
if (*DISK_CTRL & DISK_CTRL_ERR) { |
return FALSE; |
} |
p = DISK_BUFFER; |
for (i = 0; i < n * SECTOR_SIZE / sizeof(unsigned int); i++) { |
*addr++ = *p++; |
} |
sector += n; |
count -= n; |
} |
return TRUE; |
} |
|
|
/**************************************************************/ |
|
|
void main(void) { |
unsigned long numSectors; |
unsigned long partLast; |
int i, j; |
char c; |
|
/* init interrupts */ |
initInterrupts(); |
/* check disk ready */ |
if (!checkDiskReady()) { |
error("disk not ready"); |
} |
/* determine disk size */ |
numSectors = getDiskSize(); |
printf("Disk has %lu (0x%lX) sectors.\n", |
numSectors, numSectors); |
if (numSectors < 32) { |
error("disk is too small"); |
} |
/* read partition table record */ |
if (!readDisk(1, 1, (unsigned int *) ptr)) { |
error("cannot read partition table from disk"); |
} |
convertPartitionTable(ptr, NPE); |
/* show partition table */ |
printf("Partitions:\n"); |
printf(" # b type start last size description\n"); |
for (i = 0; i < NPE; i++) { |
if (ptr[i].type != 0) { |
partLast = ptr[i].start + ptr[i].size - 1; |
} else { |
partLast = 0; |
} |
printf("%2d %s 0x%08lX 0x%08lX 0x%08lX 0x%08lX ", |
i, |
ptr[i].type & 0x80000000 ? "*" : " ", |
ptr[i].type & 0x7FFFFFFF, |
ptr[i].start, |
partLast, |
ptr[i].size); |
for (j = 0; j < DESCR_SIZE; j++) { |
c = ptr[i].descr[j]; |
if (c == '\0') { |
break; |
} |
if (c >= 0x20 && c < 0x7F) { |
printf("%c", c); |
} else { |
printf("."); |
} |
} |
printf("\n"); |
} |
/* done */ |
printf("Halting...\n"); |
} |
/stdalone/shpart/biolib.h
0,0 → 1,14
/* |
* biolib.h -- basic I/O library |
*/ |
|
|
#ifndef _BIOLIB_H_ |
#define _BIOLIB_H_ |
|
|
char getc(void); |
void putc(char c); |
|
|
#endif /* _BIOLIB_H_ */ |
/stdalone/shpart/end.s
0,0 → 1,19
; |
; end.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/shpart/idedsk.h
0,0 → 1,32
/* |
* idedsk.h -- IDE disk definitions |
*/ |
|
|
#ifndef _IDEDSK_H_ |
#define _IDEDSK_H_ |
|
|
#define SECTOR_SIZE 512 |
#define WPS (SECTOR_SIZE / sizeof(unsigned int)) |
|
#define DISK_BASE ((unsigned *) 0xF0400000) /* disk base address */ |
#define DISK_CTRL (DISK_BASE + 0) /* control/status register */ |
#define DISK_CNT (DISK_BASE + 1) /* sector count register */ |
#define DISK_SCT (DISK_BASE + 2) /* disk sector register */ |
#define DISK_CAP (DISK_BASE + 3) /* disk capacity register */ |
#define DISK_BUFFER ((unsigned *) 0xF0480000) /* address of disk buffer */ |
|
#define DISK_CTRL_STRT 0x01 /* a 1 written here starts the disk command */ |
#define DISK_CTRL_IEN 0x02 /* enable disk interrupt */ |
#define DISK_CTRL_WRT 0x04 /* command type: 0 = read, 1 = write */ |
#define DISK_CTRL_ERR 0x08 /* 0 = ok, 1 = error; valid when DONE = 1 */ |
#define DISK_CTRL_DONE 0x10 /* 1 = disk has finished the command */ |
#define DISK_CTRL_READY 0x20 /* 1 = capacity valid, disk accepts command */ |
|
#define DISK_IRQ 8 /* disk interrupt number */ |
|
#define READY_RETRIES 1000000 /* retries to wait for disk to get ready */ |
|
|
#endif /* _IDEDSK_H_ */ |
/stdalone/shpart/types.h
0,0 → 1,16
/* |
* types.h -- additional types |
*/ |
|
|
#ifndef _TYPES_H_ |
#define _TYPES_H_ |
|
|
typedef int Bool; |
|
#define FALSE 0 |
#define TRUE 1 |
|
|
#endif /* _TYPES_H_ */ |
/stdalone/shpart/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/shpart/Makefile
0,0 → 1,28
# |
# Makefile for "shpart", a program to show the partitions on a hard disk |
# |
|
BUILD = ../../build |
|
SRC = start.s main.c iolib.c biolib.c end.s |
BIN = shpart.bin |
MAP = shpart.map |
|
.PHONY: all install run clean |
|
all: $(BIN) |
|
install: $(BIN) |
mkdir -p $(BUILD)/stdalone |
cp $(BIN) $(BUILD)/stdalone |
cp $(MAP) $(BUILD)/stdalone |
|
run: $(BIN) |
$(BUILD)/bin/sim -i -t 1 -l $(BIN) -d $(BUILD)/disk/disk.img |
|
$(BIN): $(SRC) |
$(BUILD)/bin/lcc -A -Wo-kernel \ |
-Wl-m -Wl$(MAP) -o $(BIN) $(SRC) |
|
clean: |
rm -f *~ $(BIN) $(MAP) |
/stdalone/shpart/start.s
0,0 → 1,228
; |
; start.s -- startup code |
; |
|
.import main |
.import _ecode |
.import _edata |
.import _ebss |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export enable |
.export disable |
.export getMask |
.export setMask |
.export getISR |
.export setISR |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
|
; reset arrives here |
reset: |
j start |
|
; interrupts arrive here |
intrpt: |
j isr |
|
; user TLB misses arrive here |
userMiss: |
j userMiss |
|
isr: |
add $26,$29,$0 ; sp -> $26 |
add $27,$1,$0 ; $1 -> $27 |
add $29,$0,istack ; set stack |
sub $29,$29,108 |
stw $2,$29,0 ; save registers |
stw $3,$29,4 |
stw $4,$29,8 |
stw $5,$29,12 |
stw $6,$29,16 |
stw $7,$29,20 |
stw $8,$29,24 |
stw $9,$29,28 |
stw $10,$29,32 |
stw $11,$29,36 |
stw $12,$29,40 |
stw $13,$29,44 |
stw $14,$29,48 |
stw $15,$29,52 |
stw $16,$29,56 |
stw $17,$29,60 |
stw $18,$29,64 |
stw $19,$29,68 |
stw $20,$29,72 |
stw $21,$29,76 |
stw $22,$29,80 |
stw $23,$29,84 |
stw $24,$29,88 |
stw $25,$29,92 |
stw $26,$29,96 |
stw $27,$29,100 |
stw $31,$29,104 |
mvfs $4,0 ; $4 = IRQ number |
slr $4,$4,16 |
and $4,$4,0x1F |
sll $26,$4,2 ; $26 = 4 * IRQ number |
ldw $26,$26,irqsrv ; get addr of service routine |
jalr $26 ; call service routine |
beq $2,$0,resume ; resume instruction if ISR returned 0 |
add $30,$30,4 ; else skip offending instruction |
resume: |
ldw $2,$29,0 |
ldw $3,$29,4 |
ldw $4,$29,8 |
ldw $5,$29,12 |
ldw $6,$29,16 |
ldw $7,$29,20 |
ldw $8,$29,24 |
ldw $9,$29,28 |
ldw $10,$29,32 |
ldw $11,$29,36 |
ldw $12,$29,40 |
ldw $13,$29,44 |
ldw $14,$29,48 |
ldw $15,$29,52 |
ldw $16,$29,56 |
ldw $17,$29,60 |
ldw $18,$29,64 |
ldw $19,$29,68 |
ldw $20,$29,72 |
ldw $21,$29,76 |
ldw $22,$29,80 |
ldw $23,$29,84 |
ldw $24,$29,88 |
ldw $25,$29,92 |
ldw $26,$29,96 |
ldw $27,$29,100 |
ldw $31,$29,104 |
add $1,$27,$0 ; $27 -> $1 |
add $29,$26,0 ; $26 -> sp |
rfx ; return from exception |
|
start: |
mvfs $8,0 |
or $8,$8,1 << 27 ; let vector point to RAM |
mvts $8,0 |
add $29,$0,stack ; set sp |
add $10,$0,_bdata ; copy data segment |
add $8,$0,_edata |
sub $9,$8,$10 |
add $9,$9,_ecode |
j cpytest |
cpyloop: |
ldw $11,$9,0 |
stw $11,$8,0 |
cpytest: |
sub $8,$8,4 |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
add $8,$0,_bbss ; clear bss |
add $9,$0,_ebss |
j clrtest |
clrloop: |
stw $0,$8,0 |
add $8,$8,4 |
clrtest: |
bltu $8,$9,clrloop |
jal main ; call 'main' |
start1: |
j start1 ; loop |
|
enable: |
mvfs $8,0 |
or $8,$8,1 << 23 |
mvts $8,0 |
jr $31 |
|
disable: |
mvfs $8,0 |
and $8,$8,~(1 << 23) |
mvts $8,0 |
jr $31 |
|
getMask: |
mvfs $8,0 |
and $2,$8,0x0000FFFF |
jr $31 |
|
setMask: |
mvfs $8,0 |
and $8,$8,0xFFFF0000 |
and $4,$4,0x0000FFFF |
or $8,$8,$4 |
mvts $8,0 |
jr $31 |
|
getISR: |
sll $4,$4,2 |
ldw $2,$4,irqsrv |
jr $31 |
|
setISR: |
sll $4,$4,2 |
stw $5,$4,irqsrv |
jr $31 |
|
.data |
|
; interrupt service routine table |
|
.align 4 |
|
irqsrv: |
.word 0 ; 00: terminal 0 transmitter interrupt |
.word 0 ; 01: terminal 0 receiver interrupt |
.word 0 ; 02: terminal 1 transmitter interrupt |
.word 0 ; 03: terminal 1 receiver interrupt |
.word 0 ; 04: keyboard interrupt |
.word 0 ; 05: unused |
.word 0 ; 06: unused |
.word 0 ; 07: unused |
.word 0 ; 08: disk interrupt |
.word 0 ; 09: unused |
.word 0 ; 10: unused |
.word 0 ; 11: unused |
.word 0 ; 12: unused |
.word 0 ; 13: unused |
.word 0 ; 14: timer interrupt |
.word 0 ; 15: unused |
.word 0 ; 16: bus timeout exception |
.word 0 ; 17: illegal instruction exception |
.word 0 ; 18: privileged instruction exception |
.word 0 ; 19: divide instruction exception |
.word 0 ; 20: trap instruction exception |
.word 0 ; 21: TLB miss exception |
.word 0 ; 22: TLB write exception |
.word 0 ; 23: TLB invalid exception |
.word 0 ; 24: illegal address exception |
.word 0 ; 25: privileged address exception |
.word 0 ; 26: unused |
.word 0 ; 27: unused |
.word 0 ; 28: unused |
.word 0 ; 29: unused |
.word 0 ; 30: unused |
.word 0 ; 31: unused |
|
.bss |
|
.align 4 |
.space 0x800 |
stack: |
|
.align 4 |
.space 0x800 |
istack: |
/stdalone/hello/hello.s
0,0 → 1,54
; |
; hello.s -- Hello, world! |
; |
|
.set tba,0xF0300000 ; terminal base address |
.set tos,0xC0010000 ; top of stack |
|
; get some addresses listed in the load map |
.export reset |
.export start |
.export out |
.export hello |
|
; minimal execution environment |
reset: |
add $29,$0,tos ; setup stack |
jal start ; do useful work |
reset1: |
j reset1 ; halt by looping |
|
; main program |
start: |
sub $29,$29,8 ; create stack frame |
stw $31,$29,0 ; save return register |
stw $16,$29,4 ; save register variable |
add $16,$0,hello ; pointer to string |
loop: |
ldbu $4,$16,0 ; get char |
beq $4,$0,stop ; null - finished |
jal out ; output char |
add $16,$16,1 ; bump pointer |
j loop ; next char |
stop: |
ldw $31,$29,0 ; restore return register |
ldw $16,$29,4 ; restore register variable |
add $29,$29,8 ; release stack frame |
jr $31 ; return |
|
; output a character to the terminal |
out: |
add $8,$0,tba ; set I/O base address |
out1: |
ldw $9,$8,8 ; get xmtr status |
and $9,$9,1 ; xmtr ready? |
beq $9,$0,out1 ; no - wait |
stw $4,$8,12 ; send char |
jr $31 ; return |
|
; a very famous little string... |
hello: |
.byte 0x0D, 0x0A |
.byte "Hello, world!" |
.byte 0x0D, 0x0A |
.byte 0x0D, 0x0A, 0 |
/stdalone/hello/Makefile
0,0 → 1,32
# |
# Makefile for "hello", a program for testing the boot loader |
# |
|
BUILD = ../../build |
|
SRC = hello.s |
OBJ = hello.o |
BIN = hello.bin |
MAP = hello.map |
|
.PHONY: all install run clean |
|
all: $(BIN) |
|
install: $(BIN) |
mkdir -p $(BUILD)/stdalone |
cp $(BIN) $(BUILD)/stdalone |
cp $(MAP) $(BUILD)/stdalone |
|
run: $(BIN) |
$(BUILD)/bin/sim -i -t 1 -l $(BIN) |
|
$(BIN): $(OBJ) |
$(BUILD)/bin/ld -h -rc 0xC0000000 \ |
-m $(MAP) -o $(BIN) $(OBJ) |
|
$(OBJ): $(SRC) |
$(BUILD)/bin/as -o $(OBJ) $(SRC) |
|
clean: |
rm -f *~ $(OBJ) $(BIN) $(MAP) |
/stdalone/onetask/os/start.h
0,0 → 1,21
/* |
* start.h -- startup code |
*/ |
|
|
#ifndef _START_H_ |
#define _START_H_ |
|
|
typedef void (*ISR)(int irq, unsigned int *registers); |
|
|
void enable(void); |
void disable(void); |
ISR getISR(int irq); |
void setISR(int irq, ISR isr); |
void startTask(unsigned int physStackTop); |
void setTLB(int index, unsigned int entryHi, unsigned int entryLo); |
|
|
#endif /* _START_H_ */ |
/stdalone/onetask/os/main.c
0,0 → 1,250
/* |
* main.c -- start the ball rolling |
*/ |
|
|
#include "stdarg.h" |
#include "start.h" |
|
|
/**************************************************************/ |
|
|
unsigned char taskCode[] = { |
#include "task.dump" |
}; |
|
|
/**************************************************************/ |
|
|
void putchar(char c) { |
unsigned int *base; |
|
if (c == '\n') { |
putchar('\r'); |
} |
base = (unsigned int *) 0xF0300000; |
while ((*(base + 2) & 1) == 0) ; |
*(base + 3) = c; |
} |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void printn(int n) { |
int a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printu(unsigned int n, unsigned int b) { |
unsigned int a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b); |
} |
putchar("0123456789ABCDEF"[n % b]); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == 'd') { |
n = va_arg(ap, int); |
printn(n); |
} else |
if (c == 'u' || c == 'o' || c == 'x') { |
u = va_arg(ap, int); |
printu(u, c == 'o' ? 8 : (c == 'x' ? 16 : 10)); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/**************************************************************/ |
|
|
static char *exceptionCause[32] = { |
/* 00 */ "terminal 0 transmitter interrupt", |
/* 01 */ "terminal 0 receiver interrupt", |
/* 02 */ "terminal 1 transmitter interrupt", |
/* 03 */ "terminal 1 receiver interrupt", |
/* 04 */ "keyboard interrupt", |
/* 05 */ "unknown interrupt", |
/* 06 */ "unknown interrupt", |
/* 07 */ "unknown interrupt", |
/* 08 */ "disk interrupt", |
/* 09 */ "unknown interrupt", |
/* 10 */ "unknown interrupt", |
/* 11 */ "unknown interrupt", |
/* 12 */ "unknown interrupt", |
/* 13 */ "unknown interrupt", |
/* 14 */ "timer interrupt", |
/* 15 */ "unknown interrupt", |
/* 16 */ "bus timeout exception", |
/* 17 */ "illegal instruction exception", |
/* 18 */ "privileged instruction exception", |
/* 19 */ "divide instruction exception", |
/* 20 */ "trap instruction exception", |
/* 21 */ "TLB miss exception", |
/* 22 */ "TLB write exception", |
/* 23 */ "TLB invalid exception", |
/* 24 */ "illegal address exception", |
/* 25 */ "privileged address exception", |
/* 26 */ "unknown exception", |
/* 27 */ "unknown exception", |
/* 28 */ "unknown exception", |
/* 29 */ "unknown exception", |
/* 30 */ "unknown exception", |
/* 31 */ "unknown exception" |
}; |
|
|
void defaultISR(int irq, unsigned int *registers) { |
printf("\n%s\n", exceptionCause[irq]); |
} |
|
|
void initInterrupts(void) { |
int i; |
|
for (i = 0; i < 32; i++) { |
setISR(i, defaultISR); |
} |
} |
|
|
/**************************************************************/ |
|
|
void loadTask(unsigned char *code, |
int csize, unsigned int physCodeAddr, |
int dsize, unsigned int physDataAddr, |
int bsize) { |
unsigned char *virtLoadAddr; |
int i; |
|
virtLoadAddr = (unsigned char *) (0xC0000000 | physCodeAddr); |
for (i = 0; i < csize; i++) { |
*virtLoadAddr++ = *code++; |
} |
virtLoadAddr = (unsigned char *) (0xC0000000 | physDataAddr); |
for (i = 0; i < dsize; i++) { |
*virtLoadAddr++ = *code++; |
} |
for (i = 0; i < bsize; i++) { |
*virtLoadAddr++ = '\0'; |
} |
} |
|
|
/**************************************************************/ |
|
|
void trapISR(int irq, unsigned int *registers) { |
/* 'putchar' is the only system call yet */ |
putchar(registers[4]); |
/* skip the trap instruction */ |
registers[30] += 4; |
} |
|
|
/**************************************************************/ |
|
|
void flushTLB(void) { |
unsigned int invalPage; |
int i; |
|
invalPage = 0xC0000000; |
for (i = 0; i < 32; i++) { |
setTLB(i, invalPage, 0); |
invalPage += (1 << 12); |
} |
} |
|
|
/**************************************************************/ |
|
|
unsigned int getNumber(unsigned char *p) { |
return (unsigned int) *(p + 0) << 24 | |
(unsigned int) *(p + 1) << 16 | |
(unsigned int) *(p + 2) << 8 | |
(unsigned int) *(p + 3) << 0; |
} |
|
|
void main(void) { |
unsigned int magic; |
unsigned int csize; |
unsigned int dsize; |
unsigned int bsize; |
|
printf("\n"); |
printf("OS: initializing interrupts\n"); |
initInterrupts(); |
setISR(20, trapISR); |
/* load code at 256 k, data at (256 + 16) k */ |
printf("OS: loading task\n"); |
magic = getNumber(taskCode + 0); |
csize = getNumber(taskCode + 4); |
dsize = getNumber(taskCode + 8); |
bsize = getNumber(taskCode + 12); |
if (magic != 0x1AA09232) { |
printf("Error: Load module is not executable!\n"); |
while (1) ; |
} |
printf("(csize = 0x%x, dsize = 0x%x, bsize = 0x%x)\n", |
csize, dsize, bsize); |
loadTask(taskCode + 8 * sizeof(unsigned int), |
csize, 64 << 12, |
dsize, 68 << 12, |
bsize); |
printf("OS: presetting TLB\n"); |
flushTLB(); |
setTLB(5, 0x00000000, 64 << 12 | 0x01); |
setTLB(27, (csize + 0x00000FFF) & 0xFFFFF000, 68 << 12 | 0x03); |
setTLB(22, 0x7FFFF000, 80 << 12 | 0x03); |
printf("OS: starting task\n"); |
startTask(80 << 12); /* stack at (256 + 64) k */ |
} |
/stdalone/onetask/os/end.s
0,0 → 1,19
; |
; end.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/onetask/os/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/onetask/os/Makefile
0,0 → 1,20
BUILD = ../../../build |
|
SRC = start.s main.c end.s |
BIN = onetask.bin |
MAP = onetask.map |
|
all: $(BIN) |
|
run: $(BIN) |
$(BUILD)/bin/sim -i -t 1 -l $(BIN) |
|
$(BIN): $(SRC) task.dump |
$(BUILD)/bin/lcc -A -Wo-kernel \ |
-Wl-m -Wl$(MAP) -o $(BIN) $(SRC) |
|
task.dump: |
../dump/dump ../task/task task.dump |
|
clean: |
rm -f *~ task.dump $(BIN) $(MAP) |
/stdalone/onetask/os/start.s
0,0 → 1,267
; |
; start.s -- startup code |
; |
|
.import main |
.import _ecode |
.import _edata |
.import _ebss |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export enable |
.export disable |
.export getISR |
.export setISR |
.export startTask |
.export setTLB |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
|
; reset arrives here |
reset: |
j start |
|
; interrupts arrive here |
intrpt: |
j isr |
|
; user TLB misses arrive here |
userMiss: |
j userMiss |
|
isr: |
add $26,$29,$0 ; sp -> $26 |
add $27,$1,$0 ; $1 -> $27 |
add $29,$0,istack ; setup interrupt stack |
sub $29,$29,128 ; save registers |
stw $2,$29,8 |
stw $3,$29,12 |
stw $4,$29,16 |
stw $5,$29,20 |
stw $6,$29,24 |
stw $7,$29,28 |
stw $8,$29,32 |
stw $9,$29,36 |
stw $10,$29,40 |
stw $11,$29,44 |
stw $12,$29,48 |
stw $13,$29,52 |
stw $14,$29,56 |
stw $15,$29,60 |
stw $16,$29,64 |
stw $17,$29,68 |
stw $18,$29,72 |
stw $19,$29,76 |
stw $20,$29,80 |
stw $21,$29,84 |
stw $22,$29,88 |
stw $23,$29,92 |
stw $24,$29,96 |
stw $25,$29,100 |
stw $26,$29,116 ; this is the task's sp |
stw $27,$29,4 ; this is the task's $1 |
stw $30,$29,120 ; this is the task's resumption address |
stw $31,$29,124 |
add $5,$29,$0 ; $5 = pointer to register array |
mvfs $4,0 ; $4 = IRQ number |
slr $4,$4,16 |
and $4,$4,0x1F |
sll $26,$4,2 ; $26 = 4 * IRQ number |
ldw $26,$26,irqsrv ; get addr of service routine |
jalr $26 ; call service routine |
j resume ; resume interrupted task if ISR returns |
|
; resume a task |
resume: |
ldw $2,$29,8 ; restore registers |
ldw $3,$29,12 |
ldw $4,$29,16 |
ldw $5,$29,20 |
ldw $6,$29,24 |
ldw $7,$29,28 |
ldw $8,$29,32 |
ldw $9,$29,36 |
ldw $10,$29,40 |
ldw $11,$29,44 |
ldw $12,$29,48 |
ldw $13,$29,52 |
ldw $14,$29,56 |
ldw $15,$29,60 |
ldw $16,$29,64 |
ldw $17,$29,68 |
ldw $18,$29,72 |
ldw $19,$29,76 |
ldw $20,$29,80 |
ldw $21,$29,84 |
ldw $22,$29,88 |
ldw $23,$29,92 |
ldw $24,$29,96 |
ldw $25,$29,100 |
ldw $26,$29,116 ; this is the task's sp |
ldw $27,$29,4 ; this is the task's $1 |
ldw $30,$29,120 ; this is the task's resumption address |
ldw $31,$29,124 |
add $1,$27,$0 ; $27 -> $1 |
add $29,$26,$0 ; $26 -> sp |
rfx ; return from exception |
|
start: |
mvfs $8,0 |
or $8,$8,1 << 27 ; let vector point to RAM |
mvts $8,0 |
add $29,$0,stack ; set sp |
add $10,$0,_bdata ; copy data segment |
add $8,$0,_edata |
sub $9,$8,$10 |
add $9,$9,_ecode |
j cpytest |
cpyloop: |
ldw $11,$9,0 |
stw $11,$8,0 |
cpytest: |
sub $8,$8,4 |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
add $8,$0,_bbss ; clear bss |
add $9,$0,_ebss |
j clrtest |
clrloop: |
stw $0,$8,0 |
add $8,$8,4 |
clrtest: |
bltu $8,$9,clrloop |
jal main ; call 'main' |
start1: |
j start1 ; loop |
|
enable: |
mvfs $8,0 |
or $8,$8,1 << 23 |
mvts $8,0 |
jr $31 |
|
disable: |
mvfs $8,0 |
and $8,$8,~(1 << 23) |
mvts $8,0 |
jr $31 |
|
getISR: |
sll $4,$4,2 |
ldw $2,$4,irqsrv |
jr $31 |
|
setISR: |
sll $4,$4,2 |
stw $5,$4,irqsrv |
jr $31 |
|
startTask: |
or $29,$4,0xC0000000 |
sub $29,$29,128 |
stw $0,$29,0 ; preset registers |
stw $0,$29,4 |
stw $0,$29,8 |
stw $0,$29,12 |
stw $0,$29,16 |
stw $0,$29,20 |
stw $0,$29,24 |
stw $0,$29,28 |
stw $0,$29,32 |
stw $0,$29,36 |
stw $0,$29,40 |
stw $0,$29,44 |
stw $0,$29,48 |
stw $0,$29,52 |
stw $0,$29,56 |
stw $0,$29,60 |
stw $0,$29,64 |
stw $0,$29,68 |
stw $0,$29,72 |
stw $0,$29,76 |
stw $0,$29,80 |
stw $0,$29,84 |
stw $0,$29,88 |
stw $0,$29,92 |
stw $0,$29,96 |
stw $0,$29,100 |
stw $0,$29,104 |
stw $0,$29,108 |
stw $0,$29,112 |
add $8,$0,0x80000000 |
stw $8,$29,116 ; sp |
stw $0,$29,120 ; task starts at virtual address 0 |
stw $0,$29,124 |
mvfs $8,0 |
or $8,$8,1 << 25 ; set previous mode to 'user' |
mvts $8,0 |
j resume |
|
setTLB: |
mvts $4,1 ; set index |
mvts $5,2 ; set entryHi |
mvts $6,3 ; set entryLo |
tbwi ; write TLB entry at index |
jr $31 |
|
.data |
|
; interrupt service routine table |
|
.align 4 |
|
irqsrv: |
.word 0 ; 00: terminal 0 transmitter interrupt |
.word 0 ; 01: terminal 0 receiver interrupt |
.word 0 ; 02: terminal 1 transmitter interrupt |
.word 0 ; 03: terminal 1 receiver interrupt |
.word 0 ; 04: keyboard interrupt |
.word 0 ; 05: unused |
.word 0 ; 06: unused |
.word 0 ; 07: unused |
.word 0 ; 08: disk interrupt |
.word 0 ; 09: unused |
.word 0 ; 10: unused |
.word 0 ; 11: unused |
.word 0 ; 12: unused |
.word 0 ; 13: unused |
.word 0 ; 14: timer interrupt |
.word 0 ; 15: unused |
.word 0 ; 16: bus timeout exception |
.word 0 ; 17: illegal instruction exception |
.word 0 ; 18: privileged instruction exception |
.word 0 ; 19: divide instruction exception |
.word 0 ; 20: trap instruction exception |
.word 0 ; 21: TLB miss exception |
.word 0 ; 22: TLB write exception |
.word 0 ; 23: TLB invalid exception |
.word 0 ; 24: illegal address exception |
.word 0 ; 25: privileged address exception |
.word 0 ; 26: unused |
.word 0 ; 27: unused |
.word 0 ; 28: unused |
.word 0 ; 29: unused |
.word 0 ; 30: unused |
.word 0 ; 31: unused |
|
.bss |
|
.align 4 |
.space 0x800 |
stack: |
|
.align 4 |
.space 0x800 |
istack: |
/stdalone/onetask/task/task.c
0,0 → 1,95
/* |
* task.c -- a simple task |
*/ |
|
|
#include "putchar.h" |
#include "stdarg.h" |
|
|
/**************************************************************/ |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void printn(int n) { |
int a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printu(unsigned int n, unsigned int b) { |
unsigned int a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b); |
} |
putchar("0123456789ABCDEF"[n % b]); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == 'd') { |
n = va_arg(ap, int); |
printn(n); |
} else |
if (c == 'u' || c == 'o' || c == 'x') { |
u = va_arg(ap, int); |
printu(u, c == 'o' ? 8 : (c == 'x' ? 16 : 10)); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/**************************************************************/ |
|
|
void main(void) { |
int i; |
|
printf("TASK: executing...\n"); |
i = 0; |
while (1) { |
printf("TASK: %d\n", i); |
i++; |
} |
} |
/stdalone/onetask/task/c0.s
0,0 → 1,30
; |
; c0.s -- startup code and begin-of-segment labels |
; |
|
.import main |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.import _ecode |
.import _edata |
.import _ebss |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
.align 4 |
|
start: |
jal main ; call 'main' function |
stop: |
j stop ; just to be sure... |
/stdalone/onetask/task/c1.s
0,0 → 1,19
; |
; c1.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/onetask/task/putchar.s
0,0 → 1,10
; |
; putchar.s -- putchar library function |
; |
|
.code |
.export putchar |
|
putchar: |
trap |
jr $31 |
/stdalone/onetask/task/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/onetask/task/putchar.h
0,0 → 1,13
/* |
* putchar.h -- putchar library function |
*/ |
|
|
#ifndef _PUTCHAR_H_ |
#define _PUTCHAR_H_ |
|
|
void putchar(char c); |
|
|
#endif /* _PUTCHAR_H_ */ |
/stdalone/onetask/task/Makefile
0,0 → 1,21
BUILD = ../../../build |
|
all: task |
|
task: c0.o task.o putchar.o c1.o |
$(BUILD)/bin/ld -o task c0.o task.o putchar.o c1.o |
|
c0.o: c0.s |
$(BUILD)/bin/as -o c0.o c0.s |
|
task.o: task.c |
$(BUILD)/bin/lcc -A -c -o task.o task.c |
|
putchar.o: putchar.s |
$(BUILD)/bin/as -o putchar.o putchar.s |
|
c1.o: c1.s |
$(BUILD)/bin/as -o c1.o c1.s |
|
clean: |
rm -f *~ c0.o task.o putchar.o c1.o task |
/stdalone/onetask/dump/dump.c
0,0 → 1,48
/* |
* dump.c -- dump a binary file as contents of a C array |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
|
|
int main(int argc, char *argv[]) { |
FILE *infile, *outfile; |
int c, n; |
|
if (argc != 3) { |
printf("Usage: %s <infile> <outfile>\n", argv[0]); |
return 1; |
} |
infile = fopen(argv[1], "rb"); |
if (infile == NULL) { |
printf("Error: cannot open file '%s' for input\n", argv[1]); |
return 1; |
} |
outfile = fopen(argv[2], "wt"); |
if (outfile == NULL) { |
printf("Error: cannot open file '%s' for output\n", argv[2]); |
return 1; |
} |
n = 0; |
while (1) { |
c = getc(infile); |
if (c == EOF) { |
break; |
} |
fprintf(outfile, "0x%02X, ", c); |
n++; |
if (n == 8) { |
n = 0; |
fprintf(outfile, "\n"); |
} |
} |
if (n != 0) { |
fprintf(outfile, "\n"); |
} |
fclose(infile); |
fclose(outfile); |
return 0; |
} |
/stdalone/onetask/dump/Makefile
0,0 → 1,15
# |
# Makefile for dump utility |
# |
|
.PHONY: all install clean |
|
all: dump |
|
install: dump |
|
dump: dump.c |
gcc -m32 -g -Wall -o dump dump.c |
|
clean: |
rm -f *~ dump |
/stdalone/onetask/Makefile
0,0 → 1,32
# |
# Makefile for "onetask", a tiny OS which runs a single task |
# |
|
BUILD = ../../build |
|
.PHONY: all install run clean |
|
all: dump/dump task/task os/onetask.bin |
|
install: dump/dump task/task os/onetask.bin |
mkdir -p $(BUILD)/stdalone |
cp os/onetask.bin $(BUILD)/stdalone |
cp os/onetask.map $(BUILD)/stdalone |
|
run: dump/dump task/task os/onetask.bin |
$(MAKE) -C os run |
|
dump/dump: |
$(MAKE) -C dump |
|
task/task: |
$(MAKE) -C task |
|
os/onetask.bin: |
$(MAKE) -C os |
|
clean: |
$(MAKE) -C dump clean |
$(MAKE) -C task clean |
$(MAKE) -C os clean |
rm -f *~ |
/stdalone/hello2/main.c
0,0 → 1,29
/* |
* main.c -- main program |
*/ |
|
|
void putchar(char c) { |
unsigned int *base; |
|
if (c == '\n') { |
putchar('\r'); |
} |
base = (unsigned int *) 0xF0300000; |
while ((*(base + 2) & 1) == 0) ; |
*(base + 3) = c; |
} |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void main(void) { |
puts("\nHello, world!\n\n"); |
} |
/stdalone/hello2/end.s
0,0 → 1,19
; |
; end.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/hello2/Makefile
0,0 → 1,28
# |
# Makefile for "hello", a program for testing the boot loader |
# |
|
BUILD = ../../build |
|
SRC = start.s main.c end.s |
BIN = hello2.bin |
MAP = hello2.map |
|
.PHONY: all install run clean |
|
all: $(BIN) |
|
install: $(BIN) |
mkdir -p $(BUILD)/stdalone |
cp $(BIN) $(BUILD)/stdalone |
cp $(MAP) $(BUILD)/stdalone |
|
run: $(BIN) |
$(BUILD)/bin/sim -i -t 1 -l $(BIN) |
|
$(BIN): $(SRC) |
$(BUILD)/bin/lcc -A -Wo-kernel \ |
-Wl-m -Wl$(MAP) -o $(BIN) $(SRC) |
|
clean: |
rm -f *~ $(BIN) $(MAP) |
/stdalone/hello2/start.s
0,0 → 1,70
; |
; start.s -- startup code |
; |
|
.import main |
.import _ecode |
.import _edata |
.import _ebss |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
|
; reset arrives here |
reset: |
j start |
|
; interrupts arrive here |
intrpt: |
j intrpt |
|
; user TLB misses arrive here |
userMiss: |
j userMiss |
|
start: |
mvfs $8,0 |
or $8,$8,1 << 27 ; let vector point to RAM |
mvts $8,0 |
add $29,$0,stack ; set sp |
add $10,$0,_bdata ; copy data segment |
add $8,$0,_edata |
sub $9,$8,$10 |
add $9,$9,_ecode |
j cpytest |
cpyloop: |
ldw $11,$9,0 |
stw $11,$8,0 |
cpytest: |
sub $8,$8,4 |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
add $8,$0,_bbss ; clear bss |
add $9,$0,_ebss |
j clrtest |
clrloop: |
stw $0,$8,0 |
add $8,$8,4 |
clrtest: |
bltu $8,$9,clrloop |
jal main ; call 'main' |
start1: |
j start1 ; loop |
|
.bss |
|
.align 4 |
.space 0x800 |
stack: |
/stdalone/dskchk/start.h
0,0 → 1,21
/* |
* start.h -- startup code |
*/ |
|
|
#ifndef _START_H_ |
#define _START_H_ |
|
|
typedef int (*ISR)(int irq); |
|
|
void enable(void); |
void disable(void); |
int getMask(void); |
void setMask(int mask); |
ISR getISR(int irq); |
void setISR(int irq, ISR isr); |
|
|
#endif /* _START_H_ */ |
/stdalone/dskchk/main.c
0,0 → 1,445
/* |
* main.c -- start the ball rolling |
*/ |
|
|
#include "stdarg.h" |
#include "start.h" |
#include "idedsk.h" |
|
|
#define NUM_SECTORS 500 |
#define SECTOR_RANGE 8000 |
|
#define NUM_BLOCKS 300 |
#define BLOCK_RANGE 1000 |
|
|
/**************************************************************/ |
|
|
#define RAND_MAX 0x7FFF |
|
|
static unsigned long randomNumber = 1; |
|
|
void srand(int seed) { |
randomNumber = seed; |
} |
|
|
int rand(void) { |
randomNumber = randomNumber * 1103515245 + 12345; |
return (unsigned int)(randomNumber >> 16) & RAND_MAX; |
} |
|
|
/**************************************************************/ |
|
|
void putchar(char c) { |
unsigned int *base; |
|
if (c == '\n') { |
putchar('\r'); |
} |
base = (unsigned int *) 0xF0300000; |
while ((*(base + 2) & 1) == 0) ; |
*(base + 3) = c; |
} |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void printn(int n) { |
int a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printu(unsigned int n, unsigned int b) { |
unsigned int a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b); |
} |
putchar("0123456789ABCDEF"[n % b]); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == 'd') { |
n = va_arg(ap, int); |
printn(n); |
} else |
if (c == 'u' || c == 'o' || c == 'x') { |
u = va_arg(ap, int); |
printu(u, c == 'o' ? 8 : (c == 'x' ? 16 : 10)); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/**************************************************************/ |
|
|
static char *exceptionCause[32] = { |
/* 00 */ "terminal 0 transmitter interrupt", |
/* 01 */ "terminal 0 receiver interrupt", |
/* 02 */ "terminal 1 transmitter interrupt", |
/* 03 */ "terminal 1 receiver interrupt", |
/* 04 */ "keyboard interrupt", |
/* 05 */ "unknown interrupt", |
/* 06 */ "unknown interrupt", |
/* 07 */ "unknown interrupt", |
/* 08 */ "disk interrupt", |
/* 09 */ "unknown interrupt", |
/* 10 */ "unknown interrupt", |
/* 11 */ "unknown interrupt", |
/* 12 */ "unknown interrupt", |
/* 13 */ "unknown interrupt", |
/* 14 */ "timer interrupt", |
/* 15 */ "unknown interrupt", |
/* 16 */ "bus timeout exception", |
/* 17 */ "illegal instruction exception", |
/* 18 */ "privileged instruction exception", |
/* 19 */ "divide instruction exception", |
/* 20 */ "trap instruction exception", |
/* 21 */ "TLB miss exception", |
/* 22 */ "TLB write exception", |
/* 23 */ "TLB invalid exception", |
/* 24 */ "illegal address exception", |
/* 25 */ "privileged address exception", |
/* 26 */ "unknown exception", |
/* 27 */ "unknown exception", |
/* 28 */ "unknown exception", |
/* 29 */ "unknown exception", |
/* 30 */ "unknown exception", |
/* 31 */ "unknown exception" |
}; |
|
|
int defaultISR(int irq) { |
printf("\n%s\n", exceptionCause[irq]); |
return 0; /* do not skip any instruction */ |
} |
|
|
void initInterrupts(void) { |
int i; |
|
for (i = 0; i < 32; i++) { |
setISR(i, defaultISR); |
} |
} |
|
|
/**************************************************************/ |
|
|
#define TIMER_CTRL ((unsigned *) 0xF0000000) |
#define TIMER_DIV ((unsigned *) 0xF0000004) |
|
|
int hundredth = 0; |
|
|
int clockISR(int irq) { |
*TIMER_CTRL = 2; |
hundredth++; |
return 0; |
} |
|
|
void initClock(void) { |
setISR(14, clockISR); |
*TIMER_DIV = 10; |
*TIMER_CTRL = 2; |
setMask(1 << 14); |
enable(); |
} |
|
|
/**************************************************************/ |
|
|
void checkDisk1(void) { |
unsigned res; |
|
printf("\nIs the disk present?\n"); |
res = *DISK_CTRL; |
printf("yes, CTRL = 0x%x\n", res); |
} |
|
|
void checkDisk2(void) { |
int start; |
int ready; |
|
printf("\nDoes the disk get ready?\n"); |
start = hundredth; |
ready = 0; |
while (start + 10 * 100 > hundredth) { |
if (*DISK_CTRL & DISK_CTRL_READY) { |
ready = hundredth; |
break; |
} |
} |
if (ready == 0) { |
printf("disk did not get ready\n"); |
} else { |
printf("disk got ready after %d/100 seconds\n", ready - start); |
} |
} |
|
|
void checkDisk3(void) { |
int errors; |
int seed; |
unsigned int *p; |
int i, j; |
|
printf("\nDisk sector buffer read/write\n"); |
errors = 0; |
srand(321); |
for (i = 0; i < NUM_SECTORS; i++) { |
seed = rand(); |
srand(seed); |
p = DISK_BUFFER; |
for (j = 0; j < WPS; j++) { |
*p++ = rand(); |
} |
srand(seed); |
p = DISK_BUFFER; |
for (j = 0; j < WPS; j++) { |
if (*p++ != rand()) { |
errors++; |
break; |
} |
} |
} |
printf("%d errors in %d sectors\n", errors, NUM_SECTORS); |
} |
|
|
void checkDisk4(void) { |
int sector; |
unsigned int *p; |
int i, j; |
int start, done; |
int errors; |
|
printf("\nRandom sector read/write, polled\n"); |
printf("writing...\n"); |
srand(321); |
for (i = 0; i < NUM_SECTORS; i++) { |
sector = rand() % SECTOR_RANGE; |
p = DISK_BUFFER; |
for (j = 0; j < WPS; j++) { |
*p++ = sector + j; |
} |
*DISK_SCT = sector; |
*DISK_CNT = 1; |
*DISK_CTRL = *DISK_CTRL |
& ~(DISK_CTRL_DONE | DISK_CTRL_ERR) |
| (DISK_CTRL_WRT | DISK_CTRL_STRT); |
start = hundredth; |
done = 0; |
while (start + 2 * 100 > hundredth) { |
if (*DISK_CTRL & DISK_CTRL_DONE) { |
done = hundredth; |
break; |
} |
} |
if (done == 0) { |
printf("disk did not complete a sector write command\n"); |
return; |
} |
} |
printf("reading...\n"); |
errors = 0; |
srand(321); |
for (i = 0; i < NUM_SECTORS; i++) { |
sector = rand() % SECTOR_RANGE; |
*DISK_SCT = sector; |
*DISK_CNT = 1; |
*DISK_CTRL = *DISK_CTRL |
& ~(DISK_CTRL_DONE | DISK_CTRL_ERR | DISK_CTRL_WRT) |
| DISK_CTRL_STRT; |
start = hundredth; |
done = 0; |
while (start + 2 * 100 > hundredth) { |
if (*DISK_CTRL & DISK_CTRL_DONE) { |
done = hundredth; |
break; |
} |
} |
if (done == 0) { |
printf("disk did not complete a sector read command\n"); |
return; |
} |
p = DISK_BUFFER; |
for (j = 0; j < WPS; j++) { |
if (*p++ != sector + j) { |
errors++; |
break; |
} |
} |
} |
printf("%d errors in %d sectors (range 0..%d)\n", |
errors, NUM_SECTORS, SECTOR_RANGE); |
} |
|
|
void checkDisk5(void) { |
int errors; |
int seed; |
unsigned int *p; |
int i, j; |
|
printf("\nDisk block buffer read/write\n"); |
errors = 0; |
srand(321); |
for (i = 0; i < NUM_BLOCKS; i++) { |
seed = rand(); |
srand(seed); |
p = DISK_BUFFER; |
for (j = 0; j < WPB; j++) { |
*p++ = rand(); |
} |
srand(seed); |
p = DISK_BUFFER; |
for (j = 0; j < WPB; j++) { |
if (*p++ != rand()) { |
errors++; |
break; |
} |
} |
} |
printf("%d errors in %d blocks\n", errors, NUM_BLOCKS); |
} |
|
|
void checkDisk6(void) { |
int block; |
unsigned int *p; |
int i, j; |
int start, done; |
int errors; |
|
printf("\nRandom block read/write, polled\n"); |
printf("writing...\n"); |
srand(321); |
for (i = 0; i < NUM_BLOCKS; i++) { |
block = rand() % BLOCK_RANGE; |
p = DISK_BUFFER; |
for (j = 0; j < WPB; j++) { |
*p++ = block + j; |
} |
*DISK_SCT = 8 * block; |
*DISK_CNT = 8; |
*DISK_CTRL = *DISK_CTRL |
& ~(DISK_CTRL_DONE | DISK_CTRL_ERR) |
| (DISK_CTRL_WRT | DISK_CTRL_STRT); |
start = hundredth; |
done = 0; |
while (start + 2 * 100 > hundredth) { |
if (*DISK_CTRL & DISK_CTRL_DONE) { |
done = hundredth; |
break; |
} |
} |
if (done == 0) { |
printf("disk did not complete a block write command\n"); |
return; |
} |
} |
printf("reading...\n"); |
errors = 0; |
srand(321); |
for (i = 0; i < NUM_BLOCKS; i++) { |
block = rand() % BLOCK_RANGE; |
*DISK_SCT = 8 * block; |
*DISK_CNT = 8; |
*DISK_CTRL = *DISK_CTRL |
& ~(DISK_CTRL_DONE | DISK_CTRL_ERR | DISK_CTRL_WRT) |
| DISK_CTRL_STRT; |
start = hundredth; |
done = 0; |
while (start + 2 * 100 > hundredth) { |
if (*DISK_CTRL & DISK_CTRL_DONE) { |
done = hundredth; |
break; |
} |
} |
if (done == 0) { |
printf("disk did not complete a block read command\n"); |
return; |
} |
p = DISK_BUFFER; |
for (j = 0; j < WPB; j++) { |
if (*p++ != block + j) { |
errors++; |
break; |
} |
} |
} |
printf("%d errors in %d blocks (range 0..%d)\n", |
errors, NUM_BLOCKS, BLOCK_RANGE); |
} |
|
|
/**************************************************************/ |
|
|
void main(void) { |
initInterrupts(); |
initClock(); |
checkDisk1(); |
checkDisk2(); |
checkDisk3(); |
checkDisk4(); |
checkDisk5(); |
checkDisk6(); |
printf("\nHalting...\n"); |
} |
/stdalone/dskchk/end.s
0,0 → 1,19
; |
; end.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/dskchk/idedsk.h
0,0 → 1,34
/* |
* idedsk.h -- IDE disk definitions |
*/ |
|
|
#ifndef _IDEDSK_H_ |
#define _IDEDSK_H_ |
|
|
#define SECTOR_SIZE 512 |
#define WPS (SECTOR_SIZE / sizeof(unsigned int)) |
#define BLOCK_SIZE 4096 |
#define WPB (BLOCK_SIZE / sizeof(unsigned int)) |
|
#define DISK_BASE ((unsigned *) 0xF0400000) /* disk base address */ |
#define DISK_CTRL (DISK_BASE + 0) /* control/status register */ |
#define DISK_CNT (DISK_BASE + 1) /* sector count register */ |
#define DISK_SCT (DISK_BASE + 2) /* disk sector register */ |
#define DISK_CAP (DISK_BASE + 3) /* disk capacity register */ |
#define DISK_BUFFER ((unsigned *) 0xF0480000) /* address of disk buffer */ |
|
#define DISK_CTRL_STRT 0x01 /* a 1 written here starts the disk command */ |
#define DISK_CTRL_IEN 0x02 /* enable disk interrupt */ |
#define DISK_CTRL_WRT 0x04 /* command type: 0 = read, 1 = write */ |
#define DISK_CTRL_ERR 0x08 /* 0 = ok, 1 = error; valid when DONE = 1 */ |
#define DISK_CTRL_DONE 0x10 /* 1 = disk has finished the command */ |
#define DISK_CTRL_READY 0x20 /* 1 = capacity valid, disk accepts command */ |
|
#define DISK_IRQ 8 /* disk interrupt number */ |
|
#define READY_RETRIES 1000000 /* retries to wait for disk to get ready */ |
|
|
#endif /* _IDEDSK_H_ */ |
/stdalone/dskchk/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/dskchk/Makefile
0,0 → 1,28
# |
# Makefile for "dskchk", a program to check the hard disk interface |
# |
|
BUILD = ../../build |
|
SRC = start.s main.c end.s |
BIN = dskchk.bin |
MAP = dskchk.map |
|
.PHONY: all install run clean |
|
all: $(BIN) |
|
install: $(BIN) |
mkdir -p $(BUILD)/stdalone |
cp $(BIN) $(BUILD)/stdalone |
cp $(MAP) $(BUILD)/stdalone |
|
run: $(BIN) |
$(BUILD)/bin/sim -i -t 1 -l $(BIN) -d $(BUILD)/disk/disk.img |
|
$(BIN): $(SRC) |
$(BUILD)/bin/lcc -A -Wo-kernel \ |
-Wl-m -Wl$(MAP) -o $(BIN) $(SRC) |
|
clean: |
rm -f *~ $(BIN) $(MAP) |
/stdalone/dskchk/start.s
0,0 → 1,228
; |
; start.s -- startup code |
; |
|
.import main |
.import _ecode |
.import _edata |
.import _ebss |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export enable |
.export disable |
.export getMask |
.export setMask |
.export getISR |
.export setISR |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
|
; reset arrives here |
reset: |
j start |
|
; interrupts arrive here |
intrpt: |
j isr |
|
; user TLB misses arrive here |
userMiss: |
j userMiss |
|
isr: |
add $26,$29,$0 ; sp -> $26 |
add $27,$1,$0 ; $1 -> $27 |
add $29,$0,istack ; set stack |
sub $29,$29,108 |
stw $2,$29,0 ; save registers |
stw $3,$29,4 |
stw $4,$29,8 |
stw $5,$29,12 |
stw $6,$29,16 |
stw $7,$29,20 |
stw $8,$29,24 |
stw $9,$29,28 |
stw $10,$29,32 |
stw $11,$29,36 |
stw $12,$29,40 |
stw $13,$29,44 |
stw $14,$29,48 |
stw $15,$29,52 |
stw $16,$29,56 |
stw $17,$29,60 |
stw $18,$29,64 |
stw $19,$29,68 |
stw $20,$29,72 |
stw $21,$29,76 |
stw $22,$29,80 |
stw $23,$29,84 |
stw $24,$29,88 |
stw $25,$29,92 |
stw $26,$29,96 |
stw $27,$29,100 |
stw $31,$29,104 |
mvfs $4,0 ; $4 = IRQ number |
slr $4,$4,16 |
and $4,$4,0x1F |
sll $26,$4,2 ; $26 = 4 * IRQ number |
ldw $26,$26,irqsrv ; get addr of service routine |
jalr $26 ; call service routine |
beq $2,$0,resume ; resume instruction if ISR returned 0 |
add $30,$30,4 ; else skip offending instruction |
resume: |
ldw $2,$29,0 |
ldw $3,$29,4 |
ldw $4,$29,8 |
ldw $5,$29,12 |
ldw $6,$29,16 |
ldw $7,$29,20 |
ldw $8,$29,24 |
ldw $9,$29,28 |
ldw $10,$29,32 |
ldw $11,$29,36 |
ldw $12,$29,40 |
ldw $13,$29,44 |
ldw $14,$29,48 |
ldw $15,$29,52 |
ldw $16,$29,56 |
ldw $17,$29,60 |
ldw $18,$29,64 |
ldw $19,$29,68 |
ldw $20,$29,72 |
ldw $21,$29,76 |
ldw $22,$29,80 |
ldw $23,$29,84 |
ldw $24,$29,88 |
ldw $25,$29,92 |
ldw $26,$29,96 |
ldw $27,$29,100 |
ldw $31,$29,104 |
add $1,$27,$0 ; $27 -> $1 |
add $29,$26,0 ; $26 -> sp |
rfx ; return from exception |
|
start: |
mvfs $8,0 |
or $8,$8,1 << 27 ; let vector point to RAM |
mvts $8,0 |
add $29,$0,stack ; set sp |
add $10,$0,_bdata ; copy data segment |
add $8,$0,_edata |
sub $9,$8,$10 |
add $9,$9,_ecode |
j cpytest |
cpyloop: |
ldw $11,$9,0 |
stw $11,$8,0 |
cpytest: |
sub $8,$8,4 |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
add $8,$0,_bbss ; clear bss |
add $9,$0,_ebss |
j clrtest |
clrloop: |
stw $0,$8,0 |
add $8,$8,4 |
clrtest: |
bltu $8,$9,clrloop |
jal main ; call 'main' |
start1: |
j start1 ; loop |
|
enable: |
mvfs $8,0 |
or $8,$8,1 << 23 |
mvts $8,0 |
jr $31 |
|
disable: |
mvfs $8,0 |
and $8,$8,~(1 << 23) |
mvts $8,0 |
jr $31 |
|
getMask: |
mvfs $8,0 |
and $2,$8,0x0000FFFF |
jr $31 |
|
setMask: |
mvfs $8,0 |
and $8,$8,0xFFFF0000 |
and $4,$4,0x0000FFFF |
or $8,$8,$4 |
mvts $8,0 |
jr $31 |
|
getISR: |
sll $4,$4,2 |
ldw $2,$4,irqsrv |
jr $31 |
|
setISR: |
sll $4,$4,2 |
stw $5,$4,irqsrv |
jr $31 |
|
.data |
|
; interrupt service routine table |
|
.align 4 |
|
irqsrv: |
.word 0 ; 00: terminal 0 transmitter interrupt |
.word 0 ; 01: terminal 0 receiver interrupt |
.word 0 ; 02: terminal 1 transmitter interrupt |
.word 0 ; 03: terminal 1 receiver interrupt |
.word 0 ; 04: keyboard interrupt |
.word 0 ; 05: unused |
.word 0 ; 06: unused |
.word 0 ; 07: unused |
.word 0 ; 08: disk interrupt |
.word 0 ; 09: unused |
.word 0 ; 10: unused |
.word 0 ; 11: unused |
.word 0 ; 12: unused |
.word 0 ; 13: unused |
.word 0 ; 14: timer interrupt |
.word 0 ; 15: unused |
.word 0 ; 16: bus timeout exception |
.word 0 ; 17: illegal instruction exception |
.word 0 ; 18: privileged instruction exception |
.word 0 ; 19: divide instruction exception |
.word 0 ; 20: trap instruction exception |
.word 0 ; 21: TLB miss exception |
.word 0 ; 22: TLB write exception |
.word 0 ; 23: TLB invalid exception |
.word 0 ; 24: illegal address exception |
.word 0 ; 25: privileged address exception |
.word 0 ; 26: unused |
.word 0 ; 27: unused |
.word 0 ; 28: unused |
.word 0 ; 29: unused |
.word 0 ; 30: unused |
.word 0 ; 31: unused |
|
.bss |
|
.align 4 |
.space 0x800 |
stack: |
|
.align 4 |
.space 0x800 |
istack: |
/stdalone/memsize/start.h
0,0 → 1,19
/* |
* start.h -- startup code |
*/ |
|
|
#ifndef _START_H_ |
#define _START_H_ |
|
|
typedef int (*ISR)(int irq); |
|
|
void enable(void); |
void disable(void); |
ISR getISR(int irq); |
void setISR(int irq, ISR isr); |
|
|
#endif /* _START_H_ */ |
/stdalone/memsize/main.c
0,0 → 1,194
/* |
* main.c -- start the ball rolling |
*/ |
|
|
#include "stdarg.h" |
#include "start.h" |
|
|
/**************************************************************/ |
|
|
void putchar(char c) { |
unsigned int *base; |
|
if (c == '\n') { |
putchar('\r'); |
} |
base = (unsigned int *) 0xF0300000; |
while ((*(base + 2) & 1) == 0) ; |
*(base + 3) = c; |
} |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void printn(int n) { |
int a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printu(unsigned int n, unsigned int b) { |
unsigned int a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b); |
} |
putchar("0123456789ABCDEF"[n % b]); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == 'd') { |
n = va_arg(ap, int); |
printn(n); |
} else |
if (c == 'u' || c == 'o' || c == 'x') { |
u = va_arg(ap, int); |
printu(u, c == 'o' ? 8 : (c == 'x' ? 16 : 10)); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/**************************************************************/ |
|
|
static char *exceptionCause[32] = { |
/* 00 */ "terminal 0 transmitter interrupt", |
/* 01 */ "terminal 0 receiver interrupt", |
/* 02 */ "terminal 1 transmitter interrupt", |
/* 03 */ "terminal 1 receiver interrupt", |
/* 04 */ "keyboard interrupt", |
/* 05 */ "unknown interrupt", |
/* 06 */ "unknown interrupt", |
/* 07 */ "unknown interrupt", |
/* 08 */ "disk interrupt", |
/* 09 */ "unknown interrupt", |
/* 10 */ "unknown interrupt", |
/* 11 */ "unknown interrupt", |
/* 12 */ "unknown interrupt", |
/* 13 */ "unknown interrupt", |
/* 14 */ "timer interrupt", |
/* 15 */ "unknown interrupt", |
/* 16 */ "bus timeout exception", |
/* 17 */ "illegal instruction exception", |
/* 18 */ "privileged instruction exception", |
/* 19 */ "divide instruction exception", |
/* 20 */ "trap instruction exception", |
/* 21 */ "TLB miss exception", |
/* 22 */ "TLB write exception", |
/* 23 */ "TLB invalid exception", |
/* 24 */ "illegal address exception", |
/* 25 */ "privileged address exception", |
/* 26 */ "unknown exception", |
/* 27 */ "unknown exception", |
/* 28 */ "unknown exception", |
/* 29 */ "unknown exception", |
/* 30 */ "unknown exception", |
/* 31 */ "unknown exception" |
}; |
|
|
int defaultISR(int irq) { |
printf("\n%s\n", exceptionCause[irq]); |
return 0; /* do not skip any instruction */ |
} |
|
|
void initInterrupts(void) { |
int i; |
|
for (i = 0; i < 32; i++) { |
setISR(i, defaultISR); |
} |
} |
|
|
/**************************************************************/ |
|
|
static int busTimeoutSeen; |
|
|
int busTimeoutISR(int irq) { |
busTimeoutSeen = 1; |
return 1; /* skip offending instruction */ |
} |
|
|
int memsize(void) { |
unsigned char *ptr; |
unsigned char b; |
ISR oldService; |
|
busTimeoutSeen = 0; |
oldService = getISR(16); |
setISR(16, busTimeoutISR); |
ptr = (unsigned char *) 0xC0000000; |
while (1) { |
b = *ptr; |
if (busTimeoutSeen) { |
break; |
} |
ptr += (1 << 12); |
} |
setISR(16, oldService); |
return (ptr - (unsigned char *) 0xC0000000) >> 12; |
} |
|
|
/**************************************************************/ |
|
|
void main(void) { |
int numberPages; |
|
initInterrupts(); |
printf("\n"); |
printf("Probing memory...\n"); |
numberPages = memsize(); |
printf("Memory size = %d pages * 4 Kbytes\n", numberPages); |
printf("Halting...\n"); |
} |
/stdalone/memsize/end.s
0,0 → 1,19
; |
; end.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/memsize/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/memsize/Makefile
0,0 → 1,28
# |
# Makefile for "memsize", a program to determine the memory size |
# |
|
BUILD = ../../build |
|
SRC = start.s main.c end.s |
BIN = memsize.bin |
MAP = memsize.map |
|
.PHONY: all install run clean |
|
all: $(BIN) |
|
install: $(BIN) |
mkdir -p $(BUILD)/stdalone |
cp $(BIN) $(BUILD)/stdalone |
cp $(MAP) $(BUILD)/stdalone |
|
run: $(BIN) |
$(BUILD)/bin/sim -i -t 1 -l $(BIN) |
|
$(BIN): $(SRC) |
$(BUILD)/bin/lcc -A -Wo-kernel \ |
-Wl-m -Wl$(MAP) -o $(BIN) $(SRC) |
|
clean: |
rm -f *~ $(BIN) $(MAP) |
/stdalone/memsize/start.s
0,0 → 1,213
; |
; start.s -- startup code |
; |
|
.import main |
.import _ecode |
.import _edata |
.import _ebss |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export enable |
.export disable |
.export getISR |
.export setISR |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
|
; reset arrives here |
reset: |
j start |
|
; interrupts arrive here |
intrpt: |
j isr |
|
; user TLB misses arrive here |
userMiss: |
j userMiss |
|
isr: |
add $26,$29,$0 ; sp -> $26 |
add $27,$1,$0 ; $1 -> $27 |
add $29,$0,istack ; set stack |
sub $29,$29,108 |
stw $2,$29,0 ; save registers |
stw $3,$29,4 |
stw $4,$29,8 |
stw $5,$29,12 |
stw $6,$29,16 |
stw $7,$29,20 |
stw $8,$29,24 |
stw $9,$29,28 |
stw $10,$29,32 |
stw $11,$29,36 |
stw $12,$29,40 |
stw $13,$29,44 |
stw $14,$29,48 |
stw $15,$29,52 |
stw $16,$29,56 |
stw $17,$29,60 |
stw $18,$29,64 |
stw $19,$29,68 |
stw $20,$29,72 |
stw $21,$29,76 |
stw $22,$29,80 |
stw $23,$29,84 |
stw $24,$29,88 |
stw $25,$29,92 |
stw $26,$29,96 |
stw $27,$29,100 |
stw $31,$29,104 |
mvfs $4,0 ; $4 = IRQ number |
slr $4,$4,16 |
and $4,$4,0x1F |
sll $26,$4,2 ; $26 = 4 * IRQ number |
ldw $26,$26,irqsrv ; get addr of service routine |
jalr $26 ; call service routine |
beq $2,$0,resume ; resume instruction if ISR returned 0 |
add $30,$30,4 ; else skip offending instruction |
resume: |
ldw $2,$29,0 |
ldw $3,$29,4 |
ldw $4,$29,8 |
ldw $5,$29,12 |
ldw $6,$29,16 |
ldw $7,$29,20 |
ldw $8,$29,24 |
ldw $9,$29,28 |
ldw $10,$29,32 |
ldw $11,$29,36 |
ldw $12,$29,40 |
ldw $13,$29,44 |
ldw $14,$29,48 |
ldw $15,$29,52 |
ldw $16,$29,56 |
ldw $17,$29,60 |
ldw $18,$29,64 |
ldw $19,$29,68 |
ldw $20,$29,72 |
ldw $21,$29,76 |
ldw $22,$29,80 |
ldw $23,$29,84 |
ldw $24,$29,88 |
ldw $25,$29,92 |
ldw $26,$29,96 |
ldw $27,$29,100 |
ldw $31,$29,104 |
add $1,$27,$0 ; $27 -> $1 |
add $29,$26,0 ; $26 -> sp |
rfx ; return from exception |
|
start: |
mvfs $8,0 |
or $8,$8,1 << 27 ; let vector point to RAM |
mvts $8,0 |
add $29,$0,stack ; set sp |
add $10,$0,_bdata ; copy data segment |
add $8,$0,_edata |
sub $9,$8,$10 |
add $9,$9,_ecode |
j cpytest |
cpyloop: |
ldw $11,$9,0 |
stw $11,$8,0 |
cpytest: |
sub $8,$8,4 |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
add $8,$0,_bbss ; clear bss |
add $9,$0,_ebss |
j clrtest |
clrloop: |
stw $0,$8,0 |
add $8,$8,4 |
clrtest: |
bltu $8,$9,clrloop |
jal main ; call 'main' |
start1: |
j start1 ; loop |
|
enable: |
mvfs $8,0 |
or $8,$8,1 << 23 |
mvts $8,0 |
jr $31 |
|
disable: |
mvfs $8,0 |
and $8,$8,~(1 << 23) |
mvts $8,0 |
jr $31 |
|
getISR: |
sll $4,$4,2 |
ldw $2,$4,irqsrv |
jr $31 |
|
setISR: |
sll $4,$4,2 |
stw $5,$4,irqsrv |
jr $31 |
|
.data |
|
; interrupt service routine table |
|
.align 4 |
|
irqsrv: |
.word 0 ; 00: terminal 0 transmitter interrupt |
.word 0 ; 01: terminal 0 receiver interrupt |
.word 0 ; 02: terminal 1 transmitter interrupt |
.word 0 ; 03: terminal 1 receiver interrupt |
.word 0 ; 04: keyboard interrupt |
.word 0 ; 05: unused |
.word 0 ; 06: unused |
.word 0 ; 07: unused |
.word 0 ; 08: disk interrupt |
.word 0 ; 09: unused |
.word 0 ; 10: unused |
.word 0 ; 11: unused |
.word 0 ; 12: unused |
.word 0 ; 13: unused |
.word 0 ; 14: timer interrupt |
.word 0 ; 15: unused |
.word 0 ; 16: bus timeout exception |
.word 0 ; 17: illegal instruction exception |
.word 0 ; 18: privileged instruction exception |
.word 0 ; 19: divide instruction exception |
.word 0 ; 20: trap instruction exception |
.word 0 ; 21: TLB miss exception |
.word 0 ; 22: TLB write exception |
.word 0 ; 23: TLB invalid exception |
.word 0 ; 24: illegal address exception |
.word 0 ; 25: privileged address exception |
.word 0 ; 26: unused |
.word 0 ; 27: unused |
.word 0 ; 28: unused |
.word 0 ; 29: unused |
.word 0 ; 30: unused |
.word 0 ; 31: unused |
|
.bss |
|
.align 4 |
.space 0x800 |
stack: |
|
.align 4 |
.space 0x800 |
istack: |
/stdalone/twotasks-1/os/start.h
0,0 → 1,23
/* |
* start.h -- startup code |
*/ |
|
|
#ifndef _START_H_ |
#define _START_H_ |
|
|
typedef void (*ISR)(int irq, unsigned int *registers); |
|
|
void enable(void); |
void disable(void); |
void orMask(unsigned int mask); |
void andMask(unsigned int mask); |
ISR getISR(int irq); |
void setISR(int irq, ISR isr); |
void startTask(void); |
void setTLB(int index, unsigned int entryHi, unsigned int entryLo); |
|
|
#endif /* _START_H_ */ |
/stdalone/twotasks-1/os/main.c
0,0 → 1,345
/* |
* main.c -- start the ball rolling |
*/ |
|
|
#include "stdarg.h" |
#include "start.h" |
|
|
/**************************************************************/ |
|
|
int currentTask; |
unsigned int *currentStkTop; |
|
|
/**************************************************************/ |
|
|
unsigned int task0Stack[256]; |
unsigned int *task0StkTop = task0Stack + 256; |
|
|
unsigned char task1Code[] = { |
#include "task1.dump" |
}; |
|
unsigned int task1Stack[256]; |
unsigned int *task1StkTop = task1Stack + 256; |
|
|
unsigned char task2Code[] = { |
#include "task2.dump" |
}; |
|
unsigned int task2Stack[256]; |
unsigned int *task2StkTop = task2Stack + 256; |
|
|
/**************************************************************/ |
|
|
void putchar(char c) { |
unsigned int *base; |
|
if (c == '\n') { |
putchar('\r'); |
} |
base = (unsigned int *) 0xF0300000; |
while ((*(base + 2) & 1) == 0) ; |
*(base + 3) = c; |
} |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void printn(int n) { |
int a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printu(unsigned int n, unsigned int b) { |
unsigned int a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b); |
} |
putchar("0123456789ABCDEF"[n % b]); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == 'd') { |
n = va_arg(ap, int); |
printn(n); |
} else |
if (c == 'u' || c == 'o' || c == 'x') { |
u = va_arg(ap, int); |
printu(u, c == 'o' ? 8 : (c == 'x' ? 16 : 10)); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/**************************************************************/ |
|
|
static char *exceptionCause[32] = { |
/* 00 */ "terminal 0 transmitter interrupt", |
/* 01 */ "terminal 0 receiver interrupt", |
/* 02 */ "terminal 1 transmitter interrupt", |
/* 03 */ "terminal 1 receiver interrupt", |
/* 04 */ "keyboard interrupt", |
/* 05 */ "unknown interrupt", |
/* 06 */ "unknown interrupt", |
/* 07 */ "unknown interrupt", |
/* 08 */ "disk interrupt", |
/* 09 */ "unknown interrupt", |
/* 10 */ "unknown interrupt", |
/* 11 */ "unknown interrupt", |
/* 12 */ "unknown interrupt", |
/* 13 */ "unknown interrupt", |
/* 14 */ "timer interrupt", |
/* 15 */ "unknown interrupt", |
/* 16 */ "bus timeout exception", |
/* 17 */ "illegal instruction exception", |
/* 18 */ "privileged instruction exception", |
/* 19 */ "divide instruction exception", |
/* 20 */ "trap instruction exception", |
/* 21 */ "TLB miss exception", |
/* 22 */ "TLB write exception", |
/* 23 */ "TLB invalid exception", |
/* 24 */ "illegal address exception", |
/* 25 */ "privileged address exception", |
/* 26 */ "unknown exception", |
/* 27 */ "unknown exception", |
/* 28 */ "unknown exception", |
/* 29 */ "unknown exception", |
/* 30 */ "unknown exception", |
/* 31 */ "unknown exception" |
}; |
|
|
void defaultISR(int irq, unsigned int *registers) { |
printf("\n%s\n", exceptionCause[irq]); |
} |
|
|
void initInterrupts(void) { |
int i; |
|
for (i = 0; i < 32; i++) { |
setISR(i, defaultISR); |
} |
} |
|
|
/**************************************************************/ |
|
|
unsigned int getNumber(unsigned char *p) { |
return (unsigned int) *(p + 0) << 24 | |
(unsigned int) *(p + 1) << 16 | |
(unsigned int) *(p + 2) << 8 | |
(unsigned int) *(p + 3) << 0; |
} |
|
|
void loadTask(unsigned char *code, |
unsigned int physCodeAddr, |
unsigned int physDataAddr) { |
unsigned int magic; |
unsigned int csize; |
unsigned int dsize; |
unsigned int bsize; |
unsigned char *virtLoadAddr; |
int i; |
|
magic = getNumber(code); |
code += sizeof(unsigned int); |
csize = getNumber(code); |
code += sizeof(unsigned int); |
dsize = getNumber(code); |
code += sizeof(unsigned int); |
bsize = getNumber(code); |
code += sizeof(unsigned int); |
if (magic != 0x1AA09232) { |
printf("Error: Load module is not executable!\n"); |
while (1) ; |
} |
code += 4 * sizeof(unsigned int); |
printf("(csize = 0x%x, dsize = 0x%x, bsize = 0x%x)\n", |
csize, dsize, bsize); |
virtLoadAddr = (unsigned char *) (0xC0000000 | physCodeAddr); |
for (i = 0; i < csize; i++) { |
*virtLoadAddr++ = *code++; |
} |
virtLoadAddr = (unsigned char *) (0xC0000000 | physDataAddr); |
for (i = 0; i < dsize; i++) { |
*virtLoadAddr++ = *code++; |
} |
for (i = 0; i < bsize; i++) { |
*virtLoadAddr++ = '\0'; |
} |
} |
|
|
/**************************************************************/ |
|
|
void trapISR(int irq, unsigned int *registers) { |
/* 'putchar' is the only system call yet */ |
putchar(registers[4]); |
/* skip the trap instruction */ |
registers[30] += 4; |
} |
|
|
/**************************************************************/ |
|
|
void missISR(int irq, unsigned int *registers) { |
if (currentTask == 1) { |
setTLB(5, 0x00000000, 64 << 12 | 0x01); /* code at 256 k */ |
setTLB(27, 0x00001000, 68 << 12 | 0x03); /* data at 272 k */ |
setTLB(22, 0x7FFFF000, 80 << 12 | 0x03); /* user-mode stack at 320 k */ |
} else if (currentTask == 2) { |
setTLB(5, 0x00000000, 96 << 12 | 0x01); /* code at 384 k */ |
setTLB(27, 0x00001000, 100 << 12 | 0x03); /* data at 400 k */ |
setTLB(22, 0x7FFFF000, 112 << 12 | 0x03); /* user-mode stack at 448 k */ |
} |
} |
|
|
void flushTLB(void) { |
unsigned int invalPage; |
int i; |
|
invalPage = 0xC0000000; |
for (i = 0; i < 32; i++) { |
setTLB(i, invalPage, 0); |
invalPage += (1 << 12); |
} |
} |
|
|
/**************************************************************/ |
|
|
void initTimer(void) { |
unsigned int *timerBase; |
|
timerBase = (unsigned int *) 0xF0000000; |
*(timerBase + 1) = 1000; |
*timerBase = 2; |
orMask(1 << 14); |
} |
|
|
int task1Started = 0; |
int task2Started = 0; |
|
|
void timerISR(int irq, unsigned int *registers) { |
unsigned int *timerBase; |
|
timerBase = (unsigned int *) 0xF0000000; |
*timerBase = 2; |
printf(">|<"); |
if (currentTask == 0) { |
if (!task1Started) { |
/* load & start task1 */ |
printf("\nOS: loading task1\n"); |
loadTask(task1Code, 64 << 12, 68 << 12); |
printf("OS: starting task1\n"); |
task1Started = 1; |
currentTask = 1; |
currentStkTop = task1StkTop; |
flushTLB(); |
startTask(); |
} |
} else if (currentTask == 1) { |
if (!task2Started) { |
/* load & start task2 */ |
printf("\nOS: loading task2\n"); |
loadTask(task2Code, 96 << 12, 100 << 12); |
printf("OS: starting task2\n"); |
task2Started = 1; |
currentTask = 2; |
currentStkTop = task2StkTop; |
flushTLB(); |
startTask(); |
} else { |
/* switch tasks */ |
currentTask = 2; |
currentStkTop = task2StkTop; |
flushTLB(); |
} |
} else if (currentTask == 2) { |
/* switch tasks */ |
currentTask = 1; |
currentStkTop = task1StkTop; |
flushTLB(); |
} |
} |
|
|
/**************************************************************/ |
|
|
void main(void) { |
currentTask = 0; |
currentStkTop = task0StkTop; |
printf("\n"); |
printf("OS: initializing interrupts\n"); |
initInterrupts(); |
setISR(20, trapISR); |
setISR(21, missISR); |
setISR(14, timerISR); |
printf("OS: initializing timer\n"); |
initTimer(); |
printf("OS: waiting for interrupt...\n"); |
enable(); |
while (1) ; |
} |
/stdalone/twotasks-1/os/end.s
0,0 → 1,19
; |
; end.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/twotasks-1/os/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/twotasks-1/os/Makefile
0,0 → 1,23
BUILD = ../../../build |
|
SRC = start.s main.c end.s |
BIN = twotasks-1.bin |
MAP = twotasks-1.map |
|
all: $(BIN) |
|
run: $(BIN) |
$(BUILD)/bin/sim -i -t 1 -l $(BIN) |
|
$(BIN): $(SRC) task1.dump task2.dump |
$(BUILD)/bin/lcc -A -Wo-kernel \ |
-Wl-m -Wl$(MAP) -o $(BIN) $(SRC) |
|
task1.dump: |
../dump/dump ../task1/task1 task1.dump |
|
task2.dump: |
../dump/dump ../task2/task2 task2.dump |
|
clean: |
rm -f *~ task1.dump task2.dump $(BIN) $(MAP) |
/stdalone/twotasks-1/os/start.s
0,0 → 1,278
; |
; start.s -- startup code |
; |
|
.import main |
.import task0StkTop |
.import currentStkTop |
.import _ecode |
.import _edata |
.import _ebss |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export enable |
.export disable |
.export orMask |
.export andMask |
.export getISR |
.export setISR |
.export startTask |
.export setTLB |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
|
; reset arrives here |
reset: |
j start |
|
; interrupts arrive here |
intrpt: |
j isr |
|
; user TLB misses arrive here |
userMiss: |
j isr |
|
isr: |
add $26,$29,$0 ; sp -> $26 |
add $27,$1,$0 ; $1 -> $27 |
ldw $29,$0,currentStkTop ; setup kernel mode stack |
sub $29,$29,128 ; save registers |
stw $2,$29,8 |
stw $3,$29,12 |
stw $4,$29,16 |
stw $5,$29,20 |
stw $6,$29,24 |
stw $7,$29,28 |
stw $8,$29,32 |
stw $9,$29,36 |
stw $10,$29,40 |
stw $11,$29,44 |
stw $12,$29,48 |
stw $13,$29,52 |
stw $14,$29,56 |
stw $15,$29,60 |
stw $16,$29,64 |
stw $17,$29,68 |
stw $18,$29,72 |
stw $19,$29,76 |
stw $20,$29,80 |
stw $21,$29,84 |
stw $22,$29,88 |
stw $23,$29,92 |
stw $24,$29,96 |
stw $25,$29,100 |
stw $26,$29,116 ; this is the task's sp |
stw $27,$29,4 ; this is the task's $1 |
stw $30,$29,120 ; this is the task's resumption addr |
stw $31,$29,124 |
add $5,$29,$0 ; $5 = pointer to register array |
mvfs $4,0 ; $4 = IRQ number |
slr $4,$4,16 |
and $4,$4,0x1F |
sll $26,$4,2 ; $26 = 4 * IRQ number |
ldw $26,$26,irqsrv ; get addr of service routine |
jalr $26 ; call service routine |
j resume ; resume task if ISR returns |
|
; resume a task |
resume: |
ldw $29,$0,currentStkTop ; setup kernel mode stack |
sub $29,$29,128 ; restore registers |
ldw $2,$29,8 |
ldw $3,$29,12 |
ldw $4,$29,16 |
ldw $5,$29,20 |
ldw $6,$29,24 |
ldw $7,$29,28 |
ldw $8,$29,32 |
ldw $9,$29,36 |
ldw $10,$29,40 |
ldw $11,$29,44 |
ldw $12,$29,48 |
ldw $13,$29,52 |
ldw $14,$29,56 |
ldw $15,$29,60 |
ldw $16,$29,64 |
ldw $17,$29,68 |
ldw $18,$29,72 |
ldw $19,$29,76 |
ldw $20,$29,80 |
ldw $21,$29,84 |
ldw $22,$29,88 |
ldw $23,$29,92 |
ldw $24,$29,96 |
ldw $25,$29,100 |
ldw $26,$29,116 ; this is the task's sp |
ldw $27,$29,4 ; this is the task's $1 |
ldw $30,$29,120 ; this is the task's resumption addr |
ldw $31,$29,124 |
add $1,$27,$0 ; $27 -> $1 |
add $29,$26,$0 ; $26 -> sp |
rfx ; return from exception |
|
start: |
mvfs $8,0 |
or $8,$8,1 << 27 ; let vector point to RAM |
mvts $8,0 |
add $10,$0,_bdata ; copy data segment |
add $8,$0,_edata |
sub $9,$8,$10 |
add $9,$9,_ecode |
j cpytest |
cpyloop: |
ldw $11,$9,0 |
stw $11,$8,0 |
cpytest: |
sub $8,$8,4 |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
add $8,$0,_bbss ; clear bss |
add $9,$0,_ebss |
j clrtest |
clrloop: |
stw $0,$8,0 |
add $8,$8,4 |
clrtest: |
bltu $8,$9,clrloop |
ldw $29,$0,task0StkTop ; setup kernel mode stack for task 0 |
jal main ; call 'main' |
start1: |
j start1 ; loop |
|
enable: |
mvfs $8,0 |
or $8,$8,1 << 23 |
mvts $8,0 |
jr $31 |
|
disable: |
mvfs $8,0 |
and $8,$8,~(1 << 23) |
mvts $8,0 |
jr $31 |
|
orMask: |
mvfs $8,0 |
and $4,$4,0x0000FFFF ; use lower 16 bits only |
or $8,$8,$4 |
mvts $8,0 |
jr $31 |
|
andMask: |
mvfs $8,0 |
or $4,$4,0xFFFF0000 ; use lower 16 bits only |
and $8,$8,$4 |
mvts $8,0 |
jr $31 |
|
getISR: |
sll $4,$4,2 |
ldw $2,$4,irqsrv |
jr $31 |
|
setISR: |
sll $4,$4,2 |
stw $5,$4,irqsrv |
jr $31 |
|
startTask: |
ldw $29,$0,currentStkTop ; setup kernel mode stack |
sub $29,$29,128 |
stw $0,$29,0 ; preset registers |
stw $0,$29,4 |
stw $0,$29,8 |
stw $0,$29,12 |
stw $0,$29,16 |
stw $0,$29,20 |
stw $0,$29,24 |
stw $0,$29,28 |
stw $0,$29,32 |
stw $0,$29,36 |
stw $0,$29,40 |
stw $0,$29,44 |
stw $0,$29,48 |
stw $0,$29,52 |
stw $0,$29,56 |
stw $0,$29,60 |
stw $0,$29,64 |
stw $0,$29,68 |
stw $0,$29,72 |
stw $0,$29,76 |
stw $0,$29,80 |
stw $0,$29,84 |
stw $0,$29,88 |
stw $0,$29,92 |
stw $0,$29,96 |
stw $0,$29,100 |
stw $0,$29,104 |
stw $0,$29,108 |
stw $0,$29,112 |
add $8,$0,0x80000000 |
stw $8,$29,116 ; sp |
stw $0,$29,120 ; task starts at virtual addr 0 |
stw $0,$29,124 |
mvfs $8,0 |
or $8,$8,1 << 25 ; set previous mode to 'user' |
or $8,$8,1 << 22 ; and enable interrupts |
mvts $8,0 |
j resume |
|
setTLB: |
mvts $4,1 ; set index |
mvts $5,2 ; set entryHi |
mvts $6,3 ; set entryLo |
tbwi ; write TLB entry at index |
jr $31 |
|
.data |
|
; interrupt service routine table |
|
.align 4 |
|
irqsrv: |
.word 0 ; 00: terminal 0 transmitter interrupt |
.word 0 ; 01: terminal 0 receiver interrupt |
.word 0 ; 02: terminal 1 transmitter interrupt |
.word 0 ; 03: terminal 1 receiver interrupt |
.word 0 ; 04: keyboard interrupt |
.word 0 ; 05: unused |
.word 0 ; 06: unused |
.word 0 ; 07: unused |
.word 0 ; 08: disk interrupt |
.word 0 ; 09: unused |
.word 0 ; 10: unused |
.word 0 ; 11: unused |
.word 0 ; 12: unused |
.word 0 ; 13: unused |
.word 0 ; 14: timer interrupt |
.word 0 ; 15: unused |
.word 0 ; 16: bus timeout exception |
.word 0 ; 17: illegal instruction exception |
.word 0 ; 18: privileged instruction exception |
.word 0 ; 19: divide instruction exception |
.word 0 ; 20: trap instruction exception |
.word 0 ; 21: TLB miss exception |
.word 0 ; 22: TLB write exception |
.word 0 ; 23: TLB invalid exception |
.word 0 ; 24: illegal address exception |
.word 0 ; 25: privileged address exception |
.word 0 ; 26: unused |
.word 0 ; 27: unused |
.word 0 ; 28: unused |
.word 0 ; 29: unused |
.word 0 ; 30: unused |
.word 0 ; 31: unused |
/stdalone/twotasks-1/task1/c0.s
0,0 → 1,30
; |
; c0.s -- startup code and begin-of-segment labels |
; |
|
.import main |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.import _ecode |
.import _edata |
.import _ebss |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
.align 4 |
|
start: |
jal main ; call 'main' function |
stop: |
j stop ; just to be sure... |
/stdalone/twotasks-1/task1/c1.s
0,0 → 1,19
; |
; c1.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/twotasks-1/task1/task1.c
0,0 → 1,95
/* |
* task1.c -- a simple task |
*/ |
|
|
#include "putchar.h" |
#include "stdarg.h" |
|
|
/**************************************************************/ |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void printn(int n) { |
int a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printu(unsigned int n, unsigned int b) { |
unsigned int a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b); |
} |
putchar("0123456789ABCDEF"[n % b]); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == 'd') { |
n = va_arg(ap, int); |
printn(n); |
} else |
if (c == 'u' || c == 'o' || c == 'x') { |
u = va_arg(ap, int); |
printu(u, c == 'o' ? 8 : (c == 'x' ? 16 : 10)); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/**************************************************************/ |
|
|
void main(void) { |
int i; |
|
printf("TASK1: executing...\n"); |
i = 0; |
while (1) { |
printf("TASK1: %d\n", i); |
i++; |
} |
} |
/stdalone/twotasks-1/task1/putchar.s
0,0 → 1,10
; |
; putchar.s -- putchar library function |
; |
|
.code |
.export putchar |
|
putchar: |
trap |
jr $31 |
/stdalone/twotasks-1/task1/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/twotasks-1/task1/putchar.h
0,0 → 1,13
/* |
* putchar.h -- putchar library function |
*/ |
|
|
#ifndef _PUTCHAR_H_ |
#define _PUTCHAR_H_ |
|
|
void putchar(char c); |
|
|
#endif /* _PUTCHAR_H_ */ |
/stdalone/twotasks-1/task1/Makefile
0,0 → 1,21
BUILD = ../../../build |
|
all: task1 |
|
task1: c0.o task1.o putchar.o c1.o |
$(BUILD)/bin/ld -o task1 c0.o task1.o putchar.o c1.o |
|
c0.o: c0.s |
$(BUILD)/bin/as -o c0.o c0.s |
|
task1.o: task1.c |
$(BUILD)/bin/lcc -A -c -o task1.o task1.c |
|
putchar.o: putchar.s |
$(BUILD)/bin/as -o putchar.o putchar.s |
|
c1.o: c1.s |
$(BUILD)/bin/as -o c1.o c1.s |
|
clean: |
rm -f *~ c0.o task1.o putchar.o c1.o task1 |
/stdalone/twotasks-1/task2/c0.s
0,0 → 1,30
; |
; c0.s -- startup code and begin-of-segment labels |
; |
|
.import main |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.import _ecode |
.import _edata |
.import _ebss |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
.align 4 |
|
start: |
jal main ; call 'main' function |
stop: |
j stop ; just to be sure... |
/stdalone/twotasks-1/task2/c1.s
0,0 → 1,19
; |
; c1.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/twotasks-1/task2/task2.c
0,0 → 1,95
/* |
* task2.c -- a simple task |
*/ |
|
|
#include "putchar.h" |
#include "stdarg.h" |
|
|
/**************************************************************/ |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void printn(int n) { |
int a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printu(unsigned int n, unsigned int b) { |
unsigned int a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b); |
} |
putchar("0123456789ABCDEF"[n % b]); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == 'd') { |
n = va_arg(ap, int); |
printn(n); |
} else |
if (c == 'u' || c == 'o' || c == 'x') { |
u = va_arg(ap, int); |
printu(u, c == 'o' ? 8 : (c == 'x' ? 16 : 10)); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/**************************************************************/ |
|
|
void main(void) { |
int i; |
|
printf("TASK2: executing...\n"); |
i = 0; |
while (1) { |
printf("TASK2: %d\n", i); |
i++; |
} |
} |
/stdalone/twotasks-1/task2/putchar.s
0,0 → 1,10
; |
; putchar.s -- putchar library function |
; |
|
.code |
.export putchar |
|
putchar: |
trap |
jr $31 |
/stdalone/twotasks-1/task2/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/twotasks-1/task2/putchar.h
0,0 → 1,13
/* |
* putchar.h -- putchar library function |
*/ |
|
|
#ifndef _PUTCHAR_H_ |
#define _PUTCHAR_H_ |
|
|
void putchar(char c); |
|
|
#endif /* _PUTCHAR_H_ */ |
/stdalone/twotasks-1/task2/Makefile
0,0 → 1,21
BUILD = ../../../build |
|
all: task2 |
|
task2: c0.o task2.o putchar.o c1.o |
$(BUILD)/bin/ld -o task2 c0.o task2.o putchar.o c1.o |
|
c0.o: c0.s |
$(BUILD)/bin/as -o c0.o c0.s |
|
task2.o: task2.c |
$(BUILD)/bin/lcc -A -c -o task2.o task2.c |
|
putchar.o: putchar.s |
$(BUILD)/bin/as -o putchar.o putchar.s |
|
c1.o: c1.s |
$(BUILD)/bin/as -o c1.o c1.s |
|
clean: |
rm -f *~ c0.o task2.o putchar.o c1.o task2 |
/stdalone/twotasks-1/dump/dump.c
0,0 → 1,48
/* |
* dump.c -- dump a binary file as contents of a C array |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
|
|
int main(int argc, char *argv[]) { |
FILE *infile, *outfile; |
int c, n; |
|
if (argc != 3) { |
printf("Usage: %s <infile> <outfile>\n", argv[0]); |
return 1; |
} |
infile = fopen(argv[1], "rb"); |
if (infile == NULL) { |
printf("Error: cannot open file '%s' for input\n", argv[1]); |
return 1; |
} |
outfile = fopen(argv[2], "wt"); |
if (outfile == NULL) { |
printf("Error: cannot open file '%s' for output\n", argv[2]); |
return 1; |
} |
n = 0; |
while (1) { |
c = getc(infile); |
if (c == EOF) { |
break; |
} |
fprintf(outfile, "0x%02X, ", c); |
n++; |
if (n == 8) { |
n = 0; |
fprintf(outfile, "\n"); |
} |
} |
if (n != 0) { |
fprintf(outfile, "\n"); |
} |
fclose(infile); |
fclose(outfile); |
return 0; |
} |
/stdalone/twotasks-1/dump/Makefile
0,0 → 1,15
# |
# Makefile for dump utility |
# |
|
.PHONY: all install clean |
|
all: dump |
|
install: dump |
|
dump: dump.c |
gcc -m32 -g -Wall -o dump dump.c |
|
clean: |
rm -f *~ dump |
/stdalone/twotasks-1/Makefile
0,0 → 1,37
# |
# Makefile for "twotasks-1", a tiny OS which runs two tasks |
# (with fixed TLB entries and no page tables) |
# |
|
BUILD = ../../build |
|
.PHONY: all install run clean |
|
all: dump/dump task1/task1 task2/task2 os/twotasks-1.bin |
|
install: dump/dump task1/task1 task2/task2 os/twotasks-1.bin |
mkdir -p $(BUILD)/stdalone |
cp os/twotasks-1.bin $(BUILD)/stdalone |
cp os/twotasks-1.map $(BUILD)/stdalone |
|
run: dump/dump task1/task1 task2/task2 os/twotasks-1.bin |
$(MAKE) -C os run |
|
dump/dump: |
$(MAKE) -C dump |
|
task1/task1: |
$(MAKE) -C task1 |
|
task2/task2: |
$(MAKE) -C task2 |
|
os/twotasks-1.bin: |
$(MAKE) -C os |
|
clean: |
$(MAKE) -C dump clean |
$(MAKE) -C task1 clean |
$(MAKE) -C task2 clean |
$(MAKE) -C os clean |
rm -f *~ |
/stdalone/wrtmbr/mbr/mbr.s
0,0 → 1,54
; |
; mbr.s -- the master boot record |
; |
|
.set tba,0xF0300000 ; terminal base address |
.set tos,0xC0001000 ; top of stack |
|
start: |
add $29,$0,tos ; set stackpointer |
jal msgout ; output message |
stop: |
j stop ; halt by looping |
|
msgout: |
sub $29,$29,8 ; allocate stack frame |
stw $31,$29,0 ; save return register |
stw $16,$29,4 ; save local variable |
add $16,$0,msg ; pointer to string |
loop: |
ldbu $4,$16,0 ; get char |
beq $4,$0,exit ; null - finished |
jal out ; output char |
add $16,$16,1 ; bump pointer |
j loop ; next char |
exit: |
ldw $31,$29,0 ; restore return register |
ldw $16,$29,4 ; restore local variable |
add $29,$29,8 ; release stack frame |
jr $31 ; return |
|
out: |
add $8,$0,tba ; set I/O base address |
out1: |
ldw $9,$8,8 ; get xmtr status |
and $9,$9,1 ; xmtr ready? |
beq $9,$0,out1 ; no - wait |
stw $4,$8,12 ; send char |
jr $31 ; return |
|
msg: |
.byte 0x0D, 0x0A |
.byte "Error: This is the default MBR, " |
.byte "which cannot load anything." |
.byte 0x0D, 0x0A |
.byte "Please replace the disk, or " |
.byte "write an operating system onto it." |
.byte 0x0D, 0x0A |
.byte "Execution halted." |
.byte 0x0D, 0x0A |
.byte 0x0D, 0x0A, 0 |
|
.locate 512-2 |
sign: |
.byte 0x55, 0xAA |
/stdalone/wrtmbr/mbr/dump.c
0,0 → 1,48
/* |
* dump.c -- dump a binary file as contents of a C array |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
|
|
int main(int argc, char *argv[]) { |
FILE *infile, *outfile; |
int c, n; |
|
if (argc != 3) { |
printf("Usage: %s <infile> <outfile>\n", argv[0]); |
return 1; |
} |
infile = fopen(argv[1], "rb"); |
if (infile == NULL) { |
printf("Error: cannot open file '%s' for input\n", argv[1]); |
return 1; |
} |
outfile = fopen(argv[2], "wt"); |
if (outfile == NULL) { |
printf("Error: cannot open file '%s' for output\n", argv[2]); |
return 1; |
} |
n = 0; |
while (1) { |
c = getc(infile); |
if (c == EOF) { |
break; |
} |
fprintf(outfile, "0x%02X, ", c); |
n++; |
if (n == 8) { |
n = 0; |
fprintf(outfile, "\n"); |
} |
} |
if (n != 0) { |
fprintf(outfile, "\n"); |
} |
fclose(infile); |
fclose(outfile); |
return 0; |
} |
/stdalone/wrtmbr/mbr/Makefile
0,0 → 1,24
# |
# Makefile for assembling the default master boot record |
# |
|
BUILD = ../../../build |
|
.PHONY: all clean |
|
all: mbr.dump |
|
mbr.dump: dump mbr.bin |
./dump mbr.bin mbr.dump |
|
dump: dump.c |
gcc -m32 -g -Wall -o dump dump.c |
|
mbr.bin: mbr.o |
$(BUILD)/bin/ld -h -rc 0xC0000000 -o mbr.bin mbr.o |
|
mbr.o: mbr.s |
$(BUILD)/bin/as -o mbr.o mbr.s |
|
clean: |
rm -f *~ dump mbr.o mbr.bin mbr.dump |
/stdalone/wrtmbr/start.h
0,0 → 1,19
/* |
* start.h -- startup code |
*/ |
|
|
#ifndef _START_H_ |
#define _START_H_ |
|
|
typedef int (*ISR)(int irq); |
|
|
void enable(void); |
void disable(void); |
ISR getISR(int irq); |
void setISR(int irq, ISR isr); |
|
|
#endif /* _START_H_ */ |
/stdalone/wrtmbr/main.c
0,0 → 1,312
/* |
* main.c -- start the ball rolling |
*/ |
|
|
#include "stdarg.h" |
#include "start.h" |
|
|
#define SCT_SIZE 512 /* in bytes */ |
|
#define DISK_BASE 0xF0400000 |
|
#define DISK_CTRL 0 /* word offset from DISK_BASE */ |
#define DISK_CNT 1 /* ditto */ |
#define DISK_SCT 2 /* ditto */ |
#define DISK_CAP 3 /* ditto */ |
|
#define DISK_BUF_STRT 0x00020000 /* word offset from DISK_BASE */ |
#define DISK_BUF_SIZE 0x00000400 /* in words */ |
|
#define DISK_CTRL_STRT 0x01 |
#define DISK_CTRL_IEN 0x02 |
#define DISK_CTRL_WRT 0x04 |
#define DISK_CTRL_ERR 0x08 |
#define DISK_CTRL_DONE 0x10 |
#define DISK_CTRL_RDY 0x20 |
|
|
/**************************************************************/ |
|
|
void putchar(char c) { |
unsigned int *base; |
|
if (c == '\n') { |
putchar('\r'); |
} |
base = (unsigned int *) 0xF0300000; |
while ((*(base + 2) & 1) == 0) ; |
*(base + 3) = c; |
} |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void printn(int n) { |
int a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printu(unsigned int n, unsigned int b) { |
unsigned int a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b); |
} |
putchar("0123456789ABCDEF"[n % b]); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == 'd') { |
n = va_arg(ap, int); |
printn(n); |
} else |
if (c == 'u' || c == 'o' || c == 'x') { |
u = va_arg(ap, int); |
printu(u, c == 'o' ? 8 : (c == 'x' ? 16 : 10)); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/**************************************************************/ |
|
|
static char *exceptionCause[32] = { |
/* 00 */ "terminal 0 transmitter interrupt", |
/* 01 */ "terminal 0 receiver interrupt", |
/* 02 */ "terminal 1 transmitter interrupt", |
/* 03 */ "terminal 1 receiver interrupt", |
/* 04 */ "keyboard interrupt", |
/* 05 */ "unknown interrupt", |
/* 06 */ "unknown interrupt", |
/* 07 */ "unknown interrupt", |
/* 08 */ "disk interrupt", |
/* 09 */ "unknown interrupt", |
/* 10 */ "unknown interrupt", |
/* 11 */ "unknown interrupt", |
/* 12 */ "unknown interrupt", |
/* 13 */ "unknown interrupt", |
/* 14 */ "timer interrupt", |
/* 15 */ "unknown interrupt", |
/* 16 */ "bus timeout exception", |
/* 17 */ "illegal instruction exception", |
/* 18 */ "privileged instruction exception", |
/* 19 */ "divide instruction exception", |
/* 20 */ "trap instruction exception", |
/* 21 */ "TLB miss exception", |
/* 22 */ "TLB write exception", |
/* 23 */ "TLB invalid exception", |
/* 24 */ "illegal address exception", |
/* 25 */ "privileged address exception", |
/* 26 */ "unknown exception", |
/* 27 */ "unknown exception", |
/* 28 */ "unknown exception", |
/* 29 */ "unknown exception", |
/* 30 */ "unknown exception", |
/* 31 */ "unknown exception" |
}; |
|
|
int defaultISR(int irq) { |
printf("\n%s\n", exceptionCause[irq]); |
return 0; /* do not skip any instruction */ |
} |
|
|
void initInterrupts(void) { |
int i; |
|
for (i = 0; i < 32; i++) { |
setISR(i, defaultISR); |
} |
} |
|
|
/**************************************************************/ |
|
|
/* the MBR buffer need not be word-aligned */ |
unsigned char mbr[SCT_SIZE] = { |
#include "mbr/mbr.dump" |
}; |
|
/* the following two buffers must be word-aligned */ |
unsigned int wrBuf[SCT_SIZE / sizeof(unsigned int)]; |
unsigned int rdBuf[SCT_SIZE / sizeof(unsigned int)]; |
|
|
void copyMBR(void) { |
unsigned char *p; |
unsigned char *q; |
int i; |
|
p = (unsigned char *) wrBuf; |
q = (unsigned char *) mbr; |
for (i = 0; i < SCT_SIZE; i++) { |
*p++ = *q++; |
} |
} |
|
|
int compareMBR(void) { |
unsigned char *p; |
unsigned char *q; |
int i; |
|
p = (unsigned char *) rdBuf; |
q = (unsigned char *) mbr; |
for (i = 0; i < SCT_SIZE; i++) { |
if (*p++ != *q++) { |
return 0; |
} |
} |
return 1; |
} |
|
|
void clearCtrl(void) { |
unsigned int *p; |
int i; |
|
p = (unsigned int *) DISK_BASE + DISK_BUF_STRT; |
for (i = 0; i < DISK_BUF_SIZE; i++) { |
*p++ = 0; |
} |
} |
|
|
void copyToCtrl(void) { |
unsigned int *p; |
unsigned int *q; |
int i; |
|
p = (unsigned int *) DISK_BASE + DISK_BUF_STRT; |
q = (unsigned int *) wrBuf; |
for (i = 0; i < SCT_SIZE / sizeof(unsigned int); i++) { |
*p++ = *q++; |
} |
} |
|
|
void copyFromCtrl(void) { |
unsigned int *p; |
unsigned int *q; |
int i; |
|
p = (unsigned int *) rdBuf; |
q = (unsigned int *) DISK_BASE + DISK_BUF_STRT; |
for (i = 0; i < SCT_SIZE / sizeof(unsigned int); i++) { |
*p++ = *q++; |
} |
} |
|
|
int checkDiskReady(void) { |
unsigned int *p; |
int tries; |
int i; |
|
p = (unsigned int *) DISK_BASE; |
for (tries = 0; tries < 10; tries++) { |
for (i = 0; i < 500000; i++) { |
if ((*(p + DISK_CTRL) & DISK_CTRL_RDY) != 0) { |
return 1; |
} |
} |
printf("."); |
} |
return 0; |
} |
|
|
void writeMBR(void) { |
unsigned int *p; |
|
p = (unsigned int *) DISK_BASE; |
*(p + DISK_CNT) = 1; |
*(p + DISK_SCT) = 0; |
*(p + DISK_CTRL) = DISK_CTRL_WRT | DISK_CTRL_STRT; |
while ((*(p + DISK_CTRL) & DISK_CTRL_DONE) == 0) ; |
} |
|
|
void readMBR(void) { |
unsigned int *p; |
|
p = (unsigned int *) DISK_BASE; |
*(p + DISK_CNT) = 1; |
*(p + DISK_SCT) = 0; |
*(p + DISK_CTRL) = DISK_CTRL_STRT; |
while ((*(p + DISK_CTRL) & DISK_CTRL_DONE) == 0) ; |
} |
|
|
void main(void) { |
initInterrupts(); |
printf("Checking disk ready..."); |
if (!checkDiskReady()) { |
printf(" disk not ready\n"); |
} else { |
printf(" ok\n"); |
printf("Writing MBR...\n"); |
copyMBR(); |
clearCtrl(); |
copyToCtrl(); |
writeMBR(); |
printf("Reading MBR...\n"); |
clearCtrl(); |
readMBR(); |
copyFromCtrl(); |
printf("Comparing MBR..."); |
if (!compareMBR()) { |
printf(" error\n"); |
} else { |
printf(" ok\n"); |
} |
} |
printf("Halting...\n"); |
} |
/stdalone/wrtmbr/end.s
0,0 → 1,19
; |
; end.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/wrtmbr/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/wrtmbr/Makefile
0,0 → 1,32
# |
# Makefile for "wrtmbr", a program to write a dummy MBR to the disk |
# |
|
BUILD = ../../build |
|
SRC = start.s main.c end.s |
BIN = wrtmbr.bin |
MAP = wrtmbr.map |
|
.PHONY: all install run clean |
|
all: $(BIN) |
|
install: $(BIN) |
mkdir -p $(BUILD)/stdalone |
cp $(BIN) $(BUILD)/stdalone |
cp $(MAP) $(BUILD)/stdalone |
|
run: $(BIN) |
$(BUILD)/bin/sim -i -t 1 -l $(BIN) -d $(BUILD)/disk/disk.img |
|
$(BIN): $(SRC) mbr/mbr.dump |
$(BUILD)/bin/lcc -A -Wo-kernel \ |
-Wl-m -Wl$(MAP) -o $(BIN) $(SRC) |
|
mbr/mbr.dump: |
$(MAKE) -C mbr |
|
clean: |
$(MAKE) -C mbr clean |
rm -f *~ $(BIN) $(MAP) |
/stdalone/wrtmbr/start.s
0,0 → 1,213
; |
; start.s -- startup code |
; |
|
.import main |
.import _ecode |
.import _edata |
.import _ebss |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export enable |
.export disable |
.export getISR |
.export setISR |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
|
; reset arrives here |
reset: |
j start |
|
; interrupts arrive here |
intrpt: |
j isr |
|
; user TLB misses arrive here |
userMiss: |
j userMiss |
|
isr: |
add $26,$29,$0 ; sp -> $26 |
add $27,$1,$0 ; $1 -> $27 |
add $29,$0,istack ; set stack |
sub $29,$29,108 |
stw $2,$29,0 ; save registers |
stw $3,$29,4 |
stw $4,$29,8 |
stw $5,$29,12 |
stw $6,$29,16 |
stw $7,$29,20 |
stw $8,$29,24 |
stw $9,$29,28 |
stw $10,$29,32 |
stw $11,$29,36 |
stw $12,$29,40 |
stw $13,$29,44 |
stw $14,$29,48 |
stw $15,$29,52 |
stw $16,$29,56 |
stw $17,$29,60 |
stw $18,$29,64 |
stw $19,$29,68 |
stw $20,$29,72 |
stw $21,$29,76 |
stw $22,$29,80 |
stw $23,$29,84 |
stw $24,$29,88 |
stw $25,$29,92 |
stw $26,$29,96 |
stw $27,$29,100 |
stw $31,$29,104 |
mvfs $4,0 ; $4 = IRQ number |
slr $4,$4,16 |
and $4,$4,0x1F |
sll $26,$4,2 ; $26 = 4 * IRQ number |
ldw $26,$26,irqsrv ; get addr of service routine |
jalr $26 ; call service routine |
beq $2,$0,resume ; resume instruction if ISR returned 0 |
add $30,$30,4 ; else skip offending instruction |
resume: |
ldw $2,$29,0 |
ldw $3,$29,4 |
ldw $4,$29,8 |
ldw $5,$29,12 |
ldw $6,$29,16 |
ldw $7,$29,20 |
ldw $8,$29,24 |
ldw $9,$29,28 |
ldw $10,$29,32 |
ldw $11,$29,36 |
ldw $12,$29,40 |
ldw $13,$29,44 |
ldw $14,$29,48 |
ldw $15,$29,52 |
ldw $16,$29,56 |
ldw $17,$29,60 |
ldw $18,$29,64 |
ldw $19,$29,68 |
ldw $20,$29,72 |
ldw $21,$29,76 |
ldw $22,$29,80 |
ldw $23,$29,84 |
ldw $24,$29,88 |
ldw $25,$29,92 |
ldw $26,$29,96 |
ldw $27,$29,100 |
ldw $31,$29,104 |
add $1,$27,$0 ; $27 -> $1 |
add $29,$26,0 ; $26 -> sp |
rfx ; return from exception |
|
start: |
mvfs $8,0 |
or $8,$8,1 << 27 ; let vector point to RAM |
mvts $8,0 |
add $29,$0,stack ; set sp |
add $10,$0,_bdata ; copy data segment |
add $8,$0,_edata |
sub $9,$8,$10 |
add $9,$9,_ecode |
j cpytest |
cpyloop: |
ldw $11,$9,0 |
stw $11,$8,0 |
cpytest: |
sub $8,$8,4 |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
add $8,$0,_bbss ; clear bss |
add $9,$0,_ebss |
j clrtest |
clrloop: |
stw $0,$8,0 |
add $8,$8,4 |
clrtest: |
bltu $8,$9,clrloop |
jal main ; call 'main' |
start1: |
j start1 ; loop |
|
enable: |
mvfs $8,0 |
or $8,$8,1 << 23 |
mvts $8,0 |
jr $31 |
|
disable: |
mvfs $8,0 |
and $8,$8,~(1 << 23) |
mvts $8,0 |
jr $31 |
|
getISR: |
sll $4,$4,2 |
ldw $2,$4,irqsrv |
jr $31 |
|
setISR: |
sll $4,$4,2 |
stw $5,$4,irqsrv |
jr $31 |
|
.data |
|
; interrupt service routine table |
|
.align 4 |
|
irqsrv: |
.word 0 ; 00: terminal 0 transmitter interrupt |
.word 0 ; 01: terminal 0 receiver interrupt |
.word 0 ; 02: terminal 1 transmitter interrupt |
.word 0 ; 03: terminal 1 receiver interrupt |
.word 0 ; 04: keyboard interrupt |
.word 0 ; 05: unused |
.word 0 ; 06: unused |
.word 0 ; 07: unused |
.word 0 ; 08: disk interrupt |
.word 0 ; 09: unused |
.word 0 ; 10: unused |
.word 0 ; 11: unused |
.word 0 ; 12: unused |
.word 0 ; 13: unused |
.word 0 ; 14: timer interrupt |
.word 0 ; 15: unused |
.word 0 ; 16: bus timeout exception |
.word 0 ; 17: illegal instruction exception |
.word 0 ; 18: privileged instruction exception |
.word 0 ; 19: divide instruction exception |
.word 0 ; 20: trap instruction exception |
.word 0 ; 21: TLB miss exception |
.word 0 ; 22: TLB write exception |
.word 0 ; 23: TLB invalid exception |
.word 0 ; 24: illegal address exception |
.word 0 ; 25: privileged address exception |
.word 0 ; 26: unused |
.word 0 ; 27: unused |
.word 0 ; 28: unused |
.word 0 ; 29: unused |
.word 0 ; 30: unused |
.word 0 ; 31: unused |
|
.bss |
|
.align 4 |
.space 0x800 |
stack: |
|
.align 4 |
.space 0x800 |
istack: |
/stdalone/Makefile
0,0 → 1,27
# |
# Makefile for building standalone test programs |
# (which are to be loaded from disk by a boot-loader) |
# |
|
BUILD = ../build |
|
DIRS = hello hello2 memsize onetask twotasks-1 twotasks-2 \ |
wrtmbr dskchk mkpart shpart |
|
.PHONY: all install clean |
|
all: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i all ; \ |
done |
|
install: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i install ; \ |
done |
|
clean: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i clean ; \ |
done |
rm -f *~ |
/stdalone/mkpart/iolib.c
0,0 → 1,329
/* |
* iolib.c -- I/O library |
*/ |
|
|
#include "types.h" |
#include "stdarg.h" |
#include "iolib.h" |
#include "biolib.h" |
|
|
/**************************************************************/ |
|
/* string functions */ |
|
|
int strlen(char *str) { |
int i; |
|
i = 0; |
while (*str++ != '\0') { |
i++; |
} |
return i; |
} |
|
|
void strcpy(char *dst, char *src) { |
while ((*dst++ = *src++) != '\0') ; |
} |
|
|
void memcpy(unsigned char *dst, unsigned char *src, unsigned int cnt) { |
while (cnt--) { |
*dst++ = *src++; |
} |
} |
|
|
/**************************************************************/ |
|
/* terminal I/O */ |
|
|
char getchar(void) { |
return getc(); |
} |
|
|
void putchar(char c) { |
if (c == '\n') { |
putchar('\r'); |
} |
putc(c); |
} |
|
|
void putString(char *s) { |
while (*s != '\0') { |
putchar(*s++); |
} |
} |
|
|
/**************************************************************/ |
|
/* get a line from the terminal */ |
|
|
void getLine(char *prompt, char *line, int max) { |
int index; |
char c; |
|
putString(prompt); |
putString(line); |
index = strlen(line); |
while (1) { |
c = getchar(); |
switch (c) { |
case '\r': |
putchar('\n'); |
line[index] = '\0'; |
return; |
case '\b': |
case 0x7F: |
if (index == 0) { |
break; |
} |
putchar('\b'); |
putchar(' '); |
putchar('\b'); |
index--; |
break; |
default: |
if (c == '\t') { |
c = ' '; |
} |
if (c < 0x20 || c > 0x7E) { |
break; |
} |
putchar(c); |
line[index++] = c; |
break; |
} |
} |
} |
|
|
/**************************************************************/ |
|
/* scaled-down version of printf */ |
|
|
/* |
* Count the number of characters needed to represent |
* a given number in base 10. |
*/ |
int countPrintn(long n) { |
long a; |
int res; |
|
res = 0; |
if (n < 0) { |
res++; |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
res += countPrintn(a); |
} |
return res + 1; |
} |
|
|
/* |
* Output a number in base 10. |
*/ |
void printn(long n) { |
long a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
/* |
* Count the number of characters needed to represent |
* a given number in a given base. |
*/ |
int countPrintu(unsigned long n, unsigned long b) { |
unsigned long a; |
int res; |
|
res = 0; |
a = n / b; |
if (a != 0) { |
res += countPrintu(a, b); |
} |
return res + 1; |
} |
|
|
/* |
* Output a number in a given base. |
*/ |
void printu(unsigned long n, unsigned long b, Bool upperCase) { |
unsigned long a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b, upperCase); |
} |
if (upperCase) { |
putchar("0123456789ABCDEF"[n % b]); |
} else { |
putchar("0123456789abcdef"[n % b]); |
} |
} |
|
|
/* |
* Output a number of filler characters. |
*/ |
void fill(int numFillers, char filler) { |
while (numFillers-- > 0) { |
putchar(filler); |
} |
} |
|
|
/* |
* Formatted output with a variable argument list. |
*/ |
void vprintf(char *fmt, va_list ap) { |
char c; |
int n; |
long ln; |
unsigned int u; |
unsigned long lu; |
char *s; |
Bool negFlag; |
char filler; |
int width, count; |
|
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == '-') { |
negFlag = TRUE; |
c = *fmt++; |
} else { |
negFlag = FALSE; |
} |
if (c == '0') { |
filler = '0'; |
c = *fmt++; |
} else { |
filler = ' '; |
} |
width = 0; |
while (c >= '0' && c <= '9') { |
width *= 10; |
width += c - '0'; |
c = *fmt++; |
} |
if (c == 'd') { |
n = va_arg(ap, int); |
count = countPrintn(n); |
if (width > 0 && !negFlag) { |
fill(width - count, filler); |
} |
printn(n); |
if (width > 0 && negFlag) { |
fill(width - count, filler); |
} |
} else |
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') { |
u = va_arg(ap, int); |
count = countPrintu(u, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10)); |
if (width > 0 && !negFlag) { |
fill(width - count, filler); |
} |
printu(u, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10), |
c == 'X'); |
if (width > 0 && negFlag) { |
fill(width - count, filler); |
} |
} else |
if (c == 'l') { |
c = *fmt++; |
if (c == 'd') { |
ln = va_arg(ap, long); |
count = countPrintn(ln); |
if (width > 0 && !negFlag) { |
fill(width - count, filler); |
} |
printn(ln); |
if (width > 0 && negFlag) { |
fill(width - count, filler); |
} |
} else |
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') { |
lu = va_arg(ap, long); |
count = countPrintu(lu, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10)); |
if (width > 0 && !negFlag) { |
fill(width - count, filler); |
} |
printu(lu, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10), |
c == 'X'); |
if (width > 0 && negFlag) { |
fill(width - count, filler); |
} |
} else { |
putchar('l'); |
putchar(c); |
} |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
count = strlen(s); |
if (width > 0 && !negFlag) { |
fill(width - count, filler); |
} |
while ((c = *s++) != '\0') { |
putchar(c); |
} |
if (width > 0 && negFlag) { |
fill(width - count, filler); |
} |
} else |
if (c == 'c') { |
c = va_arg(ap, char); |
putchar(c); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/* |
* Formatted output. |
* This is a scaled-down version of the C library's |
* printf. Used to print diagnostic information on |
* the console (and optionally to a logfile). |
*/ |
void printf(char *fmt, ...) { |
va_list ap; |
|
va_start(ap, fmt); |
vprintf(fmt, ap); |
va_end(ap); |
} |
/stdalone/mkpart/biolib.c
0,0 → 1,26
/* |
* biolib.c -- basic I/O library |
*/ |
|
|
#include "biolib.h" |
|
|
char getc(void) { |
unsigned int *base; |
char c; |
|
base = (unsigned int *) 0xF0300000; |
while ((*(base + 0) & 1) == 0) ; |
c = *(base + 1); |
return c; |
} |
|
|
void putc(char c) { |
unsigned int *base; |
|
base = (unsigned int *) 0xF0300000; |
while ((*(base + 2) & 1) == 0) ; |
*(base + 3) = c; |
} |
/stdalone/mkpart/start.h
0,0 → 1,21
/* |
* start.h -- startup code |
*/ |
|
|
#ifndef _START_H_ |
#define _START_H_ |
|
|
typedef int (*ISR)(int irq); |
|
|
void enable(void); |
void disable(void); |
int getMask(void); |
void setMask(int mask); |
ISR getISR(int irq); |
void setISR(int irq, ISR isr); |
|
|
#endif /* _START_H_ */ |
/stdalone/mkpart/iolib.h
0,0 → 1,21
/* |
* iolib.h -- I/O library |
*/ |
|
|
#ifndef _IOLIB_H_ |
#define _IOLIB_H_ |
|
|
int strlen(char *str); |
void strcpy(char *dst, char *src); |
void memcpy(unsigned char *dst, unsigned char *src, unsigned int cnt); |
char getchar(void); |
void putchar(char c); |
void putString(char *s); |
void getLine(char *prompt, char *line, int max); |
void vprintf(char *fmt, va_list ap); |
void printf(char *fmt, ...); |
|
|
#endif /* _IOLIB_H_ */ |
/stdalone/mkpart/dump/dump.c
0,0 → 1,48
/* |
* dump.c -- dump a binary file as contents of a C array |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
|
|
int main(int argc, char *argv[]) { |
FILE *infile, *outfile; |
int c, n; |
|
if (argc != 3) { |
printf("Usage: %s <infile> <outfile>\n", argv[0]); |
return 1; |
} |
infile = fopen(argv[1], "rb"); |
if (infile == NULL) { |
printf("Error: cannot open file '%s' for input\n", argv[1]); |
return 1; |
} |
outfile = fopen(argv[2], "wt"); |
if (outfile == NULL) { |
printf("Error: cannot open file '%s' for output\n", argv[2]); |
return 1; |
} |
n = 0; |
while (1) { |
c = getc(infile); |
if (c == EOF) { |
break; |
} |
fprintf(outfile, "0x%02X, ", c); |
n++; |
if (n == 8) { |
n = 0; |
fprintf(outfile, "\n"); |
} |
} |
if (n != 0) { |
fprintf(outfile, "\n"); |
} |
fclose(infile); |
fclose(outfile); |
return 0; |
} |
/stdalone/mkpart/dump/Makefile
0,0 → 1,15
# |
# Makefile for dump utility |
# |
|
.PHONY: all install clean |
|
all: dump |
|
install: dump |
|
dump: dump.c |
gcc -m32 -g -Wall -o dump dump.c |
|
clean: |
rm -f *~ dump |
/stdalone/mkpart/main.c
0,0 → 1,222
/* |
* main.c -- program to write the partition table |
* and the bootblock on a hard disk |
*/ |
|
|
#include "types.h" |
#include "stdarg.h" |
#include "iolib.h" |
#include "start.h" |
#include "idedsk.h" |
|
|
/**************************************************************/ |
|
|
void error(char *fmt, ...) { |
va_list ap; |
|
va_start(ap, fmt); |
printf("Error: "); |
vprintf(fmt, ap); |
printf(", halting...\n"); |
va_end(ap); |
while (1) ; |
} |
|
|
/**************************************************************/ |
|
|
/* |
* the boot block byte array need not be word-aligned |
*/ |
unsigned char mboot[32 * SECTOR_SIZE] = { |
#include "mboot.dump" |
}; |
|
|
/* |
* the write buffer must be word-aligned |
*/ |
unsigned int wrBuf[32 * SECTOR_SIZE / sizeof(unsigned int)]; |
|
|
/* |
* copy byte array to write buffer |
*/ |
void copyBootBlock(void) { |
unsigned char *p; |
unsigned char *q; |
int i; |
|
p = (unsigned char *) wrBuf; |
q = (unsigned char *) mboot; |
for (i = 0; i < 32 * SECTOR_SIZE; i++) { |
*p++ = *q++; |
} |
} |
|
|
/**************************************************************/ |
|
|
static char *exceptionCause[32] = { |
/* 00 */ "terminal 0 transmitter interrupt", |
/* 01 */ "terminal 0 receiver interrupt", |
/* 02 */ "terminal 1 transmitter interrupt", |
/* 03 */ "terminal 1 receiver interrupt", |
/* 04 */ "keyboard interrupt", |
/* 05 */ "unknown interrupt", |
/* 06 */ "unknown interrupt", |
/* 07 */ "unknown interrupt", |
/* 08 */ "disk interrupt", |
/* 09 */ "unknown interrupt", |
/* 10 */ "unknown interrupt", |
/* 11 */ "unknown interrupt", |
/* 12 */ "unknown interrupt", |
/* 13 */ "unknown interrupt", |
/* 14 */ "timer interrupt", |
/* 15 */ "unknown interrupt", |
/* 16 */ "bus timeout exception", |
/* 17 */ "illegal instruction exception", |
/* 18 */ "privileged instruction exception", |
/* 19 */ "divide instruction exception", |
/* 20 */ "trap instruction exception", |
/* 21 */ "TLB miss exception", |
/* 22 */ "TLB write exception", |
/* 23 */ "TLB invalid exception", |
/* 24 */ "illegal address exception", |
/* 25 */ "privileged address exception", |
/* 26 */ "unknown exception", |
/* 27 */ "unknown exception", |
/* 28 */ "unknown exception", |
/* 29 */ "unknown exception", |
/* 30 */ "unknown exception", |
/* 31 */ "unknown exception" |
}; |
|
|
int defaultISR(int irq) { |
printf("\n%s\n", exceptionCause[irq]); |
return 0; /* do not skip any instruction */ |
} |
|
|
void initInterrupts(void) { |
int i; |
|
for (i = 0; i < 32; i++) { |
setISR(i, defaultISR); |
} |
} |
|
|
/**************************************************************/ |
|
|
Bool checkDiskReady(void) { |
int tries; |
int i; |
|
for (tries = 0; tries < 10; tries++) { |
for (i = 0; i < 500000; i++) { |
if ((*DISK_CTRL & DISK_CTRL_READY) != 0) { |
return TRUE; |
} |
} |
printf("."); |
} |
return FALSE; |
} |
|
|
unsigned long getDiskSize(void) { |
return *DISK_CAP; |
} |
|
|
Bool readDisk(unsigned long sector, |
unsigned int count, |
unsigned int *addr) { |
unsigned int n; |
unsigned int *p; |
unsigned int i; |
|
while (count != 0) { |
n = count > 8 ? 8 : count; |
*DISK_SCT = sector; |
*DISK_CNT = n; |
*DISK_CTRL = DISK_CTRL_STRT; |
while ((*DISK_CTRL & DISK_CTRL_DONE) == 0) ; |
if (*DISK_CTRL & DISK_CTRL_ERR) { |
return FALSE; |
} |
p = DISK_BUFFER; |
for (i = 0; i < n * SECTOR_SIZE / sizeof(unsigned int); i++) { |
*addr++ = *p++; |
} |
sector += n; |
count -= n; |
} |
return TRUE; |
} |
|
|
Bool writeDisk(unsigned long sector, |
unsigned int count, |
unsigned int *addr) { |
unsigned int n; |
unsigned int *p; |
unsigned int i; |
|
while (count != 0) { |
n = count > 8 ? 8 : count; |
p = DISK_BUFFER; |
for (i = 0; i < n * SECTOR_SIZE / sizeof(unsigned int); i++) { |
*p++ = *addr++; |
} |
*DISK_SCT = sector; |
*DISK_CNT = n; |
*DISK_CTRL = DISK_CTRL_WRT | DISK_CTRL_STRT; |
while ((*DISK_CTRL & DISK_CTRL_DONE) == 0) ; |
if (*DISK_CTRL & DISK_CTRL_ERR) { |
return FALSE; |
} |
sector += n; |
count -= n; |
} |
return TRUE; |
} |
|
|
/**************************************************************/ |
|
|
void main(void) { |
unsigned long numSectors; |
|
/* init interrupts */ |
initInterrupts(); |
/* check disk ready */ |
if (!checkDiskReady()) { |
error("disk not ready"); |
} |
/* determine disk size */ |
numSectors = getDiskSize(); |
printf("Disk has %lu (0x%lX) sectors.\n", |
numSectors, numSectors); |
if (numSectors < 32) { |
error("disk is too small"); |
} |
/* copy boot block to write buffer */ |
copyBootBlock(); |
/* write boot block to disk */ |
printf("Writing boot block to disk...\n"); |
if (!writeDisk(0, 32, wrBuf)) { |
error("cannot write boot block to disk"); |
} |
/* done */ |
printf("Halting...\n"); |
} |
/stdalone/mkpart/biolib.h
0,0 → 1,14
/* |
* biolib.h -- basic I/O library |
*/ |
|
|
#ifndef _BIOLIB_H_ |
#define _BIOLIB_H_ |
|
|
char getc(void); |
void putc(char c); |
|
|
#endif /* _BIOLIB_H_ */ |
/stdalone/mkpart/end.s
0,0 → 1,19
; |
; end.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/mkpart/mkmboot/stage1/mbr.s
0,0 → 1,127
; |
; mbr.s -- the master boot record |
; |
|
; Runtime environment: |
; |
; This code must be loaded and started at 0xC0000000. |
; It allocates a stack from 0xC0001000 downwards. So |
; it must run within 4K (code + data + stack). |
; |
; This code expects the disk number of the boot disk |
; in $16, the start sector of the disk or partition |
; to be booted in $17 and its size in $18. |
; |
; The boot manager, which is loaded by this code, |
; must be in standalone (headerless) executable |
; format, stored at absolute disk sectors 2..31, |
; and gets loaded and started at 0xC00F0000. |
|
.set stacktop,0xC0001000 ; top of stack |
.set loadaddr,0xC00F0000 ; where to load the boot manager |
|
.set cout,0xE0000018 ; ROM console output |
.set dskio,0xE0000030 ; ROM disk I/O |
|
; reset arrives here |
reset: |
j start |
|
; interrupts arrive here |
intrpt: |
j userMiss |
|
; user TLB misses arrive here |
userMiss: |
add $4,$0,intmsg ; we do not expect any interrupt |
jal msgout |
j halt |
|
; load the boot manager and start it |
start: |
add $29,$0,stacktop ; setup stack |
add $4,$0,strtmsg ; say what is going on |
jal msgout |
add $4,$0,2 ; start loading with sector 2 |
add $5,$0,loadaddr ; where to load the boot manager |
and $5,$5,0x3FFFFFFF ; convert to physical address |
add $6,$0,30 ; 30 sectors to load |
jal rdsct |
add $8,$0,loadaddr ; start executing the boot manager |
jr $8 |
|
; read disk sectors |
; $4 start sector number (disk or partition relative) |
; $5 transfer address |
; $6 number of sectors |
rdsct: |
sub $29,$29,32 |
stw $31,$29,20 |
stw $6,$29,16 ; sector count |
add $7,$5,$0 ; transfer address |
add $6,$4,$17 ; relative sector -> absolute |
add $5,$0,'r' ; command |
add $4,$0,$16 ; disk number |
add $8,$0,dskio |
jalr $8 |
bne $2,$0,rderr ; error? |
ldw $31,$29,20 |
add $29,$29,32 |
jr $31 |
|
; disk read error |
rderr: |
add $4,$0,dremsg |
jal msgout |
j halt |
|
; output message |
; $4 pointer to string |
msgout: |
sub $29,$29,8 |
stw $31,$29,4 |
stw $16,$29,0 |
add $16,$4,0 ; $16: pointer to string |
msgout1: |
ldbu $4,$16,0 ; get character |
beq $4,$0,msgout2 ; done? |
jal chrout ; output character |
add $16,$16,1 ; bump pointer |
j msgout1 ; continue |
msgout2: |
ldw $16,$29,0 |
ldw $31,$29,4 |
add $29,$29,8 |
jr $31 |
|
; output character |
; $4 character |
chrout: |
sub $29,$29,4 |
stw $31,$29,0 |
add $8,$0,cout |
jalr $8 |
ldw $31,$29,0 |
add $29,$29,4 |
jr $31 |
|
; halt execution by looping |
halt: |
add $4,$0,hltmsg |
jal msgout |
halt1: |
j halt1 |
|
; messages |
intmsg: |
.byte "unexpected interrupt", 0x0D, 0x0A, 0 |
strtmsg: |
.byte "MBR executing...", 0x0D, 0x0A, 0 |
dremsg: |
.byte "disk read error", 0x0D, 0x0A, 0 |
hltmsg: |
.byte "bootstrap halted", 0x0D, 0x0A, 0 |
|
; boot record signature |
.locate 512-2 |
.byte 0x55, 0xAA |
/stdalone/mkpart/mkmboot/stage1/Makefile
0,0 → 1,16
# |
# Makefile to build the master boot record |
# |
|
BUILD = ../../../../build |
|
all: mbr.bin |
|
mbr.bin: mbr.o |
$(BUILD)/bin/ld -h -rc 0xC0000000 -o mbr.bin mbr.o |
|
mbr.o: mbr.s |
$(BUILD)/bin/as -o mbr.o mbr.s |
|
clean: |
rm -f *~ mbr.o mbr.bin |
/stdalone/mkpart/mkmboot/stage2/iolib.s
0,0 → 1,26
; |
; iolib.s -- a very small library of I/O routines |
; |
|
.set cin,0xE0000010 |
.set cout,0xE0000018 |
.set dskio,0xE0000030 |
|
.export getc |
.export putc |
.export rwscts |
|
.code |
.align 4 |
|
getc: |
add $8,$0,cin |
jr $8 |
|
putc: |
add $8,$0,cout |
jr $8 |
|
rwscts: |
add $8,$0,dskio |
jr $8 |
/stdalone/mkpart/mkmboot/stage2/c0.s
0,0 → 1,58
; |
; c0.s -- startup code and begin-of-segment labels |
; |
|
.import main |
|
.import _ecode |
.import _edata |
.import _ebss |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.import bootDisk |
.import startSector |
.import numSectors |
|
.code |
_bcode: |
|
start: |
add $10,$0,_bdata ; copy data segment |
add $8,$0,_edata |
sub $9,$8,$10 |
add $9,$9,_ecode |
j cpytest |
cpyloop: |
ldw $11,$9,0 |
stw $11,$8,0 |
cpytest: |
sub $8,$8,4 |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
add $8,$0,_bbss ; clear bss segment |
add $9,$0,_ebss |
j clrtest |
clrloop: |
stw $0,$8,0 |
add $8,$8,4 |
clrtest: |
bltu $8,$9,clrloop |
add $29,$0,0xC0100000 ; setup stack |
stw $16,$0,bootDisk ; make arguments available |
stw $17,$0,startSector |
stw $18,$0,numSectors |
jal main ; call 'main' function |
ldw $16,$0,bootDisk ; setup arguments for next stage |
ldw $17,$0,startSector |
ldw $18,$0,numSectors |
add $31,$0,0xC0000000 ; jump to loaded program |
jr $31 |
|
.data |
_bdata: |
|
.bss |
_bbss: |
/stdalone/mkpart/mkmboot/stage2/c1.s
0,0 → 1,19
; |
; c1.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/mkpart/mkmboot/stage2/boot.c
0,0 → 1,267
/* |
* boot.c -- second stage bootstrap (the boot manager) |
*/ |
|
|
#include "stdarg.h" |
#include "iolib.h" |
|
|
#define DEFAULT_PARTITION "0" /* default boot partition number */ |
|
#define LINE_SIZE 80 |
#define SECTOR_SIZE 512 |
#define NPE (SECTOR_SIZE / sizeof(PartEntry)) |
#define DESCR_SIZE 20 |
|
|
unsigned int bootDisk = 0; /* gets loaded by previous stage */ |
unsigned int startSector = 0; /* gets loaded by previous stage */ |
unsigned int numSectors = 0; /* gets loaded by previous stage */ |
|
|
typedef struct { |
unsigned long type; |
unsigned long start; |
unsigned long size; |
char descr[DESCR_SIZE]; |
} PartEntry; |
|
PartEntry ptr[NPE]; |
|
|
int strlen(char *str) { |
int i; |
|
i = 0; |
while (*str++ != '\0') { |
i++; |
} |
return i; |
} |
|
|
void strcpy(char *dst, char *src) { |
while ((*dst++ = *src++) != '\0') ; |
} |
|
|
char getchar(void) { |
return getc(); |
} |
|
|
void putchar(char c) { |
if (c == '\n') { |
putchar('\r'); |
} |
putc(c); |
} |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void getline(char *prompt, char *line, int n) { |
int i; |
char c; |
|
puts(prompt); |
puts(line); |
i = strlen(line); |
while (i < n - 1) { |
c = getchar(); |
if (c >= ' ' && c < 0x7F) { |
putchar(c); |
line[i] = c; |
i++; |
} else |
if (c == '\r') { |
putchar('\n'); |
line[i] = '\0'; |
i = n - 1; |
} else |
if (c == '\b' || c == 0x7F) { |
if (i > 0) { |
putchar('\b'); |
putchar(' '); |
putchar('\b'); |
i--; |
} |
} |
} |
line[n - 1] = '\0'; |
} |
|
|
int countPrintn(long n) { |
long a; |
int res; |
|
res = 0; |
if (n < 0) { |
res++; |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
res += countPrintn(a); |
} |
return res + 1; |
} |
|
|
void printn(long n) { |
long a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
char filler; |
int width, count, i; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == '0') { |
filler = '0'; |
c = *fmt++; |
} else { |
filler = ' '; |
} |
width = 0; |
if (c >= '0' && c <= '9') { |
width = c - '0'; |
c = *fmt++; |
} |
if (c == 'd') { |
n = va_arg(ap, int); |
if (width > 0) { |
count = countPrintn(n); |
for (i = 0; i < width - count; i++) { |
putchar(filler); |
} |
} |
printn(n); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else |
if (c == 'c') { |
c = va_arg(ap, char); |
putchar(c); |
} else { |
putchar(c); |
} |
} |
} |
|
|
void halt(void) { |
printf("bootstrap halted\n"); |
while (1) ; |
} |
|
|
void readDisk(unsigned int sector, unsigned char *buffer, int count) { |
int result; |
|
if (sector + count > numSectors) { |
printf("sector number exceeds disk or partition size\n"); |
halt(); |
} |
result = rwscts(bootDisk, 'r', sector + startSector, |
(unsigned int) buffer & 0x3FFFFFFF, count); |
if (result != 0) { |
printf("disk read error\n"); |
halt(); |
} |
} |
|
|
int main(void) { |
int i; |
char line[LINE_SIZE]; |
char *p; |
int part; |
|
printf("Bootstrap manager executing...\n"); |
strcpy(line, DEFAULT_PARTITION); |
readDisk(1, (unsigned char *) ptr, 1); |
while (1) { |
printf("\nPartitions:\n"); |
printf(" # | b | description\n"); |
printf("---+---+----------------------\n"); |
for (i = 0; i < NPE; i++) { |
if (ptr[i].type != 0) { |
printf("%2d | %s | %s\n", |
i, ptr[i].type & 0x80000000 ? "*" : " ", ptr[i].descr); |
} |
} |
getline("\nBoot #: ", line, LINE_SIZE); |
part = 0; |
if (line[0] == '\0') { |
continue; |
} |
p = line; |
while (*p >= '0' && *p <= '9') { |
part = part * 10 + (*p - '0'); |
p++; |
} |
if (*p != '\0' || part < 0 || part > 15) { |
printf("illegal partition number\n"); |
continue; |
} |
if ((ptr[part].type & 0x7FFFFFFF) == 0) { |
printf("partition %d does not contain a file system\n", part); |
continue; |
} |
if ((ptr[part].type & 0x80000000) == 0) { |
printf("partition %d is not bootable\n", part); |
continue; |
} |
/* load boot sector of selected partition */ |
readDisk(ptr[part].start, (unsigned char *) 0xC0000000, 1); |
/* check for signature */ |
if ((*((unsigned char *) 0xC0000000 + SECTOR_SIZE - 2) != 0x55) || |
(*((unsigned char *) 0xC0000000 + SECTOR_SIZE - 1) != 0xAA)) { |
printf("boot sector of partition %d has no signature\n", part); |
continue; |
} |
/* we have a valid boot sector, leave loop */ |
break; |
} |
/* boot manager finished, now go executing loaded boot sector */ |
startSector = ptr[part].start; |
numSectors = ptr[part].size; |
return 0; |
} |
/stdalone/mkpart/mkmboot/stage2/iolib.h
0,0 → 1,15
/* |
* iolib.h -- a very small library of I/O routines |
*/ |
|
|
#ifndef _IOLIB_H_ |
#define _IOLIB_H_ |
|
|
char getc(void); |
void putc(char c); |
int rwscts(int dskno, int cmd, int sector, int addr, int count); |
|
|
#endif /* _IOLIB_H_ */ |
/stdalone/mkpart/mkmboot/stage2/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/mkpart/mkmboot/stage2/Makefile
0,0 → 1,26
# |
# Makefile to build the boot manager |
# |
|
BUILD = ../../../../build |
|
all: boot.bin |
|
boot.bin: c0.o boot.o iolib.o c1.o |
$(BUILD)/bin/ld -h -rc 0xC00F0000 -o boot.bin \ |
c0.o boot.o iolib.o c1.o |
|
c0.o: c0.s |
$(BUILD)/bin/as -o c0.o c0.s |
|
boot.o: boot.c |
$(BUILD)/bin/lcc -A -c -o boot.o boot.c |
|
iolib.o: iolib.s |
$(BUILD)/bin/as -o iolib.o iolib.s |
|
c1.o: c1.s |
$(BUILD)/bin/as -o c1.o c1.s |
|
clean: |
rm -f *~ c0.o boot.o iolib.o c1.o boot.bin |
/stdalone/mkpart/mkmboot/Makefile
0,0 → 1,24
# |
# Makefile to build the master boot block (with an empty partition table) |
# |
|
BUILD = ../../../build |
|
.PHONY: all clean |
|
all: mbootblk |
|
mbootblk: stage1/mbr.bin stage2/boot.bin |
dd if=/dev/zero of=./zeroes bs=512 count=1 |
cat stage1/mbr.bin zeroes stage2/boot.bin >mbootblk |
|
stage1/mbr.bin: |
$(MAKE) -C stage1 |
|
stage2/boot.bin: |
$(MAKE) -C stage2 |
|
clean: |
$(MAKE) -C stage1 clean |
$(MAKE) -C stage2 clean |
rm -f *~ zeroes mbootblk |
/stdalone/mkpart/mkptbl/disk.part
0,0 → 1,41
# |
# disk.part -- disk partitioning configuration file |
# |
|
# This file consists of partition table entries, one per line |
# (empty or comment lines are also allowed). Each entry is in |
# the following form: |
# |
# partition boot type start last description |
# |
# partition: |
# possible values 0..15 |
# indicates partition number |
# different entries need not be sorted in any way |
# no two entries may have the same partition number |
# boot: |
# '*' means that the partition can be booted |
# leave this blank if the partition cannot be booted |
# more than one partition may be bootable |
# type: |
# possible values 0..0x7FFFFFFF |
# indicates partition type |
# 0x0000 = partition table entry not used |
# 0x0058 = EOS32 file system partition |
# 0x0059 = EOS32 swap space partition |
# 0x00A9 = NetBSD partition |
# start: |
# sector number where partition starts (0-based) |
# no partition may start below sector 32 |
# last: |
# last sector of partition (0-based) |
# partitions must not overlap |
# description: |
# max. 512 / 16 - 12 = 20 characters (includes trailing 0) |
# this may be displayed during bootstrap |
|
0 * 0x0058 32 131071 "EOS32 root" |
1 0x0058 131072 393215 "EOS32 usr" |
2 0x0059 393216 524287 "EOS32 swap" |
3 0x0058 524288 1048575 "EOS32 home" |
4 * 0x00A9 2097152 33554431 "NetBSD 6.0" |
/stdalone/mkpart/mkptbl/mkptbl.c
0,0 → 1,275
/* |
* mkptbl.c -- make partition table |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <stdarg.h> |
|
|
#define SECTOR_SIZE 512 |
#define NPE (SECTOR_SIZE / sizeof(PartEntry)) |
#define DESCR_SIZE 20 |
|
#define LINE_SIZE 100 |
|
|
typedef struct { |
unsigned long type; |
unsigned long start; |
unsigned long size; |
char descr[DESCR_SIZE]; |
} PartEntry; |
|
PartEntry ptr[NPE]; |
|
|
void error(char *fmt, ...) { |
va_list ap; |
|
va_start(ap, fmt); |
printf("Error: "); |
vprintf(fmt, ap); |
printf("\n"); |
va_end(ap); |
exit(1); |
} |
|
|
void convertNumber(unsigned char *p, unsigned long val) { |
*(p + 0) = val >> 24; |
*(p + 1) = val >> 16; |
*(p + 2) = val >> 8; |
*(p + 3) = val >> 0; |
} |
|
|
void convertPartitionTable(PartEntry *e, int n) { |
int i; |
unsigned char *p; |
|
for (i = 0; i < n; i++) { |
p = (unsigned char *) &e[i]; |
convertNumber(p + 0, e[i].type); |
convertNumber(p + 4, e[i].start); |
convertNumber(p + 8, e[i].size); |
} |
} |
|
|
int parseNumber(char **pc, unsigned long *pi) { |
char *p; |
unsigned int base, dval; |
unsigned long n; |
|
p = *pc; |
while (*p == ' ' || *p == '\t') { |
p++; |
} |
if (*p == '\0' || *p == '\n') { |
printf("Error: number is missing!\n"); |
return 0; |
} |
base = 10; |
if (*p == '0') { |
p++; |
if (*p != '\0' && *p != '\n') { |
if (*p == 'x' || *p == 'X') { |
base = 16; |
p++; |
} else { |
base = 8; |
} |
} |
} |
n = 0; |
while ((*p >= '0' && *p <= '9') || |
(*p >= 'a' && *p <= 'f') || |
(*p >= 'A' && *p <= 'F')) { |
if (*p >= '0' && *p <= '9') { |
dval = (*p - '0'); |
} else |
if (*p >= 'a' && *p <= 'f') { |
dval = (*p - 'a' + 10); |
} else |
if (*p >= 'A' && *p <= 'F') { |
dval = (*p - 'A' + 10); |
} |
if (dval >= base) { |
printf("Error: digit value %d is illegal in number base %d\n", |
dval, base); |
return 0; |
} |
n *= base; |
n += dval; |
p++; |
} |
while (*p == ' ' || *p == '\t') { |
p++; |
} |
*pc = p; |
*pi = n; |
return 1; |
} |
|
|
int parseString(char **pc, char *dst) { |
char *p; |
|
p = *pc; |
while (*p == ' ' || *p == '\t') { |
p++; |
} |
if (*p != '\"') { |
return 0; |
} |
p++; |
while (*p != '\"' && *p != '\0' && *p != '\n') { |
*dst++ = *p++; |
} |
if (*p != '\"') { |
return 0; |
} |
p++; |
while (*p == ' ' || *p == '\t') { |
p++; |
} |
*pc = p; |
*dst = '\0'; |
return 1; |
} |
|
|
int main(int argc, char *argv[]) { |
char *confName; |
char *outName; |
FILE *conf; |
FILE *out; |
char line[LINE_SIZE]; |
char *p; |
int lineNumber; |
unsigned long partNum; |
unsigned long bootable; |
unsigned long partType; |
unsigned long partStart; |
unsigned long partLast; |
unsigned long partSize; |
char descr[LINE_SIZE]; |
|
/* check command line arguments */ |
if (argc != 3) { |
printf("Usage: %s <configuration file> <output file>\n", argv[0]); |
exit(1); |
} |
confName = argv[1]; |
outName = argv[2]; |
/* create partition table */ |
conf = fopen(confName, "rt"); |
if (conf == NULL) { |
error("cannot open configuration file '%s'", confName); |
} |
lineNumber = 0; |
/* handle partition table entries */ |
while (fgets(line, LINE_SIZE, conf) != NULL) { |
lineNumber++; |
p = line; |
while (*p == ' ' || *p == '\t') { |
p++; |
} |
if (*p == '\0' || *p == '\n' || *p == '#') { |
continue; |
} |
if (!parseNumber(&p, &partNum)) { |
error("cannot read partition number in config file '%s', line %d", |
confName, lineNumber); |
} |
if (partNum >= 16) { |
error("illegal partition number in config file '%s', line %d", |
confName, lineNumber); |
} |
if (*p == '*') { |
p++; |
bootable = 0x80000000; |
} else { |
bootable = 0x00000000; |
} |
if (!parseNumber(&p, &partType)) { |
error("cannot read partition type in config file '%s', line %d", |
confName, lineNumber); |
} |
if ((partType & 0x80000000) != 0) { |
error("illegal partition type in config file '%s', line %d", |
confName, lineNumber); |
} |
if (!parseNumber(&p, &partStart)) { |
error("cannot read start sector in config file '%s', line %d", |
confName, lineNumber); |
} |
if (partStart < 32) { |
error("illegal start sector in config file '%s', line %d", |
confName, lineNumber); |
} |
if (!parseNumber(&p, &partLast)) { |
error("cannot read last sector in config file '%s', line %d", |
confName, lineNumber); |
} |
if (partLast < partStart) { |
error("illegal last sector in config file '%s', line %d", |
confName, lineNumber); |
} |
partSize = partLast - partStart + 1; |
if (!parseString(&p, descr)) { |
error("cannot read description in config file '%s', line %d", |
confName, lineNumber); |
} |
if (strlen(descr) >= DESCR_SIZE) { |
error("description too long in config file '%s', line %d", |
confName, lineNumber); |
} |
if (partType != 0) { |
ptr[partNum].type = bootable | partType; |
ptr[partNum].start = partStart; |
ptr[partNum].size = partSize; |
memset(ptr[partNum].descr, 0, DESCR_SIZE); |
strcpy(ptr[partNum].descr, descr); |
} else { |
ptr[partNum].type = 0; |
ptr[partNum].start = 0; |
ptr[partNum].size = 0; |
memset(ptr[partNum].descr, 0, DESCR_SIZE); |
} |
} |
fclose(conf); |
/* next, show partition table */ |
printf("Partitions:\n"); |
printf(" # b type start last size description\n"); |
for (partNum = 0; partNum < NPE; partNum++) { |
if (ptr[partNum].type != 0) { |
partLast = ptr[partNum].start + ptr[partNum].size - 1; |
} else { |
partLast = 0; |
} |
printf("%2lu %s 0x%08lX 0x%08lX 0x%08lX 0x%08lX %s\n", |
partNum, |
ptr[partNum].type & 0x80000000 ? "*" : " ", |
ptr[partNum].type & 0x7FFFFFFF, |
ptr[partNum].start, |
partLast, |
ptr[partNum].size, |
ptr[partNum].descr); |
} |
/* finally, write partition table to output file */ |
convertPartitionTable(ptr, NPE); |
out = fopen(outName, "wb"); |
if (out == NULL) { |
error("cannot open output file '%s'", outName); |
} |
if (fwrite(ptr, 1, SECTOR_SIZE, out) != SECTOR_SIZE) { |
error("cannot write partition table to output file '%s'", outName); |
} |
fclose(out); |
/* done */ |
return 0; |
} |
/stdalone/mkpart/mkptbl/Makefile
0,0 → 1,14
# |
# Makefile for generating a partition table |
# |
|
all: parttbl |
|
parttbl: mkptbl disk.part |
./mkptbl disk.part parttbl |
|
mkptbl: mkptbl.c |
gcc -m32 -g -Wall -o mkptbl mkptbl.c |
|
clean: |
rm -f *~ mkptbl parttbl |
/stdalone/mkpart/idedsk.h
0,0 → 1,32
/* |
* idedsk.h -- IDE disk definitions |
*/ |
|
|
#ifndef _IDEDSK_H_ |
#define _IDEDSK_H_ |
|
|
#define SECTOR_SIZE 512 |
#define WPS (SECTOR_SIZE / sizeof(unsigned int)) |
|
#define DISK_BASE ((unsigned *) 0xF0400000) /* disk base address */ |
#define DISK_CTRL (DISK_BASE + 0) /* control/status register */ |
#define DISK_CNT (DISK_BASE + 1) /* sector count register */ |
#define DISK_SCT (DISK_BASE + 2) /* disk sector register */ |
#define DISK_CAP (DISK_BASE + 3) /* disk capacity register */ |
#define DISK_BUFFER ((unsigned *) 0xF0480000) /* address of disk buffer */ |
|
#define DISK_CTRL_STRT 0x01 /* a 1 written here starts the disk command */ |
#define DISK_CTRL_IEN 0x02 /* enable disk interrupt */ |
#define DISK_CTRL_WRT 0x04 /* command type: 0 = read, 1 = write */ |
#define DISK_CTRL_ERR 0x08 /* 0 = ok, 1 = error; valid when DONE = 1 */ |
#define DISK_CTRL_DONE 0x10 /* 1 = disk has finished the command */ |
#define DISK_CTRL_READY 0x20 /* 1 = capacity valid, disk accepts command */ |
|
#define DISK_IRQ 8 /* disk interrupt number */ |
|
#define READY_RETRIES 1000000 /* retries to wait for disk to get ready */ |
|
|
#endif /* _IDEDSK_H_ */ |
/stdalone/mkpart/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/mkpart/types.h
0,0 → 1,16
/* |
* types.h -- additional types |
*/ |
|
|
#ifndef _TYPES_H_ |
#define _TYPES_H_ |
|
|
typedef int Bool; |
|
#define FALSE 0 |
#define TRUE 1 |
|
|
#endif /* _TYPES_H_ */ |
/stdalone/mkpart/Makefile
0,0 → 1,49
# |
# Makefile for "mkpart", a program to write the partition table |
# and the bootblock on a hard disk |
# |
|
BUILD = ../../build |
|
SRC = start.s main.c iolib.c biolib.c end.s |
BIN = mkpart.bin |
MAP = mkpart.map |
|
.PHONY: all install run clean |
|
all: $(BIN) |
|
install: $(BIN) |
mkdir -p $(BUILD)/stdalone |
cp $(BIN) $(BUILD)/stdalone |
cp $(MAP) $(BUILD)/stdalone |
|
run: $(BIN) |
$(BUILD)/bin/sim -i -t 1 -l $(BIN) -d $(BUILD)/disk/disk.img |
|
$(BIN): $(SRC) mboot.dump |
$(BUILD)/bin/lcc -A -Wo-kernel \ |
-Wl-m -Wl$(MAP) -o $(BIN) $(SRC) |
|
mboot.dump: dump/dump mboot |
./dump/dump mboot mboot.dump |
|
dump/dump: |
$(MAKE) -C dump all |
|
mboot: mkmboot/mbootblk mkptbl/parttbl |
dd if=/dev/zero of=mboot bs=512 count=32 |
dd if=mkmboot/mbootblk of=mboot bs=512 conv=notrunc |
dd if=mkptbl/parttbl of=mboot bs=512 seek=1 conv=notrunc |
|
mkptbl/parttbl: |
$(MAKE) -C mkptbl all |
|
mkmboot/mbootblk: |
$(MAKE) -C mkmboot all |
|
clean: |
$(MAKE) -C dump clean |
$(MAKE) -C mkptbl clean |
$(MAKE) -C mkmboot clean |
rm -f *~ mboot mboot.dump $(BIN) $(MAP) |
/stdalone/mkpart/start.s
0,0 → 1,228
; |
; start.s -- startup code |
; |
|
.import main |
.import _ecode |
.import _edata |
.import _ebss |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export enable |
.export disable |
.export getMask |
.export setMask |
.export getISR |
.export setISR |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
|
; reset arrives here |
reset: |
j start |
|
; interrupts arrive here |
intrpt: |
j isr |
|
; user TLB misses arrive here |
userMiss: |
j userMiss |
|
isr: |
add $26,$29,$0 ; sp -> $26 |
add $27,$1,$0 ; $1 -> $27 |
add $29,$0,istack ; set stack |
sub $29,$29,108 |
stw $2,$29,0 ; save registers |
stw $3,$29,4 |
stw $4,$29,8 |
stw $5,$29,12 |
stw $6,$29,16 |
stw $7,$29,20 |
stw $8,$29,24 |
stw $9,$29,28 |
stw $10,$29,32 |
stw $11,$29,36 |
stw $12,$29,40 |
stw $13,$29,44 |
stw $14,$29,48 |
stw $15,$29,52 |
stw $16,$29,56 |
stw $17,$29,60 |
stw $18,$29,64 |
stw $19,$29,68 |
stw $20,$29,72 |
stw $21,$29,76 |
stw $22,$29,80 |
stw $23,$29,84 |
stw $24,$29,88 |
stw $25,$29,92 |
stw $26,$29,96 |
stw $27,$29,100 |
stw $31,$29,104 |
mvfs $4,0 ; $4 = IRQ number |
slr $4,$4,16 |
and $4,$4,0x1F |
sll $26,$4,2 ; $26 = 4 * IRQ number |
ldw $26,$26,irqsrv ; get addr of service routine |
jalr $26 ; call service routine |
beq $2,$0,resume ; resume instruction if ISR returned 0 |
add $30,$30,4 ; else skip offending instruction |
resume: |
ldw $2,$29,0 |
ldw $3,$29,4 |
ldw $4,$29,8 |
ldw $5,$29,12 |
ldw $6,$29,16 |
ldw $7,$29,20 |
ldw $8,$29,24 |
ldw $9,$29,28 |
ldw $10,$29,32 |
ldw $11,$29,36 |
ldw $12,$29,40 |
ldw $13,$29,44 |
ldw $14,$29,48 |
ldw $15,$29,52 |
ldw $16,$29,56 |
ldw $17,$29,60 |
ldw $18,$29,64 |
ldw $19,$29,68 |
ldw $20,$29,72 |
ldw $21,$29,76 |
ldw $22,$29,80 |
ldw $23,$29,84 |
ldw $24,$29,88 |
ldw $25,$29,92 |
ldw $26,$29,96 |
ldw $27,$29,100 |
ldw $31,$29,104 |
add $1,$27,$0 ; $27 -> $1 |
add $29,$26,0 ; $26 -> sp |
rfx ; return from exception |
|
start: |
mvfs $8,0 |
or $8,$8,1 << 27 ; let vector point to RAM |
mvts $8,0 |
add $29,$0,stack ; set sp |
add $10,$0,_bdata ; copy data segment |
add $8,$0,_edata |
sub $9,$8,$10 |
add $9,$9,_ecode |
j cpytest |
cpyloop: |
ldw $11,$9,0 |
stw $11,$8,0 |
cpytest: |
sub $8,$8,4 |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
add $8,$0,_bbss ; clear bss |
add $9,$0,_ebss |
j clrtest |
clrloop: |
stw $0,$8,0 |
add $8,$8,4 |
clrtest: |
bltu $8,$9,clrloop |
jal main ; call 'main' |
start1: |
j start1 ; loop |
|
enable: |
mvfs $8,0 |
or $8,$8,1 << 23 |
mvts $8,0 |
jr $31 |
|
disable: |
mvfs $8,0 |
and $8,$8,~(1 << 23) |
mvts $8,0 |
jr $31 |
|
getMask: |
mvfs $8,0 |
and $2,$8,0x0000FFFF |
jr $31 |
|
setMask: |
mvfs $8,0 |
and $8,$8,0xFFFF0000 |
and $4,$4,0x0000FFFF |
or $8,$8,$4 |
mvts $8,0 |
jr $31 |
|
getISR: |
sll $4,$4,2 |
ldw $2,$4,irqsrv |
jr $31 |
|
setISR: |
sll $4,$4,2 |
stw $5,$4,irqsrv |
jr $31 |
|
.data |
|
; interrupt service routine table |
|
.align 4 |
|
irqsrv: |
.word 0 ; 00: terminal 0 transmitter interrupt |
.word 0 ; 01: terminal 0 receiver interrupt |
.word 0 ; 02: terminal 1 transmitter interrupt |
.word 0 ; 03: terminal 1 receiver interrupt |
.word 0 ; 04: keyboard interrupt |
.word 0 ; 05: unused |
.word 0 ; 06: unused |
.word 0 ; 07: unused |
.word 0 ; 08: disk interrupt |
.word 0 ; 09: unused |
.word 0 ; 10: unused |
.word 0 ; 11: unused |
.word 0 ; 12: unused |
.word 0 ; 13: unused |
.word 0 ; 14: timer interrupt |
.word 0 ; 15: unused |
.word 0 ; 16: bus timeout exception |
.word 0 ; 17: illegal instruction exception |
.word 0 ; 18: privileged instruction exception |
.word 0 ; 19: divide instruction exception |
.word 0 ; 20: trap instruction exception |
.word 0 ; 21: TLB miss exception |
.word 0 ; 22: TLB write exception |
.word 0 ; 23: TLB invalid exception |
.word 0 ; 24: illegal address exception |
.word 0 ; 25: privileged address exception |
.word 0 ; 26: unused |
.word 0 ; 27: unused |
.word 0 ; 28: unused |
.word 0 ; 29: unused |
.word 0 ; 30: unused |
.word 0 ; 31: unused |
|
.bss |
|
.align 4 |
.space 0x800 |
stack: |
|
.align 4 |
.space 0x800 |
istack: |
/stdalone/twotasks-2/os/start.h
0,0 → 1,23
/* |
* start.h -- startup code |
*/ |
|
|
#ifndef _START_H_ |
#define _START_H_ |
|
|
typedef void (*ISR)(int irq, unsigned int *registers); |
|
|
void enable(void); |
void disable(void); |
void orMask(unsigned int mask); |
void andMask(unsigned int mask); |
ISR getISR(int irq); |
void setISR(int irq, ISR isr); |
void startTask(void); |
void setTLB(int index, unsigned int entryHi, unsigned int entryLo); |
|
|
#endif /* _START_H_ */ |
/stdalone/twotasks-2/os/main.c
0,0 → 1,369
/* |
* main.c -- start the ball rolling |
*/ |
|
|
#include "stdarg.h" |
#include "start.h" |
|
|
/**************************************************************/ |
|
|
int currentTask; |
unsigned int **currentPageDir; |
unsigned int *currentStkTop; |
|
|
/**************************************************************/ |
|
|
unsigned int task0Stack[256]; |
unsigned int *task0StkTop = task0Stack + 256; |
|
|
unsigned char task1Code[] = { |
#include "task1.dump" |
}; |
|
unsigned int task1Stack[256]; |
unsigned int *task1StkTop = task1Stack + 256; |
|
unsigned int **task1PageDir; |
|
|
unsigned char task2Code[] = { |
#include "task2.dump" |
}; |
|
unsigned int task2Stack[256]; |
unsigned int *task2StkTop = task2Stack + 256; |
|
unsigned int **task2PageDir; |
|
|
/**************************************************************/ |
|
|
unsigned int pageTablePool[10][1024]; |
int nextPageTable = 0; |
|
|
unsigned int *allocPageTable(void) { |
unsigned int *pageTable; |
int i; |
|
pageTable = pageTablePool[nextPageTable++]; |
for (i = 0; i < 1024; i++) { |
pageTable[i] = 0; |
} |
return pageTable; |
} |
|
|
/**************************************************************/ |
|
|
void putchar(char c) { |
unsigned int *base; |
|
if (c == '\n') { |
putchar('\r'); |
} |
base = (unsigned int *) 0xF0300000; |
while ((*(base + 2) & 1) == 0) ; |
*(base + 3) = c; |
} |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void printn(int n) { |
int a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printu(unsigned int n, unsigned int b) { |
unsigned int a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b); |
} |
putchar("0123456789ABCDEF"[n % b]); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == 'd') { |
n = va_arg(ap, int); |
printn(n); |
} else |
if (c == 'u' || c == 'o' || c == 'x') { |
u = va_arg(ap, int); |
printu(u, c == 'o' ? 8 : (c == 'x' ? 16 : 10)); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/**************************************************************/ |
|
|
static char *exceptionCause[32] = { |
/* 00 */ "terminal 0 transmitter interrupt", |
/* 01 */ "terminal 0 receiver interrupt", |
/* 02 */ "terminal 1 transmitter interrupt", |
/* 03 */ "terminal 1 receiver interrupt", |
/* 04 */ "keyboard interrupt", |
/* 05 */ "unknown interrupt", |
/* 06 */ "unknown interrupt", |
/* 07 */ "unknown interrupt", |
/* 08 */ "disk interrupt", |
/* 09 */ "unknown interrupt", |
/* 10 */ "unknown interrupt", |
/* 11 */ "unknown interrupt", |
/* 12 */ "unknown interrupt", |
/* 13 */ "unknown interrupt", |
/* 14 */ "timer interrupt", |
/* 15 */ "unknown interrupt", |
/* 16 */ "bus timeout exception", |
/* 17 */ "illegal instruction exception", |
/* 18 */ "privileged instruction exception", |
/* 19 */ "divide instruction exception", |
/* 20 */ "trap instruction exception", |
/* 21 */ "TLB miss exception", |
/* 22 */ "TLB write exception", |
/* 23 */ "TLB invalid exception", |
/* 24 */ "illegal address exception", |
/* 25 */ "privileged address exception", |
/* 26 */ "unknown exception", |
/* 27 */ "unknown exception", |
/* 28 */ "unknown exception", |
/* 29 */ "unknown exception", |
/* 30 */ "unknown exception", |
/* 31 */ "unknown exception" |
}; |
|
|
void defaultISR(int irq, unsigned int *registers) { |
printf("\n%s\n", exceptionCause[irq]); |
} |
|
|
void initInterrupts(void) { |
int i; |
|
for (i = 0; i < 32; i++) { |
setISR(i, defaultISR); |
} |
} |
|
|
/**************************************************************/ |
|
|
unsigned int getNumber(unsigned char *p) { |
return (unsigned int) *(p + 0) << 24 | |
(unsigned int) *(p + 1) << 16 | |
(unsigned int) *(p + 2) << 8 | |
(unsigned int) *(p + 3) << 0; |
} |
|
|
unsigned int **loadTask(unsigned char *code, |
unsigned int physCodeAddr, |
unsigned int physDataAddr, |
unsigned int physStackAddr) { |
unsigned int magic; |
unsigned int csize; |
unsigned int dsize; |
unsigned int bsize; |
unsigned char *virtLoadAddr; |
int i; |
unsigned int **pageDir; |
|
magic = getNumber(code); |
code += sizeof(unsigned int); |
csize = getNumber(code); |
code += sizeof(unsigned int); |
dsize = getNumber(code); |
code += sizeof(unsigned int); |
bsize = getNumber(code); |
code += sizeof(unsigned int); |
if (magic != 0x1AA09232) { |
printf("Error: Load module is not executable!\n"); |
while (1) ; |
} |
code += 4 * sizeof(unsigned int); |
printf("(csize = 0x%x, dsize = 0x%x, bsize = 0x%x)\n", |
csize, dsize, bsize); |
virtLoadAddr = (unsigned char *) (0xC0000000 | physCodeAddr); |
for (i = 0; i < csize; i++) { |
*virtLoadAddr++ = *code++; |
} |
virtLoadAddr = (unsigned char *) (0xC0000000 | physDataAddr); |
for (i = 0; i < dsize; i++) { |
*virtLoadAddr++ = *code++; |
} |
for (i = 0; i < bsize; i++) { |
*virtLoadAddr++ = '\0'; |
} |
/* allocate a page directory and two page tables */ |
pageDir = (unsigned int **) allocPageTable(); |
pageDir[0] = allocPageTable(); |
pageDir[0][0] = physCodeAddr | 0x01; |
pageDir[0][1] = physDataAddr | 0x03; |
pageDir[511] = allocPageTable(); |
pageDir[511][1023] = physStackAddr | 0x03; |
return pageDir; |
} |
|
|
/**************************************************************/ |
|
|
void trapISR(int irq, unsigned int *registers) { |
/* 'putchar' is the only system call yet */ |
putchar(registers[4]); |
/* skip the trap instruction */ |
registers[30] += 4; |
} |
|
|
/**************************************************************/ |
|
|
void flushTLB(void) { |
unsigned int invalPage; |
int i; |
|
invalPage = 0xC0000000; |
for (i = 0; i < 32; i++) { |
setTLB(i, invalPage, 0); |
invalPage += (1 << 12); |
} |
} |
|
|
/**************************************************************/ |
|
|
void initTimer(void) { |
unsigned int *timerBase; |
|
timerBase = (unsigned int *) 0xF0000000; |
*(timerBase + 1) = 1000; |
*timerBase = 2; |
orMask(1 << 14); |
} |
|
|
int task1Started = 0; |
int task2Started = 0; |
|
|
void timerISR(int irq, unsigned int *registers) { |
unsigned int *timerBase; |
|
timerBase = (unsigned int *) 0xF0000000; |
*timerBase = 2; |
printf(">|<"); |
if (currentTask == 0) { |
if (!task1Started) { |
/* load & start task1 */ |
printf("\nOS: loading task1\n"); |
task1PageDir = loadTask(task1Code, 64 << 12, 68 << 12, 80 << 12); |
printf("OS: starting task1\n"); |
task1Started = 1; |
currentTask = 1; |
currentPageDir = task1PageDir; |
currentStkTop = task1StkTop; |
flushTLB(); |
startTask(); |
} |
} else if (currentTask == 1) { |
if (!task2Started) { |
/* load & start task2 */ |
printf("\nOS: loading task2\n"); |
task2PageDir = loadTask(task2Code, 96 << 12, 100 << 12, 112 << 12); |
printf("OS: starting task2\n"); |
task2Started = 1; |
currentTask = 2; |
currentPageDir = task2PageDir; |
currentStkTop = task2StkTop; |
flushTLB(); |
startTask(); |
} else { |
/* switch tasks */ |
currentTask = 2; |
currentPageDir = task2PageDir; |
currentStkTop = task2StkTop; |
flushTLB(); |
} |
} else if (currentTask == 2) { |
/* switch tasks */ |
currentTask = 1; |
currentPageDir = task1PageDir; |
currentStkTop = task1StkTop; |
flushTLB(); |
} |
} |
|
|
/**************************************************************/ |
|
|
void main(void) { |
currentTask = 0; |
currentStkTop = task0StkTop; |
printf("\n"); |
printf("OS: initializing interrupts\n"); |
initInterrupts(); |
setISR(20, trapISR); |
setISR(14, timerISR); |
printf("OS: initializing timer\n"); |
initTimer(); |
printf("OS: waiting for interrupt...\n"); |
enable(); |
while (1) ; |
} |
/stdalone/twotasks-2/os/end.s
0,0 → 1,19
; |
; end.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/twotasks-2/os/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/twotasks-2/os/Makefile
0,0 → 1,23
BUILD = ../../../build |
|
SRC = start.s main.c end.s |
BIN = twotasks-2.bin |
MAP = twotasks-2.map |
|
all: $(BIN) |
|
run: $(BIN) |
$(BUILD)/bin/sim -i -t 1 -l $(BIN) |
|
$(BIN): $(SRC) task1.dump task2.dump |
$(BUILD)/bin/lcc -A -Wo-kernel \ |
-Wl-m -Wl$(MAP) -o $(BIN) $(SRC) |
|
task1.dump: |
../dump/dump ../task1/task1 task1.dump |
|
task2.dump: |
../dump/dump ../task2/task2 task2.dump |
|
clean: |
rm -f *~ task1.dump task2.dump $(BIN) $(MAP) |
/stdalone/twotasks-2/os/start.s
0,0 → 1,294
; |
; start.s -- startup code |
; |
|
.import main |
.import task0StkTop |
.import currentStkTop |
.import currentPageDir |
.import _ecode |
.import _edata |
.import _ebss |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export enable |
.export disable |
.export orMask |
.export andMask |
.export getISR |
.export setISR |
.export startTask |
.export setTLB |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
|
; reset arrives here |
reset: |
j start |
|
; interrupts arrive here |
intrpt: |
j isr |
|
; user TLB misses arrive here |
userMiss: |
add $27,$1,$0 |
ldw $26,$0,currentPageDir |
mvfs $1,2 |
slr $1,$1,20 |
and $1,$1,0xFFC |
add $26,$26,$1 |
ldw $26,$26,0 |
mvfs $1,2 |
slr $1,$1,10 |
and $1,$1,0xFFC |
add $26,$26,$1 |
ldw $26,$26,0 |
mvts $26,3 ; entryLow |
tbwr |
add $1,$27,$0 |
rfx |
|
isr: |
add $26,$29,$0 ; sp -> $26 |
add $27,$1,$0 ; $1 -> $27 |
ldw $29,$0,currentStkTop ; setup kernel mode stack |
sub $29,$29,128 ; save registers |
stw $2,$29,8 |
stw $3,$29,12 |
stw $4,$29,16 |
stw $5,$29,20 |
stw $6,$29,24 |
stw $7,$29,28 |
stw $8,$29,32 |
stw $9,$29,36 |
stw $10,$29,40 |
stw $11,$29,44 |
stw $12,$29,48 |
stw $13,$29,52 |
stw $14,$29,56 |
stw $15,$29,60 |
stw $16,$29,64 |
stw $17,$29,68 |
stw $18,$29,72 |
stw $19,$29,76 |
stw $20,$29,80 |
stw $21,$29,84 |
stw $22,$29,88 |
stw $23,$29,92 |
stw $24,$29,96 |
stw $25,$29,100 |
stw $26,$29,116 ; this is the task's sp |
stw $27,$29,4 ; this is the task's $1 |
stw $30,$29,120 ; this is the task's resumption addr |
stw $31,$29,124 |
add $5,$29,$0 ; $5 = pointer to register array |
mvfs $4,0 ; $4 = IRQ number |
slr $4,$4,16 |
and $4,$4,0x1F |
sll $26,$4,2 ; $26 = 4 * IRQ number |
ldw $26,$26,irqsrv ; get addr of service routine |
jalr $26 ; call service routine |
j resume ; resume task if ISR returns |
|
; resume a task |
resume: |
ldw $29,$0,currentStkTop ; setup kernel mode stack |
sub $29,$29,128 ; restore registers |
ldw $2,$29,8 |
ldw $3,$29,12 |
ldw $4,$29,16 |
ldw $5,$29,20 |
ldw $6,$29,24 |
ldw $7,$29,28 |
ldw $8,$29,32 |
ldw $9,$29,36 |
ldw $10,$29,40 |
ldw $11,$29,44 |
ldw $12,$29,48 |
ldw $13,$29,52 |
ldw $14,$29,56 |
ldw $15,$29,60 |
ldw $16,$29,64 |
ldw $17,$29,68 |
ldw $18,$29,72 |
ldw $19,$29,76 |
ldw $20,$29,80 |
ldw $21,$29,84 |
ldw $22,$29,88 |
ldw $23,$29,92 |
ldw $24,$29,96 |
ldw $25,$29,100 |
ldw $26,$29,116 ; this is the task's sp |
ldw $27,$29,4 ; this is the task's $1 |
ldw $30,$29,120 ; this is the task's resumption addr |
ldw $31,$29,124 |
add $1,$27,$0 ; $27 -> $1 |
add $29,$26,$0 ; $26 -> sp |
rfx ; return from exception |
|
start: |
mvfs $8,0 |
or $8,$8,1 << 27 ; let vector point to RAM |
mvts $8,0 |
add $10,$0,_bdata ; copy data segment |
add $8,$0,_edata |
sub $9,$8,$10 |
add $9,$9,_ecode |
j cpytest |
cpyloop: |
ldw $11,$9,0 |
stw $11,$8,0 |
cpytest: |
sub $8,$8,4 |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
add $8,$0,_bbss ; clear bss |
add $9,$0,_ebss |
j clrtest |
clrloop: |
stw $0,$8,0 |
add $8,$8,4 |
clrtest: |
bltu $8,$9,clrloop |
ldw $29,$0,task0StkTop ; setup kernel mode stack for task 0 |
jal main ; call 'main' |
start1: |
j start1 ; loop |
|
enable: |
mvfs $8,0 |
or $8,$8,1 << 23 |
mvts $8,0 |
jr $31 |
|
disable: |
mvfs $8,0 |
and $8,$8,~(1 << 23) |
mvts $8,0 |
jr $31 |
|
orMask: |
mvfs $8,0 |
and $4,$4,0x0000FFFF ; use lower 16 bits only |
or $8,$8,$4 |
mvts $8,0 |
jr $31 |
|
andMask: |
mvfs $8,0 |
or $4,$4,0xFFFF0000 ; use lower 16 bits only |
and $8,$8,$4 |
mvts $8,0 |
jr $31 |
|
getISR: |
sll $4,$4,2 |
ldw $2,$4,irqsrv |
jr $31 |
|
setISR: |
sll $4,$4,2 |
stw $5,$4,irqsrv |
jr $31 |
|
startTask: |
ldw $29,$0,currentStkTop ; setup kernel mode stack |
sub $29,$29,128 |
stw $0,$29,0 ; preset registers |
stw $0,$29,4 |
stw $0,$29,8 |
stw $0,$29,12 |
stw $0,$29,16 |
stw $0,$29,20 |
stw $0,$29,24 |
stw $0,$29,28 |
stw $0,$29,32 |
stw $0,$29,36 |
stw $0,$29,40 |
stw $0,$29,44 |
stw $0,$29,48 |
stw $0,$29,52 |
stw $0,$29,56 |
stw $0,$29,60 |
stw $0,$29,64 |
stw $0,$29,68 |
stw $0,$29,72 |
stw $0,$29,76 |
stw $0,$29,80 |
stw $0,$29,84 |
stw $0,$29,88 |
stw $0,$29,92 |
stw $0,$29,96 |
stw $0,$29,100 |
stw $0,$29,104 |
stw $0,$29,108 |
stw $0,$29,112 |
add $8,$0,0x80000000 |
stw $8,$29,116 ; sp |
stw $0,$29,120 ; task starts at virtual addr 0 |
stw $0,$29,124 |
mvfs $8,0 |
or $8,$8,1 << 25 ; set previous mode to 'user' |
or $8,$8,1 << 22 ; and enable interrupts |
mvts $8,0 |
j resume |
|
setTLB: |
mvts $4,1 ; set index |
mvts $5,2 ; set entryHi |
mvts $6,3 ; set entryLo |
tbwi ; write TLB entry at index |
jr $31 |
|
.data |
|
; interrupt service routine table |
|
.align 4 |
|
irqsrv: |
.word 0 ; 00: terminal 0 transmitter interrupt |
.word 0 ; 01: terminal 0 receiver interrupt |
.word 0 ; 02: terminal 1 transmitter interrupt |
.word 0 ; 03: terminal 1 receiver interrupt |
.word 0 ; 04: keyboard interrupt |
.word 0 ; 05: unused |
.word 0 ; 06: unused |
.word 0 ; 07: unused |
.word 0 ; 08: disk interrupt |
.word 0 ; 09: unused |
.word 0 ; 10: unused |
.word 0 ; 11: unused |
.word 0 ; 12: unused |
.word 0 ; 13: unused |
.word 0 ; 14: timer interrupt |
.word 0 ; 15: unused |
.word 0 ; 16: bus timeout exception |
.word 0 ; 17: illegal instruction exception |
.word 0 ; 18: privileged instruction exception |
.word 0 ; 19: divide instruction exception |
.word 0 ; 20: trap instruction exception |
.word 0 ; 21: TLB miss exception |
.word 0 ; 22: TLB write exception |
.word 0 ; 23: TLB invalid exception |
.word 0 ; 24: illegal address exception |
.word 0 ; 25: privileged address exception |
.word 0 ; 26: unused |
.word 0 ; 27: unused |
.word 0 ; 28: unused |
.word 0 ; 29: unused |
.word 0 ; 30: unused |
.word 0 ; 31: unused |
/stdalone/twotasks-2/task1/c0.s
0,0 → 1,30
; |
; c0.s -- startup code and begin-of-segment labels |
; |
|
.import main |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.import _ecode |
.import _edata |
.import _ebss |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
.align 4 |
|
start: |
jal main ; call 'main' function |
stop: |
j stop ; just to be sure... |
/stdalone/twotasks-2/task1/c1.s
0,0 → 1,19
; |
; c1.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/twotasks-2/task1/task1.c
0,0 → 1,95
/* |
* task1.c -- a simple task |
*/ |
|
|
#include "putchar.h" |
#include "stdarg.h" |
|
|
/**************************************************************/ |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void printn(int n) { |
int a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printu(unsigned int n, unsigned int b) { |
unsigned int a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b); |
} |
putchar("0123456789ABCDEF"[n % b]); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == 'd') { |
n = va_arg(ap, int); |
printn(n); |
} else |
if (c == 'u' || c == 'o' || c == 'x') { |
u = va_arg(ap, int); |
printu(u, c == 'o' ? 8 : (c == 'x' ? 16 : 10)); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/**************************************************************/ |
|
|
void main(void) { |
int i; |
|
printf("TASK1: executing...\n"); |
i = 0; |
while (1) { |
printf("TASK1: %d\n", i); |
i++; |
} |
} |
/stdalone/twotasks-2/task1/putchar.s
0,0 → 1,10
; |
; putchar.s -- putchar library function |
; |
|
.code |
.export putchar |
|
putchar: |
trap |
jr $31 |
/stdalone/twotasks-2/task1/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/twotasks-2/task1/putchar.h
0,0 → 1,13
/* |
* putchar.h -- putchar library function |
*/ |
|
|
#ifndef _PUTCHAR_H_ |
#define _PUTCHAR_H_ |
|
|
void putchar(char c); |
|
|
#endif /* _PUTCHAR_H_ */ |
/stdalone/twotasks-2/task1/Makefile
0,0 → 1,21
BUILD = ../../../build |
|
all: task1 |
|
task1: c0.o task1.o putchar.o c1.o |
$(BUILD)/bin/ld -o task1 c0.o task1.o putchar.o c1.o |
|
c0.o: c0.s |
$(BUILD)/bin/as -o c0.o c0.s |
|
task1.o: task1.c |
$(BUILD)/bin/lcc -A -c -o task1.o task1.c |
|
putchar.o: putchar.s |
$(BUILD)/bin/as -o putchar.o putchar.s |
|
c1.o: c1.s |
$(BUILD)/bin/as -o c1.o c1.s |
|
clean: |
rm -f *~ c0.o task1.o putchar.o c1.o task1 |
/stdalone/twotasks-2/task2/c0.s
0,0 → 1,30
; |
; c0.s -- startup code and begin-of-segment labels |
; |
|
.import main |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.import _ecode |
.import _edata |
.import _ebss |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
.code |
.align 4 |
|
start: |
jal main ; call 'main' function |
stop: |
j stop ; just to be sure... |
/stdalone/twotasks-2/task2/c1.s
0,0 → 1,19
; |
; c1.s -- end-of-segment labels |
; |
|
.export _ecode |
.export _edata |
.export _ebss |
|
.code |
.align 4 |
_ecode: |
|
.data |
.align 4 |
_edata: |
|
.bss |
.align 4 |
_ebss: |
/stdalone/twotasks-2/task2/task2.c
0,0 → 1,95
/* |
* task2.c -- a simple task |
*/ |
|
|
#include "putchar.h" |
#include "stdarg.h" |
|
|
/**************************************************************/ |
|
|
void puts(char *s) { |
char c; |
|
while ((c = *s++) != '\0') { |
putchar(c); |
} |
} |
|
|
void printn(int n) { |
int a; |
|
if (n < 0) { |
putchar('-'); |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
printn(a); |
} |
putchar(n % 10 + '0'); |
} |
|
|
void printu(unsigned int n, unsigned int b) { |
unsigned int a; |
|
a = n / b; |
if (a != 0) { |
printu(a, b); |
} |
putchar("0123456789ABCDEF"[n % b]); |
} |
|
|
void printf(char *fmt, ...) { |
va_list ap; |
char c; |
int n; |
unsigned int u; |
char *s; |
|
va_start(ap, fmt); |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
va_end(ap); |
return; |
} |
putchar(c); |
} |
c = *fmt++; |
if (c == 'd') { |
n = va_arg(ap, int); |
printn(n); |
} else |
if (c == 'u' || c == 'o' || c == 'x') { |
u = va_arg(ap, int); |
printu(u, c == 'o' ? 8 : (c == 'x' ? 16 : 10)); |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
puts(s); |
} else { |
putchar(c); |
} |
} |
} |
|
|
/**************************************************************/ |
|
|
void main(void) { |
int i; |
|
printf("TASK2: executing...\n"); |
i = 0; |
while (1) { |
printf("TASK2: %d\n", i); |
i++; |
} |
} |
/stdalone/twotasks-2/task2/putchar.s
0,0 → 1,10
; |
; putchar.s -- putchar library function |
; |
|
.code |
.export putchar |
|
putchar: |
trap |
jr $31 |
/stdalone/twotasks-2/task2/stdarg.h
0,0 → 1,41
/* |
* stdarg.h -- variable argument lists |
*/ |
|
|
#ifndef _STDARG_H_ |
#define _STDARG_H_ |
|
|
typedef char *va_list; |
|
|
static float __va_arg_tmp; |
|
|
#define va_start(list, start) \ |
((void)((list) = (sizeof(start)<4 ? \ |
(char *)((int *)&(start)+1) : (char *)(&(start)+1)))) |
|
#define __va_arg(list, mode, n) \ |
(__typecode(mode)==1 && sizeof(mode)==4 ? \ |
(__va_arg_tmp = *(double *)(&(list += \ |
((sizeof(double)+n)&~n))[-(int)((sizeof(double)+n)&~n)]), \ |
*(mode *)&__va_arg_tmp) : \ |
*(mode *)(&(list += \ |
((sizeof(mode)+n)&~n))[-(int)((sizeof(mode)+n)&~n)])) |
|
#define _bigendian_va_arg(list, mode, n) \ |
(sizeof(mode)==1 ? *(mode *)(&(list += 4)[-1]) : \ |
sizeof(mode)==2 ? *(mode *)(&(list += 4)[-2]) : \ |
__va_arg(list, mode, n)) |
|
#define va_end(list) ((void)0) |
|
#define va_arg(list, mode) \ |
(sizeof(mode)==8 ? \ |
*(mode *)(&(list = (char*)(((int)list + 15)&~7U))[-8]) : \ |
_bigendian_va_arg(list, mode, 3U)) |
|
|
#endif /* _STDARG_H_ */ |
/stdalone/twotasks-2/task2/putchar.h
0,0 → 1,13
/* |
* putchar.h -- putchar library function |
*/ |
|
|
#ifndef _PUTCHAR_H_ |
#define _PUTCHAR_H_ |
|
|
void putchar(char c); |
|
|
#endif /* _PUTCHAR_H_ */ |
/stdalone/twotasks-2/task2/Makefile
0,0 → 1,21
BUILD = ../../../build |
|
all: task2 |
|
task2: c0.o task2.o putchar.o c1.o |
$(BUILD)/bin/ld -o task2 c0.o task2.o putchar.o c1.o |
|
c0.o: c0.s |
$(BUILD)/bin/as -o c0.o c0.s |
|
task2.o: task2.c |
$(BUILD)/bin/lcc -A -c -o task2.o task2.c |
|
putchar.o: putchar.s |
$(BUILD)/bin/as -o putchar.o putchar.s |
|
c1.o: c1.s |
$(BUILD)/bin/as -o c1.o c1.s |
|
clean: |
rm -f *~ c0.o task2.o putchar.o c1.o task2 |
/stdalone/twotasks-2/dump/dump.c
0,0 → 1,48
/* |
* dump.c -- dump a binary file as contents of a C array |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
|
|
int main(int argc, char *argv[]) { |
FILE *infile, *outfile; |
int c, n; |
|
if (argc != 3) { |
printf("Usage: %s <infile> <outfile>\n", argv[0]); |
return 1; |
} |
infile = fopen(argv[1], "rb"); |
if (infile == NULL) { |
printf("Error: cannot open file '%s' for input\n", argv[1]); |
return 1; |
} |
outfile = fopen(argv[2], "wt"); |
if (outfile == NULL) { |
printf("Error: cannot open file '%s' for output\n", argv[2]); |
return 1; |
} |
n = 0; |
while (1) { |
c = getc(infile); |
if (c == EOF) { |
break; |
} |
fprintf(outfile, "0x%02X, ", c); |
n++; |
if (n == 8) { |
n = 0; |
fprintf(outfile, "\n"); |
} |
} |
if (n != 0) { |
fprintf(outfile, "\n"); |
} |
fclose(infile); |
fclose(outfile); |
return 0; |
} |
/stdalone/twotasks-2/dump/Makefile
0,0 → 1,15
# |
# Makefile for dump utility |
# |
|
.PHONY: all install clean |
|
all: dump |
|
install: dump |
|
dump: dump.c |
gcc -m32 -g -Wall -o dump dump.c |
|
clean: |
rm -f *~ dump |
/stdalone/twotasks-2/Makefile
0,0 → 1,37
# |
# Makefile for "twotasks-2", a tiny OS which runs two tasks |
# (with randomly written TLB entries and real page tables) |
# |
|
BUILD = ../../build |
|
.PHONY: all install run clean |
|
all: dump/dump task1/task1 task2/task2 os/twotasks-2.bin |
|
install: dump/dump task1/task1 task2/task2 os/twotasks-2.bin |
mkdir -p $(BUILD)/stdalone |
cp os/twotasks-2.bin $(BUILD)/stdalone |
cp os/twotasks-2.map $(BUILD)/stdalone |
|
run: dump/dump task1/task1 task2/task2 os/twotasks-2.bin |
$(MAKE) -C os run |
|
dump/dump: |
$(MAKE) -C dump |
|
task1/task1: |
$(MAKE) -C task1 |
|
task2/task2: |
$(MAKE) -C task2 |
|
os/twotasks-2.bin: |
$(MAKE) -C os |
|
clean: |
$(MAKE) -C dump clean |
$(MAKE) -C task1 clean |
$(MAKE) -C task2 clean |
$(MAKE) -C os clean |
rm -f *~ |
/Makefile
4,7 → 4,7
|
VERSION = 0.22 |
|
DIRS = doc binutils sim simtest fpga hwtests monitor disk |
DIRS = doc binutils sim simtest fpga hwtests monitor disk stdalone |
BUILD = `pwd`/build |
|
.PHONY: all compiler builddir clean dist |