URL
https://opencores.org/ocsvn/eco32/eco32/trunk
Subversion Repositories eco32
Compare Revisions
- This comparison shows the changes necessary to convert path
/eco32/tags/eco32-0.26/hwtests/kbdtest
- from Rev 245 to Rev 270
- ↔ Reverse comparison
Rev 245 → Rev 270
/Makefile
0,0 → 1,27
# |
# Makefile for kbdtest ROM |
# |
|
BUILD = ../../build |
|
KBDTEST_SRC = start.s main.c lib.c serial.s end.s |
|
.PHONY: all install run clean |
|
all: kbdtest.exo |
|
install: kbdtest.exo |
|
kbdtest.exo: kbdtest.bin |
$(BUILD)/bin/bin2exo -S2 0 kbdtest.bin kbdtest.exo |
|
kbdtest.bin: $(KBDTEST_SRC) |
$(BUILD)/bin/lcc -A -Wo-rom -Wl-rd -Wl0xC03F0000 \ |
-Wl-m -Wlkbdtest.map -o kbdtest.bin $(KBDTEST_SRC) |
|
run: kbdtest.bin |
$(BUILD)/bin/sim -i -c -s 1 -t 0 -r kbdtest.bin |
|
clean: |
rm -f *~ |
rm -f kbdtest.map kbdtest.bin kbdtest.exo |
/README
0,0 → 1,5
This is a test for the keyboard. After initializing the interrupt |
system, the program waits for keyboard interrupts. As soon as a byte |
is sent by the keyboard, its hex representation is output on serial |
line 0 (as are the initialization messages). If you run this test on |
the simulator, be sure to give the input focus to the console screen. |
/serial.s
0,0 → 1,98
; |
; serial.s -- the serial line interface |
; |
|
;*************************************************************** |
|
.set ser0base,0xF0300000 ; serial line 0 base address |
.set ser1base,0xF0301000 ; serial line 1 base address |
|
.export serinit ; initialize serial interface |
|
.export ser0inchk ; line 0 input check |
.export ser0in ; line 0 input |
.export ser0outchk ; line 0 output check |
.export ser0out ; line 0 output |
|
.export ser1inchk ; line 1 input check |
.export ser1in ; line 1 input |
.export ser1outchk ; line 1 output check |
.export ser1out ; line 1 output |
|
;*************************************************************** |
|
.code |
.align 4 |
|
serinit: |
jr $31 |
|
;*************************************************************** |
|
.code |
.align 4 |
|
ser0inchk: |
add $8,$0,ser0base |
ldw $2,$8,0 |
and $2,$2,1 |
jr $31 |
|
ser0in: |
add $8,$0,ser0base |
ser0in1: |
ldw $9,$8,0 |
and $9,$9,1 |
beq $9,$0,ser0in1 |
ldw $2,$8,4 |
jr $31 |
|
ser0outchk: |
add $8,$0,ser0base |
ldw $2,$8,8 |
and $2,$2,1 |
jr $31 |
|
ser0out: |
add $8,$0,ser0base |
ser0out1: |
ldw $9,$8,8 |
and $9,$9,1 |
beq $9,$0,ser0out1 |
stw $4,$8,12 |
jr $31 |
|
;*************************************************************** |
|
.code |
.align 4 |
|
ser1inchk: |
add $8,$0,ser1base |
ldw $2,$8,0 |
and $2,$2,1 |
jr $31 |
|
ser1in: |
add $8,$0,ser1base |
ser1in1: |
ldw $9,$8,0 |
and $9,$9,1 |
beq $9,$0,ser1in1 |
ldw $2,$8,4 |
jr $31 |
|
ser1outchk: |
add $8,$0,ser1base |
ldw $2,$8,8 |
and $2,$2,1 |
jr $31 |
|
ser1out: |
add $8,$0,ser1base |
ser1out1: |
ldw $9,$8,8 |
and $9,$9,1 |
beq $9,$0,ser1out1 |
stw $4,$8,12 |
jr $31 |
/main.c
0,0 → 1,129
/* |
* main.c -- the main program |
*/ |
|
|
#include "common.h" |
#include "lib.h" |
#include "start.h" |
|
|
int charAvail = 0; |
char charRead; |
|
|
/**************************************************************/ |
|
|
/* |
* Interrupt and exception messages which will be shown if |
* the corresponding interrupt or exception is not handled. |
*/ |
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 5", |
/* 06 */ "unknown interrupt 6", |
/* 07 */ "unknown interrupt 7", |
/* 08 */ "disk interrupt", |
/* 09 */ "unknown interrupt 9", |
/* 10 */ "unknown interrupt 10", |
/* 11 */ "unknown interrupt 11", |
/* 12 */ "unknown interrupt 12", |
/* 13 */ "unknown interrupt 13", |
/* 14 */ "timer 0 interrupt", |
/* 15 */ "timer 1 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 26", |
/* 27 */ "unknown exception 27", |
/* 28 */ "unknown exception 28", |
/* 29 */ "unknown exception 29", |
/* 30 */ "unknown exception 30", |
/* 31 */ "unknown exception 31" |
}; |
|
|
/* |
* This is the default interrupt service routine. |
* It simply panics with a message that tells the cause. |
*/ |
void defaultISR(int irq, InterruptContext *icp) { |
printf("**** %s ****\n", exceptionCause[irq]); |
while (1) ; |
} |
|
|
/* |
* Initialize all interrupts and exceptions to the default ISR. |
* Enable interrupts. |
*/ |
void initInterrupts(void) { |
int i; |
|
for (i = 0; i < 32; i++) { |
setISR(i, defaultISR); |
} |
enable(); |
} |
|
|
/**************************************************************/ |
|
|
void kbdISR(int irq, InterruptContext *icp) { |
unsigned int *p; |
|
p = (unsigned int *) 0xF0200000; |
charRead = *(p + 1); |
charAvail = 1; |
} |
|
|
void kbdEnable(void) { |
unsigned int *p; |
|
p = (unsigned int *) 0xF0200000; |
*p = 2; |
} |
|
|
int main(void) { |
unsigned char c; |
int n; |
|
printf("Keyboard Test:\n"); |
printf("initializing interrupts...\n"); |
initInterrupts(); |
printf("setting kbd ISR...\n"); |
setISR(4, kbdISR); |
printf("enabling kbd interrupt mask bit...\n"); |
setMask(getMask() | (1 << 4)); |
printf("enabling interrupts in kbd controller...\n"); |
kbdEnable(); |
n = 0; |
while (1) { |
while (charAvail == 0) ; |
disable(); |
c = charRead; |
charAvail = 0; |
enable(); |
printf("%02X ", c); |
if (++n == 24) { |
n = 0; |
printf("\n"); |
} |
} |
return 0; |
} |
/start.s
0,0 → 1,384
; |
; start.s -- startup and support routines |
; |
|
.set dmapaddr,0xC0000000 ; base of directly mapped addresses |
.set stacktop,0xC0400000 ; monitor stack is at top of memory |
|
.set ICNTXT_SIZE,34 * 4 ; size of interrupt context |
|
.set PSW,0 ; reg # of PSW |
.set V_SHIFT,27 ; interrupt vector ctrl bit |
.set V,1 << V_SHIFT |
.set UM_SHIFT,26 ; curr user mode ctrl bit |
.set UM,1 << UM_SHIFT |
.set PUM_SHIFT,25 ; prev user mode ctrl bit |
.set PUM,1 << PUM_SHIFT |
.set OUM_SHIFT,24 ; old user mode ctrl bit |
.set OUM,1 << OUM_SHIFT |
.set IE_SHIFT,23 ; curr int enable ctrl bit |
.set IE,1 << IE_SHIFT |
.set PIE_SHIFT,22 ; prev int enable ctrl bit |
.set PIE,1 << PIE_SHIFT |
.set OIE_SHIFT,21 ; old int enable ctrl bit |
.set OIE,1 << OIE_SHIFT |
|
.set TLB_INDEX,1 ; reg # of TLB Index |
.set TLB_ENTRY_HI,2 ; reg # of TLB EntryHi |
.set TLB_ENTRY_LO,3 ; reg # of TLB EntryLo |
.set TLB_ENTRIES,32 ; number of TLB entries |
|
;*************************************************************** |
|
.import _ecode |
.import _edata |
.import _ebss |
|
.import serinit |
.import ser0in |
.import ser0out |
|
.import main |
|
.export _bcode |
.export _bdata |
.export _bbss |
|
.export cin |
.export cout |
|
.export getTLB_HI |
.export getTLB_LO |
.export setTLB |
.export wrtRndTLB |
.export probeTLB |
.export wait |
|
.export enable |
.export disable |
.export getMask |
.export setMask |
.export getISR |
.export setISR |
|
;*************************************************************** |
|
.code |
_bcode: |
|
.data |
_bdata: |
|
.bss |
_bbss: |
|
;*************************************************************** |
|
.code |
.align 4 |
|
reset: |
j start |
|
interrupt: |
j isr |
|
userMiss: |
j userMiss |
|
;*************************************************************** |
|
.code |
.align 4 |
|
cin: |
j ser0in |
|
cout: |
j ser0out |
|
;*************************************************************** |
|
.code |
.align 4 |
|
start: |
; force CPU into a defined state |
mvts $0,PSW ; disable interrupts and user mode |
|
; initialize TLB |
mvts $0,TLB_ENTRY_LO ; invalidate all TLB entries |
add $8,$0,dmapaddr ; by impossible virtual page number |
add $9,$0,$0 |
add $10,$0,TLB_ENTRIES |
tlbloop: |
mvts $8,TLB_ENTRY_HI |
mvts $9,TLB_INDEX |
tbwi |
add $8,$8,0x1000 ; all entries must be different |
add $9,$9,1 |
bne $9,$10,tlbloop |
|
; copy data segment |
add $10,$0,_bdata ; lowest dst addr to be written to |
add $8,$0,_edata ; one above the top dst addr |
sub $9,$8,$10 ; $9 = size of data segment |
add $9,$9,_ecode ; data is waiting right after code |
j cpytest |
cpyloop: |
ldw $11,$9,0 ; src addr in $9 |
stw $11,$8,0 ; dst addr in $8 |
cpytest: |
sub $8,$8,4 ; downward |
sub $9,$9,4 |
bgeu $8,$10,cpyloop |
|
; clear bss segment |
add $8,$0,_bbss ; start with first word of bss |
add $9,$0,_ebss ; this is one above the top |
j clrtest |
clrloop: |
stw $0,$8,0 ; dst addr in $8 |
add $8,$8,4 ; upward |
clrtest: |
bltu $8,$9,clrloop |
|
; now do some useful work |
add $29,$0,stacktop ; setup monitor stack |
jal serinit ; init serial interface |
jal main ; enter command loop |
|
; main should never return |
j start ; just to be sure... |
|
;*************************************************************** |
|
; Word getTLB_HI(int index) |
getTLB_HI: |
mvts $4,TLB_INDEX |
tbri |
mvfs $2,TLB_ENTRY_HI |
jr $31 |
|
; Word getTLB_LO(int index) |
getTLB_LO: |
mvts $4,TLB_INDEX |
tbri |
mvfs $2,TLB_ENTRY_LO |
jr $31 |
|
; void setTLB(int index, Word entryHi, Word entryLo) |
setTLB: |
mvts $4,TLB_INDEX |
mvts $5,TLB_ENTRY_HI |
mvts $6,TLB_ENTRY_LO |
tbwi |
jr $31 |
|
; void wrtRndTLB(Word entryHi, Word entryLo) |
wrtRndTLB: |
mvts $4,TLB_ENTRY_HI |
mvts $5,TLB_ENTRY_LO |
tbwr |
jr $31 |
|
; Word probeTLB(Word entryHi) |
probeTLB: |
mvts $4,TLB_ENTRY_HI |
tbs |
mvfs $2,TLB_INDEX |
jr $31 |
|
; void wait(int n) |
wait: |
j wait2 |
wait1: |
add $4,$4,$0 |
sub $4,$4,1 |
wait2: |
bne $4,$0,wait1 |
jr $31 |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; void enable(void) |
enable: |
mvfs $8,PSW |
or $8,$8,IE |
mvts $8,PSW |
jr $31 |
|
; void disable(void) |
disable: |
mvfs $8,PSW |
and $8,$8,~IE |
mvts $8,PSW |
jr $31 |
|
; U32 getMask(void) |
getMask: |
mvfs $8,PSW |
and $2,$8,0x0000FFFF ; return lower 16 bits only |
jr $31 |
|
; U32 setMask(U32 mask) |
setMask: |
mvfs $8,PSW |
and $2,$8,0x0000FFFF ; return lower 16 bits only |
and $4,$4,0x0000FFFF ; use lower 16 bits only |
and $8,$8,0xFFFF0000 |
or $8,$8,$4 |
mvts $8,PSW |
jr $31 |
|
; ISR getISR(int irq) |
getISR: |
sll $4,$4,2 |
ldw $2,$4,irqsrv |
jr $31 |
|
; ISR setISR(int irq, ISR isr) |
setISR: |
sll $4,$4,2 |
ldw $2,$4,irqsrv |
stw $5,$4,irqsrv |
jr $31 |
|
;*************************************************************** |
|
.code |
.align 4 |
|
; general interrupt service routine |
; only register $28 is available for bootstrapping |
isr: |
.nosyn |
add $28,$29,$0 |
sub $28,$28,ICNTXT_SIZE ; $28 points to interrupt context |
stw $0,$28,0*4 ; save registers |
stw $1,$28,1*4 |
stw $2,$28,2*4 |
stw $3,$28,3*4 |
stw $4,$28,4*4 |
stw $5,$28,5*4 |
stw $6,$28,6*4 |
stw $7,$28,7*4 |
stw $8,$28,8*4 |
stw $9,$28,9*4 |
stw $10,$28,10*4 |
stw $11,$28,11*4 |
stw $12,$28,12*4 |
stw $13,$28,13*4 |
stw $14,$28,14*4 |
stw $15,$28,15*4 |
stw $16,$28,16*4 |
stw $17,$28,17*4 |
stw $18,$28,18*4 |
stw $19,$28,19*4 |
stw $20,$28,20*4 |
stw $21,$28,21*4 |
stw $22,$28,22*4 |
stw $23,$28,23*4 |
stw $24,$28,24*4 |
stw $25,$28,25*4 |
stw $26,$28,26*4 |
stw $27,$28,27*4 |
stw $28,$28,28*4 |
stw $29,$28,29*4 |
stw $30,$28,30*4 |
stw $31,$28,31*4 |
mvfs $8,TLB_ENTRY_HI ; save TLB EntryHi |
stw $8,$28,32*4 |
mvfs $8,PSW ; save PSW |
stw $8,$28,33*4 |
add $29,$28,$0 ; $29 is required to hold sp |
.syn |
add $5,$29,$0 ; $5 = pointer to interrupt context |
slr $4,$8,16 ; $4 = IRQ number |
and $4,$4,0x1F |
sll $8,$4,2 ; $8 = 4 * IRQ number |
ldw $8,$8,irqsrv ; get addr of service routine |
jalr $8 ; call service routine |
.nosyn |
mvts $0,PSW ; ISR may have enabled interrupts |
add $28,$29,$0 ; $28 points to interrupt context |
ldw $8,$28,32*4 ; restore TLB EntryHi |
mvts $8,TLB_ENTRY_HI |
ldw $0,$28,0*4 ; restore registers |
ldw $1,$28,1*4 |
ldw $2,$28,2*4 |
ldw $3,$28,3*4 |
ldw $4,$28,4*4 |
ldw $5,$28,5*4 |
ldw $6,$28,6*4 |
ldw $7,$28,7*4 |
ldw $8,$28,8*4 |
ldw $9,$28,9*4 |
ldw $10,$28,10*4 |
ldw $11,$28,11*4 |
ldw $12,$28,12*4 |
ldw $13,$28,13*4 |
ldw $14,$28,14*4 |
ldw $15,$28,15*4 |
ldw $16,$28,16*4 |
ldw $17,$28,17*4 |
ldw $18,$28,18*4 |
ldw $19,$28,19*4 |
ldw $20,$28,20*4 |
ldw $21,$28,21*4 |
ldw $22,$28,22*4 |
ldw $23,$28,23*4 |
ldw $24,$28,24*4 |
ldw $25,$28,25*4 |
ldw $26,$28,26*4 |
ldw $27,$28,27*4 |
ldw $28,$28,28*4 |
ldw $29,$28,29*4 |
ldw $30,$28,30*4 |
ldw $31,$28,31*4 |
ldw $28,$28,33*4 ; restore PSW |
mvts $28,PSW |
rfx ; done |
.syn |
|
;*************************************************************** |
|
.data |
.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 0 interrupt |
.word 0 ; 15: timer 1 interrupt |
.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 |
/start.h
0,0 → 1,36
/* |
* start.h -- startup and support routines |
*/ |
|
|
#ifndef _START_H_ |
#define _START_H_ |
|
|
typedef struct { |
Word ic_reg[32]; /* general purpose registers */ |
Word ic_tlbhi; /* TLB EntryHi */ |
Word ic_psw; /* PSW */ |
} InterruptContext; |
|
typedef void (*ISR)(int irq, InterruptContext *icp); |
|
|
int cin(void); |
void cout(char c); |
|
Word getTLB_HI(int index); |
Word getTLB_LO(int index); |
void setTLB(int index, Word entryHi, Word entryLo); |
void wrtRndTLB(Word entryHi, Word entryLo); |
Word probeTLB(Word entryHi); |
void wait(int n); |
void enable(void); |
void disable(void); |
Word getMask(void); |
Word setMask(Word mask); |
ISR getISR(int irq); |
ISR setISR(int irq, ISR isr); |
|
|
#endif /* _START_H_ */ |
/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: |
/lib.c
0,0 → 1,624
/* |
* lib.c -- the library |
*/ |
|
|
#include "common.h" |
#include "lib.h" |
#include "stdarg.h" |
#include "start.h" |
|
|
/**************************************************************/ |
|
|
/* |
* This is only for debugging. |
* Place a breakpoint at the very beginning of this routine |
* and call it wherever you want to break execution. |
*/ |
void debugBreak(void) { |
} |
|
|
/**************************************************************/ |
|
|
/* |
* Count the length of a string (without terminating null character). |
*/ |
int strlen(const char *s) { |
const char *p; |
|
p = s; |
while (*p != '\0') { |
p++; |
} |
return p - s; |
} |
|
|
/* |
* Compare two strings. |
* Return a number < 0, = 0, or > 0 iff the first string is less |
* than, equal to, or greater than the second one, respectively. |
*/ |
int strcmp(const char *s, const char *t) { |
while (*s == *t) { |
if (*s == '\0') { |
return 0; |
} |
s++; |
t++; |
} |
return *s - *t; |
} |
|
|
/* |
* Copy string t to string s (includes terminating null character). |
*/ |
char *strcpy(char *s, const char *t) { |
char *p; |
|
p = s; |
while ((*p = *t) != '\0') { |
p++; |
t++; |
} |
return s; |
} |
|
|
/* |
* Append string t to string s. |
*/ |
char *strcat(char *s, const char *t) { |
char *p; |
|
p = s; |
while (*p != '\0') { |
p++; |
} |
while ((*p = *t) != '\0') { |
p++; |
t++; |
} |
return s; |
} |
|
|
/* |
* Locate character c in string s. |
*/ |
char *strchr(const char *s, char c) { |
while (*s != c) { |
if (*s == '\0') { |
return NULL; |
} |
s++; |
} |
return (char *) s; |
} |
|
|
/* |
* Extract the next token from the string s, delimited |
* by any character from the delimiter string t. |
*/ |
char *strtok(char *s, const char *t) { |
static char *p; |
char *q; |
|
if (s != NULL) { |
p = s; |
} else { |
p++; |
} |
while (*p != '\0' && strchr(t, *p) != NULL) { |
p++; |
} |
if (*p == '\0') { |
return NULL; |
} |
q = p++; |
while (*p != '\0' && strchr(t, *p) == NULL) { |
p++; |
} |
if (*p != '\0') { |
*p = '\0'; |
} else { |
p--; |
} |
return q; |
} |
|
|
/**************************************************************/ |
|
|
/* |
* Determine if a character is 'white space'. |
*/ |
static Bool isspace(char c) { |
Bool res; |
|
switch (c) { |
case ' ': |
case '\f': |
case '\n': |
case '\r': |
case '\t': |
case '\v': |
res = true; |
break; |
default: |
res = false; |
break; |
} |
return res; |
} |
|
|
/* |
* Check for valid digit, and convert to value. |
*/ |
static Bool checkDigit(char c, int base, int *value) { |
if (c >= '0' && c <= '9') { |
*value = c - '0'; |
} else |
if (c >= 'A' && c <= 'Z') { |
*value = c - 'A' + 10; |
} else |
if (c >= 'a' && c <= 'z') { |
*value = c - 'a' + 10; |
} else { |
return false; |
} |
return *value < base; |
} |
|
|
/* |
* Convert initial part of string to unsigned long integer. |
*/ |
unsigned long strtoul(const char *s, char **endp, int base) { |
unsigned long res; |
int sign; |
int digit; |
|
res = 0; |
while (isspace(*s)) { |
s++; |
} |
if (*s == '+') { |
sign = 1; |
s++; |
} else |
if (*s == '-') { |
sign = -1; |
s++; |
} else { |
sign = 1; |
} |
if (base == 0 || base == 16) { |
if (*s == '0' && |
(*(s + 1) == 'x' || *(s + 1) == 'X')) { |
/* base is 16 */ |
s += 2; |
base = 16; |
} else { |
/* base is 0 or 16, but number does not start with "0x" */ |
if (base == 0) { |
if (*s == '0') { |
s++; |
base = 8; |
} else { |
base = 10; |
} |
} else { |
/* take base as is */ |
} |
} |
} else { |
/* take base as is */ |
} |
while (checkDigit(*s, base, &digit)) { |
res *= base; |
res += digit; |
s++; |
} |
if (endp != NULL) { |
*endp = (char *) s; |
} |
return sign * res; |
} |
|
|
/**************************************************************/ |
|
|
/* |
* Exchange two array items of a given size. |
*/ |
static void xchg(char *p, char *q, int size) { |
char t; |
|
while (size--) { |
t = *p; |
*p++ = *q; |
*q++ = t; |
} |
} |
|
|
/* |
* This is a recursive version of quicksort. |
*/ |
static void sort(char *l, char *r, int size, |
int (*cmp)(const void *, const void *)) { |
char *i; |
char *j; |
char *x; |
|
i = l; |
j = r; |
x = l + (((r - l) / size) / 2) * size; |
do { |
while (cmp(i, x) < 0) { |
i += size; |
} |
while (cmp(x, j) < 0) { |
j -= size; |
} |
if (i <= j) { |
/* exchange array elements i and j */ |
/* attention: update x if it is one of these */ |
if (x == i) { |
x = j; |
} else |
if (x == j) { |
x = i; |
} |
xchg(i, j, size); |
i += size; |
j -= size; |
} |
} while (i <= j); |
if (l < j) { |
sort(l, j, size, cmp); |
} |
if (i < r) { |
sort(i, r, size, cmp); |
} |
} |
|
|
/* |
* External interface for the quicksort algorithm. |
*/ |
void qsort(void *base, int n, int size, |
int (*cmp)(const void *, const void*)) { |
sort((char *) base, (char *) base + (n - 1) * size, size, cmp); |
} |
|
|
/**************************************************************/ |
|
|
/* |
* Input a character from the console. |
*/ |
char getchar(void) { |
return cin(); |
} |
|
|
/* |
* Output a character on the console. |
* Replace LF by CR/LF. |
*/ |
void putchar(char c) { |
if (c == '\n') { |
cout('\r'); |
} |
cout(c); |
} |
|
|
/**************************************************************/ |
|
|
/* |
* Count the number of characters needed to represent |
* a given number in base 10. |
*/ |
static 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. |
*/ |
static void *printn(void *(*emit)(void *, char), void *arg, |
int *nchar, long n) { |
long a; |
|
if (n < 0) { |
arg = emit(arg, '-'); |
(*nchar)++; |
n = -n; |
} |
a = n / 10; |
if (a != 0) { |
arg = printn(emit, arg, nchar, a); |
} |
arg = emit(arg, n % 10 + '0'); |
(*nchar)++; |
return arg; |
} |
|
|
/* |
* Count the number of characters needed to represent |
* a given number in a given base. |
*/ |
static 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. |
*/ |
static void *printu(void *(*emit)(void *, char), void *arg, |
int *nchar, unsigned long n, unsigned long b, |
Bool upperCase) { |
unsigned long a; |
|
a = n / b; |
if (a != 0) { |
arg = printu(emit, arg, nchar, a, b, upperCase); |
} |
if (upperCase) { |
arg = emit(arg, "0123456789ABCDEF"[n % b]); |
(*nchar)++; |
} else { |
arg = emit(arg, "0123456789abcdef"[n % b]); |
(*nchar)++; |
} |
return arg; |
} |
|
|
/* |
* Output a number of filler characters. |
*/ |
static void *fill(void *(*emit)(void *, char), void *arg, |
int *nchar, int numFillers, char filler) { |
while (numFillers-- > 0) { |
arg = emit(arg, filler); |
(*nchar)++; |
} |
return arg; |
} |
|
|
/* |
* This function does the real work of formatted printing. |
*/ |
static int doPrintf(void *(*emit)(void *, char), void *arg, |
const char *fmt, va_list ap) { |
int nchar; |
char c; |
int n; |
long ln; |
unsigned int u; |
unsigned long lu; |
char *s; |
Bool negFlag; |
char filler; |
int width, count; |
|
nchar = 0; |
while (1) { |
while ((c = *fmt++) != '%') { |
if (c == '\0') { |
return nchar; |
} |
arg = emit(arg, c); |
nchar++; |
} |
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) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
arg = printn(emit, arg, &nchar, n); |
if (width > 0 && negFlag) { |
arg = fill(emit, arg, &nchar, 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) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
arg = printu(emit, arg, &nchar, u, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10), |
c == 'X'); |
if (width > 0 && negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
} else |
if (c == 'l') { |
c = *fmt++; |
if (c == 'd') { |
ln = va_arg(ap, long); |
count = countPrintn(ln); |
if (width > 0 && !negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
arg = printn(emit, arg, &nchar, ln); |
if (width > 0 && negFlag) { |
arg = fill(emit, arg, &nchar, 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) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
arg = printu(emit, arg, &nchar, lu, |
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10), |
c == 'X'); |
if (width > 0 && negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
} else { |
arg = emit(arg, 'l'); |
nchar++; |
arg = emit(arg, c); |
nchar++; |
} |
} else |
if (c == 's') { |
s = va_arg(ap, char *); |
count = strlen(s); |
if (width > 0 && !negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
while ((c = *s++) != '\0') { |
arg = emit(arg, c); |
nchar++; |
} |
if (width > 0 && negFlag) { |
arg = fill(emit, arg, &nchar, width - count, filler); |
} |
} else |
if (c == 'c') { |
c = va_arg(ap, char); |
arg = emit(arg, c); |
nchar++; |
} else { |
arg = emit(arg, c); |
nchar++; |
} |
} |
/* never reached */ |
return 0; |
} |
|
|
/* |
* Emit a character to the console. |
*/ |
static void *emitToConsole(void *dummy, char c) { |
putchar(c); |
return dummy; |
} |
|
|
/* |
* Formatted output with a variable argument list. |
*/ |
static int vprintf(const char *fmt, va_list ap) { |
int n; |
|
n = doPrintf(emitToConsole, NULL, fmt, ap); |
return n; |
} |
|
|
/* |
* Formatted output. |
*/ |
int printf(const char *fmt, ...) { |
int n; |
va_list ap; |
|
va_start(ap, fmt); |
n = vprintf(fmt, ap); |
va_end(ap); |
return n; |
} |
|
|
/* |
* Emit a character to a buffer. |
*/ |
static void *emitToBuffer(void *bufptr, char c) { |
*(char *)bufptr = c; |
return (char *) bufptr + 1; |
} |
|
|
/* |
* Formatted output into a buffer with a variable argument list. |
*/ |
static int vsprintf(char *s, const char *fmt, va_list ap) { |
int n; |
|
n = doPrintf(emitToBuffer, s, fmt, ap); |
s[n] = '\0'; |
return n; |
} |
|
|
/* |
* Formatted output into a buffer. |
*/ |
int sprintf(char *s, const char *fmt, ...) { |
int n; |
va_list ap; |
|
va_start(ap, fmt); |
n = vsprintf(s, fmt, ap); |
va_end(ap); |
return n; |
} |
/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_ */ |
/lib.h
0,0 → 1,31
/* |
* lib.h -- the library |
*/ |
|
|
#ifndef _LIB_H_ |
#define _LIB_H_ |
|
|
void debugBreak(void); |
|
int strlen(const char *s); |
int strcmp(const char *s, const char *t); |
char *strcpy(char *s, const char *t); |
char *strcat(char *s, const char *t); |
char *strchr(const char *s, char c); |
char *strtok(char *s, const char *t); |
|
unsigned long strtoul(const char *s, char **endp, int base); |
|
void qsort(void *base, int n, int size, |
int (*cmp)(const void *, const void *)); |
|
char getchar(void); |
void putchar(char c); |
|
int printf(const char *fmt, ...); |
int sprintf(char *s, const char *fmt, ...); |
|
|
#endif /* _LIB_H_ */ |
/common.h
0,0 → 1,27
/* |
* common.h -- common definitions |
*/ |
|
|
#ifndef _COMMON_H_ |
#define _COMMON_H_ |
|
|
#define PAGE_SHIFT 12 /* log2 of page size */ |
#define PAGE_SIZE (1 << PAGE_SHIFT) /* page size in bytes */ |
#define OFFSET_MASK (PAGE_SIZE - 1) /* mask for offset in page */ |
#define PAGE_MASK (~OFFSET_MASK) /* mask for page number */ |
|
|
typedef enum { false, true } Bool; /* truth values */ |
|
|
typedef unsigned int Word; /* 32 bit quantities */ |
typedef unsigned short Half; /* 16 bit quantities */ |
typedef unsigned char Byte; /* 8 bit quantities */ |
|
|
#define NULL ((void *) 0) |
|
|
#endif /* _COMMON_H_ */ |