URL
https://opencores.org/ocsvn/s6soc/s6soc/trunk
Subversion Repositories s6soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/s6soc/trunk/sw
- from Rev 27 to Rev 29
- ↔ Reverse comparison
Rev 27 → Rev 29
/zipos/cmodram.ld
58,7 → 58,7
obj-zip/keypad.o(.text) |
obj-zip/display.o(.text) |
obj-zip/rtcsim.o(.text) |
*(.rodata) *(.strings) |
*(.rodata*) *(.strings) |
load_image_start = . ; |
} > flash |
.ramcode : { |
/zipos/doorbell.c
4,7 → 4,16
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: |
// Purpose: This is the user program, or perhaps more appropriately |
// user program(s), associated with running the ZipOS on the |
// CMod-S6. To run within the ZipOS, a user program must implement |
// two functions: kntasks() and kinit(TASKP *). The first one is simple. |
// it simply returns the number of tasks the kernel needs to allocate |
// space for. The second routine needs to allocate space for each task, |
// set up any file descriptors associated with (each) task, and identify |
// the entry point of each task. These are the only two routines |
// associated with user tasks called from kernel space. Examples of each |
// are found within here. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
47,6 → 56,7
|
#include "../dev/display.h" |
#include "../dev/rtcsim.h" |
#include "../dev/keypad.h" |
|
/* Our system will need some pipes to handle ... life. How about these: |
* |
58,9 → 68,8
* lcdpipe - write()s to this pipe write to the LCD display SPI port |
* pwmpipe - write()s to this pipe will send values to the audio port |
* Interrupt consumed |
* cmdpipe - written to by the user command task, read by the display task |
* used to communicate menu status |
* |
* These pipes are allocated within the kernel setup function, ksetup(). |
*/ |
|
/* We'll need some tasks as well: |
108,6 → 117,15
*/ |
// #define KEYPAD_TASK keypad_task_id |
/* |
* Read from the keypad, and set up a series of menu screens on the Display, |
* so that we can: |
* |
* 1. Set time |
* 2. Set dawn |
* 3. Set dusk |
*/ |
#define MENU_TASK menu_task_id |
/* |
* Maintain a realtime clock |
*/ |
#define RTCCLOCK_TASK rtccclock_task_id |
122,12 → 140,6
*/ |
#define DOORBELL_TASK doorbell_task_id |
|
/* |
* Interract with any user commands, such as setting the clock, setting |
* nighttime (when the lights turn on) or setting daytime when only the |
* doorbell rings. |
*/ |
// #define COMMAND_TASK command_task_id |
#define LAST_TASK last_task_id |
|
typedef enum { |
139,8 → 151,11
DOORBELL_TASK, DISPLAY_TASK, |
#endif |
#endif |
#ifdef KEYPAD_TASK |
KEYPAD_TASK, |
//#ifdef KEYPAD_TASK |
//KEYPAD_TASK, |
//#endif |
#ifdef MENU_TASK |
MENU_TASK, |
#endif |
#ifdef COMMAND_TASK |
COMMAND_TASK, |
153,7 → 168,7
doorbell_task(void), |
display_task(void), |
keypad_task(void), |
command_task(void); |
menu_task(void); |
// idle_task ... is accomplished within the kernel |
extern void restore_context(int *), save_context(int *); |
extern SYSPIPE *rxpipe, *txpipe, *pwmpipe, *lcdpipe; |
171,43 → 186,42
#ifdef DOORBELL_TASK |
#ifdef DISPLAY_TASK |
// 13 + 10 +9(uwrite)+4(uarthex)+2(uartstr)+2(uartchr) |
tasklist[DOORBELL_TASK] = new_task(64, doorbell_task); |
tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT] = sys_malloc(sizeof(KFILDES)); |
tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT]->id = (int)lcdpipe; |
tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT]->dev= pipedev; |
tasklist[DOORBELL_TASK]->fd[FILENO_STDERR] = sys_malloc(sizeof(KFILDES)); |
tasklist[DOORBELL_TASK]->fd[FILENO_STDERR]->id = (int)txpipe; |
tasklist[DOORBELL_TASK]->fd[FILENO_STDERR]->dev= pipedev; |
tasklist[DOORBELL_TASK]->fd[FILENO_AUX] = sys_malloc(sizeof(KFILDES)); |
tasklist[DOORBELL_TASK]->fd[FILENO_AUX]->id = (int)pwmpipe; |
tasklist[DOORBELL_TASK]->fd[FILENO_AUX]->dev= pipedev; |
tasklist[DOORBELL_TASK] = new_task(96, doorbell_task); |
// tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT]= kopen((int)lcdpipe,pipedev); |
tasklist[DOORBELL_TASK]->fd[FILENO_STDERR]= kopen((int)txpipe, pipedev); |
tasklist[DOORBELL_TASK]->fd[FILENO_AUX] = kopen((int)pwmpipe, pipedev); |
|
// |
tasklist[DISPLAY_TASK] = new_task(32, display_task); |
tasklist[DISPLAY_TASK]->fd[FILENO_STDIN] = sys_malloc(sizeof(KFILDES)); |
tasklist[DISPLAY_TASK]->fd[FILENO_STDIN]->id = (int)lcdpipe; |
tasklist[DISPLAY_TASK]->fd[FILENO_STDIN]->dev= pipedev; |
tasklist[DISPLAY_TASK]->fd[FILENO_STDIN] = kopen((int)lcdpipe,pipedev); |
#endif |
#endif |
|
|
#ifdef KEYPAD_TASK |
tasklist[KEYPAD_TASK] = new_task(16, keypad_task); |
tasklist[KEYPAD_TASK]->fd[FILENO_STDOUT] = sys_malloc(sizeof(KFILDES)); |
tasklist[NMEA_TASK]->fd[FILENO_STDOUT]->id = (int)keypipe; |
tasklist[NMEA_TASK]->fd[FILENO_STDOUT]->dev= pipedev; |
// Stack = 7 + 9(uwrite) + 2*4 |
tasklist[KEYPAD_TASK] = new_task(32, keypad_task); |
tasklist[KEYPAD_TASK]->fd[FILENO_STDOUT] = kopen((int)keypipe,pipedev); |
#endif |
#ifdef MENU_TASK |
// Stack = 18 + 10(showbell/shownow) + 9(uwrite) + 2(menu_readkey) |
// + 18 (time_menu/dawn_menu/dusk_menu) |
tasklist[MENU_TASK] = new_task(72, menu_task); |
// tasklist[MENU_TASK]->fd[FILENO_STDIN] = kopen((int)keypipe,pipedev); |
tasklist[MENU_TASK]->fd[FILENO_STDOUT]= kopen((int)lcdpipe,pipedev); |
tasklist[MENU_TASK]->fd[FILENO_STDERR]= kopen((int)txpipe, pipedev); |
#endif |
} |
|
#ifdef DOORBELL_TASK |
// #define HALF_HOUR_S 1800 // Seconds per half hour |
// #define HALF_HOUR_S 180 // Seconds per three minutes--for test |
#define HALF_HOUR_S 30 // 3 Mins is to long, here's 3 seconds |
|
#include "../dev/samples.c" |
|
#ifdef MENU_TASK |
unsigned dawn = 0x060000, dusk = 0x180000; |
#else |
const unsigned dawn = 0x060000, dusk = 0x180000; |
int nwritten = 0, nread = 0, nstarts = 0; |
#endif |
|
void shownow(unsigned now) { // Uses 10 stack slots + 8 for write() |
char dmsg[9]; |
252,14 → 266,6
write(FILENO_STDOUT, dmsg, 9); |
} |
|
void belllight(unsigned now) { |
IOSPACE *sys = (IOSPACE *)IOADDR; |
if ((now < dawn)||(now > dusk)) |
sys->io_spio = 0x088; // Turn our light on |
else |
sys->io_spio = 0x80; // Turn light off |
} |
|
void uartchr(char v) { |
if (write(FILENO_STDERR, &v, 1) != 1) |
write(FILENO_STDERR, "APPLE-PANIC", 11); |
282,9 → 288,20
else |
ch += '0'; |
uartchr(ch); |
} uartstr("\r\n\0"); |
} uartstr("\r\n"); |
} |
|
#ifdef DOORBELL_TASK |
#include "../dev/samples.c" |
|
void belllight(unsigned now) { |
IOSPACE *sys = (IOSPACE *)IOADDR; |
if ((now < dawn)||(now > dusk)) |
sys->io_spio = 0x088; // Turn our light on |
else |
sys->io_spio = 0x80; // Turn light off |
} |
|
void doorbell_task(void) { |
// Controls LED 0x08 |
|
293,21 → 310,25
// write(KFD_STDOUT, disp_build_gtlogo, sizeof(disp_build_gtlogo)); |
// write(KFD_STDOUT, disp_reset_data, sizeof(disp_reset_data)); |
// write(KFD_STDOUT, disp_gtech_data, sizeof(disp_gtech_data)); |
|
IOSPACE *sys = (IOSPACE *)IOADDR; |
|
while(1) { |
nread = nwritten = 0; |
int event; |
// Initial state: doorbell is not ringing. In this state, we |
// can wait forever for an event |
sys->io_spio = 0x080; // Turn our light off |
event = wait(INT_BUTTON|SWINT_PPS,-1); |
|
#ifndef MENU_TASK |
unsigned when = rtcclock; |
if (event & INT_BUTTON) |
showbell(when); |
else if (event & SWINT_PPS) |
shownow(when); |
#else |
if (event & INT_BUTTON) |
post(SWINT_DOORBELL); |
#endif |
|
while(event & INT_BUTTON) { |
// Next state, the button has been pressed, the |
326,17 → 347,9
if (len > 256) |
len = 256; |
|
/* |
while(len > 64) { |
write(FILENO_AUX, sptr, 64); |
sptr += 64; |
len -= 64; |
}*/ |
|
// We will stall here, if the audio FIFO is full |
write(FILENO_AUX, sptr, len); |
sptr += len; |
nwritten += len; |
|
// If the user presses the button more than |
// once, we start the sound over as well as |
343,21 → 356,25
// our light counter. |
event = wait(INT_BUTTON|SWINT_PPS, 0); |
if (event&INT_BUTTON) { |
if (sptr > &sound_data[2048]) { |
if (sptr > &sound_data[1024]) { |
sptr = sound_data; |
seconds = 0; |
#ifndef MENU_TASK |
when = (volatile unsigned)rtcclock; |
showbell(when); |
#else |
post(SWINT_DOORBELL); |
#endif |
} |
} else if (event&SWINT_PPS) { |
seconds++; |
belllight(rtcclock); |
#ifndef MENU_TASK |
showbell(when); |
#endif |
} |
} |
|
uartchr('D'); |
|
// Next state: the doorbell is no longer ringing, but |
// we have yet to return to normal--the light is still |
// on. |
365,32 → 382,279
(((event=wait(INT_BUTTON|SWINT_PPS,-1))&INT_BUTTON)==0)) { |
seconds++; |
belllight(rtcclock); |
#ifndef MENU_TASK |
showbell(when); |
#endif |
} |
if (event&INT_BUTTON) { |
#ifndef MENU_TASK |
when = (volatile unsigned)rtcclock; |
showbell(when); |
uartchr('B'); |
#endif |
} |
} |
|
// uartstr("\r\n"); |
uartstr("\r\nNWritten: "); uarthex(nwritten); |
uartstr("NRead : "); uarthex(nread); |
uartstr("NStarts : "); uarthex(nstarts); |
nwritten = nread = nstarts = 0; |
} |
} |
#endif |
|
#ifdef MENU_TASK |
void entered_menu_str(char *str, unsigned now,int pos) { |
// |
// Set current time |
// xx:xx:xx |
// |
str[0] = PACK(0x1b, '[', '1',';'); |
str[1] = PACK('0','H',' ',' '); |
str[2] = PACK(' ','x','x',':'); |
str[3] = PACK('x','x',' ',' '); |
//str[3]=PACK('x','x',':','x'); |
str[4] = PACK(' ','\0','\0','\0'); |
|
if (pos>0) { |
int ch = ((now >> 20)&0x0f)+'0'; |
str[2] &= ~0x0ff0000; |
str[2] |= (ch<<16); |
|
/* |
if (pos > 1) { |
int ch = ((now >> 16)&0x0f)+'0'; |
str[2] &= ~0x0ff00; |
str[2] |= (ch<<8); |
|
if (pos > 2) { |
int ch = ((now >> 12)&0x0f)+'0'; |
str[3] &= ~0xff000000; |
str[3] |= (ch<<24); |
|
NWritten: 000018E7 |
NRead : 000018E7 |
NStarts : 00000001 |
if (pos > 3) { |
int ch = ((now >> 8)&0x0f)+'0'; |
str[3] &= ~0x0ff0000; |
str[3] |= (ch<<16); |
|
if (pos > 4) { |
int ch = ((now >> 4)&0x0f)+'0'; |
str[3] &= ~0x0ff00; |
str[3] |= ':'<<8; |
str[3] &= ~0x0ff; |
str[3] |= (ch); |
|
*/ |
if (pos > 5) |
ch = (now&0x0f)+'0'; |
else |
ch = 'x'; |
str[4] &= ~0x0ff000000; |
str[4] |= (ch<<24); |
}}}}} |
} |
|
void show_time_menu(unsigned when, int posn) { |
char dmsg[10]; |
dmsg[0] = PACK(0x1b,'[','j','S'); |
dmsg[1] = PACK('e','t',' ','c'); |
dmsg[2] = PACK('u','r','r','e'); |
dmsg[3] = PACK('n','t',' ','t'); |
dmsg[4] = PACK('i','m','e',':'); |
entered_menu_str(&dmsg[5], when, posn); |
write(FILENO_STDOUT, dmsg, 9); |
} |
|
void show_dawn_menu(unsigned when, int posn) { |
char dmsg[10]; |
dmsg[0] = PACK(0x1b,'[','j','S'); |
dmsg[1] = PACK('e','t',' ','s'); |
dmsg[2] = PACK('u','n','r','i'); |
dmsg[3] = PACK('s','e',':','\0'); |
entered_menu_str(&dmsg[4], when, posn); |
write(FILENO_STDOUT, dmsg, 8); |
} |
|
void show_dusk_menu(unsigned when, int posn) { |
char dmsg[10]; |
dmsg[0] = PACK(0x1b,'[','j','S'); |
dmsg[1] = PACK('e','t',' ','s'); |
dmsg[2] = PACK('u','n','s','e'); |
dmsg[3] = PACK('t',':','\0','\0'); |
entered_menu_str(&dmsg[4], when, posn); |
write(FILENO_STDOUT, dmsg, 8); |
} |
|
int menu_readkey(void) { |
int key; |
wait(0,3); |
key = keypadread(); |
keypad_wait_for_release(); |
clear(INT_KEYPAD); |
return key; |
} |
|
void time_menu(void) { |
int timeout = 60; |
unsigned newclock = 0; |
for(int p=0; p<6; p++) { |
int key, event; |
show_time_menu(newclock, p); |
do { |
event = wait(SWINT_PPS|INT_KEYPAD,-1); |
if (event&SWINT_PPS) { |
timeout--; |
if (timeout == 0) |
return; |
} if (event&INT_KEYPAD) { |
timeout = 60; |
key = menu_readkey(); |
if ((key >= 0)&&(key < 10)) { |
int sh; |
sh = (5-p)*4; |
newclock &= ~(0x0f<<sh); |
newclock |= (key<<sh); |
} else if (key == 12) { |
if (p>=0) |
p--; |
} else { |
if (p > 4) |
break; |
else |
return; |
} |
} |
} while(0==(event&INT_KEYPAD)); |
} |
|
clear(SWINT_PPS); |
rtcclock = newclock; |
if (wait(SWINT_PPS, 1)) |
rtcclock = newclock; |
} |
|
void dawn_menu(void) { |
int timeout = 60; |
unsigned newdawn = 0; |
for(int p=0; p<6; p++) { |
int key, event; |
show_dawn_menu(newdawn, p); |
do { |
event = wait(SWINT_PPS|INT_KEYPAD,-1); |
if (event&SWINT_PPS) { |
timeout--; |
if (timeout == 0) |
return; |
} if (event&INT_KEYPAD) { |
timeout = 60; |
key = menu_readkey(); |
if ((key >= 0)&&(key < 10)) { |
int sh = (5-p)*4; |
newdawn &= ~(0x0f<<sh); |
newdawn |= key<<sh; |
} else if (key == 12) { |
if (p>=0) |
p--; |
} else { |
if (p > 4) |
break; |
else |
return; |
} |
} |
} while(0 == (event&INT_KEYPAD)); |
} dawn = newdawn; |
} |
|
void dusk_menu(void) { |
int timeout = 60; |
unsigned newdusk = 0; |
for(int p=0; p<6; p++) { |
int key, event; |
show_dusk_menu(newdusk, p); |
do { |
event = wait(SWINT_PPS|INT_KEYPAD,-1); |
if (event&SWINT_PPS) { |
timeout--; |
if (timeout == 0) |
return; |
} if (event&INT_KEYPAD) { |
key = menu_readkey(); |
if ((key >= 0)&&(key < 10)) { |
int sh = (5-p)*4; |
newdusk &= ~(0x0f<<sh); |
newdusk |= key<<sh; |
} else if (key == 12) { |
if (p>=0) |
p--; |
} else { |
if (p > 4) |
break; |
else |
return; |
} |
} |
} while(0 == (event&INT_KEYPAD)); |
} dusk = newdusk; |
} |
|
void unknown_menu(void) { |
// 0123456789ABCDEF |
// Unknown Cmd Key |
// A/Tm B/Dwn C/Dsk |
char dmsg[11]; |
dmsg[0] = PACK(0x1b,'[','j','U'); |
dmsg[1] = PACK('n','k','n','o'); |
dmsg[2] = PACK('w','n',' ','C'); |
dmsg[3] = PACK('m','d',' ','K'); |
dmsg[4] = PACK('e','y','\0','\0'); |
dmsg[5] = PACK(0x1b,'[','1',';'); |
dmsg[6] = PACK('0','H','A','/'); |
dmsg[7] = PACK('T','m',' ','B'); |
dmsg[8] = PACK('/','D','w','n'); |
dmsg[9] = PACK(' ','C','/','D'); |
dmsg[10] = PACK('s','k',0,0); |
write(FILENO_STDOUT, dmsg, 11); |
} |
void menu_task(void) { |
// Controls LED 0x08 |
|
// Start by initializing the display to GT Gisselquist\nTechnology |
// write(KFD_STDOUT, disp_build_backslash,sizeof(disp_build_backslash)); |
// write(KFD_STDOUT, disp_build_gtlogo, sizeof(disp_build_gtlogo)); |
// write(KFD_STDOUT, disp_reset_data, sizeof(disp_reset_data)); |
// write(KFD_STDOUT, disp_gtech_data, sizeof(disp_gtech_data)); |
IOSPACE *sys = (IOSPACE *)IOADDR; |
unsigned belltime = 0, when; |
|
|
when = rtcclock; |
while(1) { |
int event; |
// Initial state: doorbell is not ringing. In this state, we |
// can wait forever for an event |
sys->io_spio = 0x080; // Turn our light off |
event = wait(SWINT_DOORBELL|SWINT_PPS|INT_KEYPAD,-1); |
if (event & SWINT_DOORBELL) { |
showbell(when); |
belltime = time(); |
} else if (event & SWINT_PPS) { |
unsigned now = time(); |
if ((now-belltime)<HALF_HOUR_S) |
showbell(when); |
else { |
when = rtcclock; |
shownow(when); |
} |
} |
|
if (event & INT_KEYPAD) { |
int key; |
key = menu_readkey(); |
switch(key) { |
case 10: time_menu(); |
when = rtcclock; |
break; |
case 11: dawn_menu(); break; |
case 12: dusk_menu(); break; |
default: |
unknown_menu(); |
wait(0,3000); |
} clear(INT_KEYPAD); |
} |
} |
} |
#endif |
|
/zipos/swint.h
50,5 → 50,6
#define SWINT_PPD 0x020000 |
#define SWINT_ALARM 0x040000 |
#define SWINT_CLOCK 0x080000 |
#define SWINT_DOORBELL 0x100000 |
|
#endif |
/zipos/ksetup.c
6,7 → 6,7
// |
// Purpose: These are the routines from kernel.c that didn't need to be |
// in RAM memory. They are specifically the pre-run setup |
// routines. |
// routines that are executed from FLASH memory. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
58,6 → 58,7
|
int LAST_TASK; |
|
__attribute__((cold)) |
TASKP *ksetup(void) { |
TASKP *tasklist; |
IOSPACE *sys = (IOSPACE *)IOADDR; |
78,7 → 79,7
txpipe = new_syspipe(8); txpipe->m_rdtask = INTERRUPT_READ_TASK; |
keypipe = new_syspipe(16); |
lcdpipe = new_syspipe(16); |
pwmpipe = new_syspipe(256); pwmpipe->m_rdtask= INTERRUPT_READ_TASK; |
pwmpipe = new_syspipe(128); pwmpipe->m_rdtask= INTERRUPT_READ_TASK; |
cmdpipe = new_syspipe(16); |
|
tasklist = sys_malloc(sizeof(TASKP)*(1+LAST_TASK)); |
112,12 → 113,14
sys->io_spio = 0x0f7; |
} |
|
// __attribute__((noreturn)) |
void kuserexit(int a) { |
syscall(TRAPID_EXIT, a, 0, 0); |
} |
|
__attribute__((malloc)) |
void *sys_malloc(int sz) { |
{ |
if (0) { |
SCOPE *s = (SCOPE *)SCOPEADDR; |
s->s_control = TRIGGER_SCOPE_NOW | (s->s_control & 0x0ffff); |
} |
132,3 → 135,9
return res; |
} |
|
KFILDES *kopen(int id, KDEVICE *dev) { |
KFILDES *fd = (KFILDES *)sys_malloc(sizeof(KFILDES)); |
fd->id = (int)id; |
fd->dev= dev; |
return fd; |
} |
/zipos/kernel.c
72,8 → 72,6
|
int LAST_TASK; |
|
extern int nwritten, nread, nstarts; |
|
void kernel_entry(void) { |
int nheartbeats= 0, tickcount = 0, milliseconds=0, ticks = 0; |
int audiostate = 0, buttonstate = 0; |
183,7 → 181,6
} else if (kpop_syspipe(pwmpipe, &v)==0) { |
audiostate = (2|(v<<2))&0x03ffff; |
sys->io_pwm_audio = (v>>16)&0x0ffff; |
nread++; |
} else { |
audiostate = 0; |
// Turn the device off |
203,8 → 200,6
}} else { // if (audiostate == 0) |
int sample; |
if (kpop_syspipe(pwmpipe, &sample)==0) { |
nstarts++; |
nread++; |
audiostate = (2|(sample<<2))&0x03ffff; |
sys->io_pwm_audio = 0x310000 | ((sample>>16)&0x0ffff); |
enableset |= (INT_ENABLEV(INT_AUDIO)); |
211,7 → 206,8
sys->io_spio = 0x022; |
sys->io_pic = INT_AUDIO; |
} // else sys->io_spio = 0x020; |
} milliseconds = kpost(tasklist, pic, milliseconds); |
} |
milliseconds = kpost(tasklist, pic, milliseconds); |
|
// Restart interrupts |
enableset &= (~0x0ffff); // Keep the bottom bits off |
229,8 → 225,6
sys->io_pic = INT_AUDIO; |
enableset |= (INT_ENABLEV(INT_AUDIO)); |
sys->io_spio = 0x022; |
nstarts++; |
nread++; |
} // else sys->io_spio = 0x020; |
|
// Or the beginning of a transmit pipe. |
326,10 → 320,11
else { kpanic(); zip_halt(); } |
if ((!fd)||(!fd->dev)) |
last_context[1] = -EBADF; |
else |
else { |
fd->dev->write(current, fd->id, |
(void *)last_context[3], last_context[4]); |
} break; |
}} |
break; |
case TRAPID_TIME: |
last_context[1] = tickcount; |
break; |
392,11 → 387,12
} |
|
// Now let's see if we can find the next ready task to run |
for(; nxtid<LAST_TASK; nxtid++) |
for(; nxtid<LAST_TASK; nxtid++) { |
if (tasklist[nxtid]->state == SCHED_READY) { |
current=tasklist[nxtid]; |
break; |
} |
} |
// The last task (the idle task) doesn't count |
if (nxtid >= LAST_TASK) { |
nxtid = 0; // Don't automatically run idle task |
406,8 → 402,7
} |
// Now we stop at the idle task, if nothing else is ready |
current = tasklist[nxtid]; |
} |
return current; |
} return current; |
} |
|
int kpost(TASKP *tasklist, unsigned events, int milliseconds) { |
/zipos/kfildes.h
68,4 → 68,6
#define NULL (void *)0 |
#endif |
|
KFILDES *kopen(int id, KDEVICE *dev); |
|
#endif |
/zipos/Makefile
73,6 → 73,9
$(OBJDIR)/%.s: %.c |
$(CC) -S $(CFLAGS) -c $< -o $@ |
|
$(OBJDIR)/%.s: ../dev/%.c |
$(CC) -S $(CFLAGS) -c $< -o $@ |
|
$(OBJDIR)/resetdump.o: resetdump.s |
$(AS) $^ -o $@ |
|
/dev/keypad.h
0,0 → 1,46
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: keypad.h |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: A device driver (task) for the 16 character keypad. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#ifndef KEYPAD_H |
#define KEYPAD_H |
extern int keypadread(void); |
extern void keypad_wait_for_release(void); |
|
#ifdef ZIPOS |
extern void keypad_task(void); |
#endif |
#endif |
/dev/kptest.c
0,0 → 1,93
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: kptest.c |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: To test and demonstrate that the keypad works. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include "asmstartup.h" |
#include "board.h" |
#include "keypad.h" |
|
void txchr(char v) { |
volatile IOSPACE *sys = (IOSPACE *)IOADDR; |
if (v < 10) |
return; |
v &= 0x07f; |
sys->io_pic = INT_UARTTX; |
while((sys->io_pic&INT_UARTTX)==0) |
; |
sys->io_uart = v; |
} |
|
void txstr(const char *str) { |
const char *ptr = str; |
while(*ptr) { |
txchr(*ptr++); |
} |
} |
|
void entry(void) { |
register IOSPACE *sys = (IOSPACE *)0x0100; |
|
sys->io_pic = 0x07fffffff; // Acknowledge and turn off all interrupts |
sys->io_spio = 0x0f0; |
sys->io_tima = 100000 | TM_REPEAT; |
|
txstr("Press any keypad button for test.\r\n"); |
|
while(1) { |
int ch; |
while(0 == (sys->io_pic & INT_KEYPAD)) |
; |
sys->io_pic = INT_KEYPAD | INT_TIMA; |
// Wait 5 ms |
for(int i=0; i<5; i++) { |
while(0 == (sys->io_pic & INT_TIMA)) |
; |
} |
sys->io_spio = 0x011; |
ch = keypadread(); |
if (ch < 0) |
; // txstr("Unknown key pressed or error\n"); |
else if (ch < 10) |
txchr(ch+'0'); |
else if (ch == 15) |
txstr("F\r\n"); |
else if (ch < 15) |
txchr(ch+'A'-10); |
else txstr("Unknown key pressed\n"); |
keypad_wait_for_release(); |
sys->io_spio = 0x010; |
} |
} |
/dev/Makefile
46,7 → 46,7
## |
## |
all: |
PROGRAMS := helloworld |
PROGRAMS := helloworld doorbell doorbell2 kptest |
all: $(OBJDIR)/ $(PROGRAMS) |
|
|
61,7 → 61,7
# Not for build, for for building tags and dependency files, we need to know |
# what the sources and headers are |
DEVDRVR:= keypad.c display.c rtcsim.c |
SOURCES:= helloworld.c doorbell.c doorbell2.c $(DEVDRVR) |
SOURCES:= helloworld.c doorbell.c doorbell2.c kptest.c $(DEVDRVR) |
HEADERS:= board.h |
# OBJECTS:= $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(SOURCES))) |
OBJDRVR := $(addprefix $(OBJDIR)/,$(subst .c,.o,$(DEVDRVR))) |
96,6 → 96,11
$(OBJDIR)/doorbell2.txt: doorbell2 |
$(OBJDUMP) -dr $^ > $@ |
|
kptest: $(OBJDIR)/ $(OBJDIR)/kptest.o $(OBJDRVR) cmod.ld |
$(CC) $(LDFLAGS) $(OBJDIR)/kptest.o $(OBJDRVR) -o $@ |
$(OBJDIR)/kptest.txt: kptest |
$(OBJDUMP) -dr $^ > $@ |
|
define build-depends |
@echo "Building dependency file(s)" |
$(CC) $(CPPFLAGS) -MM $(SOURCES) > $(OBJDIR)/xdep.txt |
/dev/keypad.c
0,0 → 1,138
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: keypad.c |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: A device driver (task) for the 16 character keypad. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include "board.h" |
#ifdef ZIPOS |
#include "../zipos/ktraps.h" |
#include "../zipos/kfildes.h" |
#endif |
|
static const int keymap[] = { |
0x01,0x02,0x03,0x0a, |
0x04,0x05,0x06,0x0b, |
0x07,0x08,0x09,0x0c, |
0x00,0x0f,0x0e,0x0d |
}; |
|
int keypadread(void) { |
int row, col, key; |
IOSPACE *sys = (IOSPACE *)IOADDR; |
|
row = sys->io_spio & 0x0f00; |
if (row != 0x0f00) { |
// If a button is still pressed .. |
// |
// Check columns one and two to see if they were responsible |
// for the button |
sys->io_spio = 0x0cf00; |
// Get the result |
col = sys->io_spio; |
if ((col&0x0f00)!=0x0f00) { |
// Column one or two is pressed |
sys->io_spio = 0x0ef00; |
col = sys->io_spio; |
if ((col&0x0f00)!=0x0f00) |
col = 0; |
else |
col = 1; |
} else { |
// Must be column three or four |
sys->io_spio = 0x7f00; |
col = sys->io_spio; |
if ((col & 0x0f00)!= 0x0f00) // Column 4 |
col = 3; |
else |
col = 2; |
} sys->io_spio = 0x0f00; // Reset column pins to zero |
if (row == (int)(sys->io_spio & 0x0f00)) { |
// The key didn't change, so we might have something |
row >>= 8; |
row &= 0x0f; |
row ^= 0x0f; |
|
// Found the pin |
if (row == 1) |
row=0; |
else if (row == 2) |
row = 1; |
else if (row == 4) |
row = 2; |
else if (row == 8) |
row = 3; |
else |
// Two or more buttons were pressed |
// -- declare an error |
row = -1; |
|
if (row>=0) { |
key = (row |(col<<2)); |
key = keymap[key]; |
} else key = -1; |
} else key = -1; |
} else key = -1; |
|
if (sys->io_pic & INT_ENABLE) |
sys->io_pic = INT_ENABLE|INT_KEYPAD; |
else sys->io_pic = INT_KEYPAD; |
|
return key; |
} |
|
void keypad_wait_for_release(void) { |
IOSPACE *sys = (IOSPACE *)IOADDR; |
sys->io_spio = 0x0f00; |
while((sys->io_spio & 0x0f00)!=0x0f00) |
#ifdef ZIPOS |
wait(0,2); |
#else |
; |
#endif |
} |
|
#ifdef ZIPOS |
void keypad_task(void) { |
clear(INT_KEYPAD); |
while(1) { |
int key; |
wait(INT_KEYPAD,-1); // Automatically clears |
key = keypadread(); |
write(FILENO_STDOUT, &key, 1); |
// Prepare for the next key |
clear(INT_KEYPAD); |
} |
} |
#endif |