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/zipos
- from Rev 44 to Rev 45
- ↔ Reverse comparison
Rev 44 → Rev 45
/Makefile
42,49 → 42,56
AS := $(CROSS)as |
OBJDUMP := $(CROSS)objdump |
OBJDIR := obj-zip |
DEVSRCSR:= display.c keypad.c rtcsim.c |
DEVSRCSR:= display.c keypad.c rtcsim.c txfns.c |
DEVSRCS := $(addprefix ../dev/,$(DEVSRCSR)) |
DEVOBJS := $(addprefix $(OBJDIR)/,$(subst .c,.o,$(DEVSRCSR))) |
SOURCES := bootloader.c kernel.c ksetup.c syspipe.c pipesetup.c taskp.c doorbell.c zipsys.c # ziplib.c |
SOURCES := bootloader.c kernel.c ksetup.c syspipe.c pipesetup.c taskp.c doorbell.c zipsys.c string.c # ziplib.c |
OBJECTS := $(addprefix $(OBJDIR)/,$(subst .c,.o,$(SOURCES))) $(DEVOBJS) $(OBJDIR)/resetdump.o |
HEADERS := $(wildcard *.h) $(subst .c,.h,$(DEVSRCS)) |
# CFLAGS := -O3 -fdump-tree-all -Wall -Wextra -nostdlib -fno-builtin |
# CFLAGS := -O3 -fdump-rtl-all -DZIPOS -Wall -Wextra -nostdlib -fno-builtin |
CFLAGS := -O3 -DZIPOS -Wall -Wextra -nostdlib -fno-builtin |
# CFLAGS := -Wall -Wextra -nostdlib -fno-builtin |
LDFLAGS := -T cmodram.ld -Wl,-Map,$(OBJDIR)/doorbell.map |
CFLAGS := -I. -I../dev -Os -DZIPOS -Wall -Wextra -nostdlib -fno-builtin -Wa,-nocis |
LDFLAGS := -T cmodram.ld -Wl,-Map,$(OBJDIR)/doorbell.map -nostdlib |
|
all: $(OBJDIR)/ doorbell |
all: doorbell |
$(OBJDIR)/: |
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi" |
$(mk-objdir) |
|
%.o: $(OBJDIR)/%.o |
$(CC) $(CFLAGS) -c $< -o $@ |
|
$(OBJDIR)/%.o: %.c |
$(mk-objdir) |
$(CC) $(CFLAGS) -c $< -o $@ |
|
$(OBJDIR)/%.o: ../dev/%.c |
$(mk-objdir) |
$(CC) $(CFLAGS) -c $< -o $@ |
|
$(OBJDIR)/%.txt: $(OBJDIR)/%.o |
$(OBJDUMP) -d $^ -o $@ |
$(OBJDUMP) -Dr $^ > $@ |
|
$(OBJDIR)/%.s: %.c |
$(mk-objdir) |
$(CC) -S $(CFLAGS) -c $< -o $@ |
|
$(OBJDIR)/%.s: ../dev/%.c |
$(mk-objdir) |
$(CC) -S $(CFLAGS) -c $< -o $@ |
|
$(OBJDIR)/resetdump.o: resetdump.s |
$(AS) $^ -o $@ |
$(mk-objdir) |
$(AS) -nocis $^ -o $@ |
|
doorbell: $(OBJECTS) cmodram.ld |
$(CC) $(LDFLAGS) $(OBJECTS) -o $@ |
|
$(OBJDIR)/doorbell.txt: doorbell |
doorbell.txt: doorbell |
$(OBJDUMP) -d $^ > $@ |
|
define mk-objdir |
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi" |
endef |
|
define build-depends |
@echo "Building dependency file(s)" |
@$(CC) $(CPPFLAGS) -MM $(SOURCES) $(DEVSRCS) > $(OBJDIR)/xdepends.txt |
93,7 → 100,8
endef |
|
.PHONY: depends |
depends: $(OBJDIR)/ tags |
depends: tags |
$(mk-objdir) |
$(build-depends) |
|
tags: $(SOURCES) $(HEADERS) |
/board.h
59,9 → 59,8
#define INT_BUTTON 0x001 |
#define INT_BUSERR 0x002 // Kind of useless, a buserr will kill us anyway |
#define INT_SCOPE 0x004 |
#define INT_RTC 0x008 // May not be available, due to lack of space |
#define INT_TIMA 0x010 |
#define INT_TIMB 0x020 |
#define INT_TIMER 0x010 |
//#define INT_WATCHDOG 0x020 // Catching a watchdog/reset interrupt makes no sense |
#define INT_UARTRX 0x040 |
#define INT_UARTTX 0x080 |
#define INT_KEYPAD 0x100 |
71,6 → 70,8
#define INT_ENABLEV(IN) (INT_ENABLE|((IN)<<16)) |
#define INT_DISABLEV(IN) ((IN)<<16) |
#define INT_CLEAR(IN) (IN) |
#define INT_CLEARPIC 0x7fff7fff |
#define INT_DALLPIC 0x7fff0000 |
|
// Clocks per second, for use with the timer |
#define TM_ONE_SECOND 80000000 |
77,50 → 78,46
#define TM_REPEAT 0x80000000 |
|
typedef struct { |
volatile int io_pic; |
volatile unsigned *io_buserr; |
volatile int io_tima, io_timb; |
volatile unsigned io_pwm_audio; |
volatile unsigned io_spio; // aka keypad, buttons, and keyboard |
volatile unsigned io_gpio; |
volatile unsigned io_uart; |
volatile unsigned io_version; |
int io_pic; |
unsigned *io_buserr; |
int io_timer, io_watchdog; |
unsigned io_pwm_audio; |
unsigned io_spio; // aka keypad, buttons, and keyboard |
unsigned io_gpio; |
unsigned io_uart; |
unsigned io_version; |
} IOSPACE; |
|
// Wishbone scope control |
#define TRIGGER_SCOPE_NOW 0x88000000 |
#define SCOPE_IS_STOPPED 0x40000000 |
#define DISABLE_TRIGGER 0x84000000 |
typedef struct { |
volatile unsigned s_control, s_data; |
} SCOPE; |
|
typedef struct { |
volatile unsigned f_crc, f_far_maj, f_far_min, f_fdri, |
f_fdro, f_cmd, f_ctl, f_mask, |
f_stat, f_lout, f_cor1, f_cor2, |
f_pwrdn, f_flr, f_idcode, f_cwdt, |
f_hcopt, f_csbo, f_gen1, f_gen2, |
f_gen3, f_gen4, f_gen5, f_mode, |
f_gwe, f_mfwr, f_cclk, f_seu, f_exp, f_rdbk, |
f_bootsts, f_eye, f_cbc; |
} FPGACONFIG; |
#define WBSCOPE_NO_RESET 0x80000000 |
#define WBSCOPE_MANUAL WBSCOPE_TRIGGER |
// |
#define WBSCOPE_STOPPED 0x40000000 |
#define WBSCOPE_TRIGGERED 0x20000000 |
#define WBSCOPE_PRIMED 0x10000000 |
#define WBSCOPE_TRIGGER (0x08000000|WBSCOPE_NO_RESET) |
#define WBSCOPE_DISABLED 0x04000000 |
#define WBSCOPE_DISABLE 0x04000000 // Disable the scope trigger |
#define WBSCOPE_RZERO 0x02000000 // Unused,true if ptd at begning |
#define WBSCOPE_LGLEN(A) ((A>>20)&0x01f) |
#define WBSCOPE_LENGTH(A) (1<<(WBSCOPE_LGLEN(A))) |
|
typedef struct { |
volatile unsigned c_clock, c_timer, c_stopwatch, c_alarm; |
} RTCCLOCK; |
typedef struct WBSCOPE_S { |
unsigned s_ctrl, s_data; |
} WBSCOPE; |
|
#define IOADDR 0x000100 |
#define SCOPEADDR 0x000200 |
// #define FCTLADDR 0x000300 // Flash control, depends upon write capability |
#define CONFIGADDR 0x000400 |
// #define RTCADDR 0x000800 // Disabled for lack of space on device |
#define RAMADDR 0x002000 |
#define RAMSZ 0x001000 |
#define FLASHADDR 0x400000 |
#define RESET_ADDR 0x480000 |
#define FLASHSZ 0x400000 |
#define IOADDR 0x000400 |
#define SCOPEADDR 0x000800 |
// #define FCTLADDR 0x000c00 // Flash control, depends upon write capability |
#define RAMADDR 0x004000 |
#define RAMSZ (RAMADDR) |
#define FLASHADDR 0x1000000 |
#define RESET_ADDR 0x1200000 |
#define FLASHSZ (FLASHADDR) |
|
static volatile IOSPACE *const _sys = (IOSPACE *)IOADDR; |
static volatile WBSCOPE *const _scope = (WBSCOPE *)SCOPEADDR; |
|
#define valid_ram_region(PTR,LN) (((int)(PTR)>=RAMADDR)&&((int)(PTR+LN)<RAMADDR+RAMSZ)) |
#define valid_flash_region(PTR,LN) (((int)(PTR)>=FLASHADDR)&&((int)(PTR+LN)<FLASHADDR+FLASHSZ)) |
#define valid_mem_region(PTR,LN) ((valid_ram_region(PTR,LN))||(valid_flash_region(PTR,LN))) |
/bootloader.c
38,22 → 38,24
// |
// |
#include "board.h" |
#include "bootloader.h" |
|
// These values will be filled in by the linker. They are unknown at compile |
// time. |
extern int load_image_start, load_image_end, bss_image_end; |
|
void bootloader(void) { |
int len = ((int)&load_image_end) - RAMADDR; |
int *flash = &load_image_start; |
int *mem = (int *)RAMADDR; |
void _bootloader(void) __attribute__ ((section(".boot"))); |
|
for(int i=0; i<len; i++) |
mem[i] = flash[i]; |
void _bootloader(void) { |
int *flash = _kernel_image_start; |
int *mem = _blkram; |
|
while(mem < _kernel_image_end) |
*mem++ = *flash++; |
|
// While I'd love to continue and clear to the end of memory, doing |
// so will corrupt my stack and perhaps even my return address. Hence |
// we only do this much. |
for(int i=len; i< ((int)&bss_image_end)-RAMADDR; i++) |
mem[i] = 0; |
while(mem < _bss_image_end) |
*mem++ = 0; |
} |
|
/cmod.ld
34,18 → 34,38
|
MEMORY |
{ |
blkram (wx) : ORIGIN = 0x002000, LENGTH = 0x001000 |
flash (rx) : ORIGIN = 0x400000, LENGTH = 0x400000 |
blkram (wx) : ORIGIN = 0x0004000, LENGTH = 0x0004000 |
flash (rx) : ORIGIN = 0x1000000, LENGTH = 0x1000000 |
} |
|
_top_of_stack = ORIGIN(blkram) + LENGTH(blkram) - 1; |
_flash = ORIGIN(flash); |
_blkram = ORIGIN(blkram); |
_sdram = 0; |
_top_of_stack = ORIGIN(blkram) + LENGTH(blkram) - 4; |
_sdram_image_start = 0; |
_sdram_image_end = 0; |
|
SECTIONS |
{ |
. = 0x0480000; |
.rocode 0x0480000 : { *(.start) *(.text) |
*(.rodata) |
*(.strings) } > flash |
.data : { *(.fixdata) *(.data) *(COMMON) *(.bss) } > blkram |
_top_of_heap = .; |
.rocode 0x1200000 : { |
_boot_address = .; |
*(.start) *(.boot) |
*(.text*) |
*(.rodata*) |
*(.strings*) |
} > flash |
_kernel_image_start = . ; |
.data : { |
*(.kernel*) |
*(.fixdata*) |
*(.data*) |
*(COMMON*) |
_kernel_image_end = . ; |
}> blkram AT> flash |
_blkram_image_end = . ; |
.bss : { |
*(.bss*) |
_bss_image_end = . ; |
} > blkram |
_top_of_heap = .; |
} |
/cmodram.ld
40,34 → 40,51
|
MEMORY |
{ |
blkram (wx) : ORIGIN = 0x002000, LENGTH = 0x001000 |
flash (rx) : ORIGIN = 0x400000, LENGTH = 0x400000 |
blkram (wx) : ORIGIN = 0x0004000, LENGTH = 0x0004000 |
flash (rx) : ORIGIN = 0x1000000, LENGTH = 0x1000000 |
} |
|
_top_of_stack = ORIGIN(blkram) + LENGTH(blkram) - 1; |
_flash = ORIGIN(flash); |
_blkram = ORIGIN(blkram); |
_sdram = 0; |
_top_of_stack = ORIGIN(blkram) + LENGTH(blkram) - 4; |
_sdram_image_start = 0; |
_sdram_image_end = 0; |
|
SECTIONS |
{ |
. = 0x0480000; |
.rocode 0x0480000 : { *(.start) |
.rocode 0x1200000 : ALIGN(4) { |
_boot_address = .; |
*(.start) *(.boot) |
obj-zip/bootloader.o(.text) |
obj-zip/ksetup.o(.text) |
obj-zip/pipesetup.o(.text) |
obj-zip/taskp.o(.text) |
obj-zip/doorbell.o(.text) |
obj-zip/keypad.o(.text) |
obj-zip/display.o(.text) |
obj-zip/rtcsim.o(.text) |
*(.rodata*) *(.strings) |
load_image_start = . ; |
} > flash |
.ramcode : { |
obj-zip/kernel.o(.text) |
obj-zip/syspipe.o(.text) |
obj-zip/keypad.o(.text*) |
obj-zip/display.o(.text*) |
obj-zip/rtcsim.o(.text*) |
obj-zip/doorbell.o(.text*) |
*(.rodata*) |
*(.strings*) |
__rocode_alignment = (. + 3) & ~ 3; |
. = __rocode_alignment; |
} > flash |
_kernel_image_start = . ; |
.ramcode : ALIGN_WITH_INPUT { |
obj-zip/kernel.o(.text*) |
obj-zip/syspipe.o(.text*) |
} > blkram AT> flash |
.data : { *(.fixdata) *(.data) *(COMMON) |
load_image_end = . ; |
} > blkram AT> flash |
.bss : { *(.bss) bss_image_end = . ; } > blkram |
_top_of_heap = .; |
.data : ALIGN_WITH_INPUT { |
*(.kernel*) |
*(.fixdata*) |
*(.data*) |
*(COMMON*) |
_kernel_image_end = . ; |
}> blkram AT> flash |
_blkram_image_end = . ; |
.bss : ALIGN_WITH_INPUT { |
*(.bss*) |
_bss_image_end = . ; |
} > blkram |
_top_of_heap = .; |
} |
/doorbell.c
53,11 → 53,18
#include "ktraps.h" |
#include "errno.h" |
#include "swint.h" |
#include "txfns.h" |
|
#include "../dev/display.h" |
#include "../dev/rtcsim.h" |
#include "../dev/keypad.h" |
|
typedef unsigned size_t; |
|
size_t strlen(const char *); |
char *strcat(char *, const char *); |
char *strcpy(char *, const char *); |
|
/* Our system will need some pipes to handle ... life. How about these: |
* |
* rxpipe - read()s from this pipe read from the UART |
140,6 → 147,14
*/ |
#define DOORBELL_TASK doorbell_task_id |
|
|
/* |
* Just print Hello World every 15 seconds or so. This is really a test of the |
* write() and txpipe infrastructure, but not really a valid part of the task. |
* |
*/ |
// #define HELLO_TASK hello_task_id |
|
#define LAST_TASK last_task_id |
|
typedef enum { |
157,8 → 172,8
#ifdef MENU_TASK |
MENU_TASK, |
#endif |
#ifdef COMMAND_TASK |
COMMAND_TASK, |
#ifdef HELLO_TASK |
HELLO_TASK, |
#endif |
LAST_TASK |
} TASKNAME; |
168,7 → 183,8
doorbell_task(void), |
display_task(void), |
keypad_task(void), |
menu_task(void); |
menu_task(void), |
hello_task(void); |
// idle_task ... is accomplished within the kernel |
extern void restore_context(int *), save_context(int *); |
extern SYSPIPE *rxpipe, *txpipe, *pwmpipe, *lcdpipe; |
179,20 → 195,20
return LAST_TASK; |
} void kinit(TASKP *tasklist) { |
#ifdef RTCCLOCK_TASK |
// |
tasklist[RTCCLOCK_TASK] = new_task(16, rtctask); |
// Stack = 36 (rtctask) + 4(rtcdatenext) |
tasklist[RTCCLOCK_TASK] = new_task(64, rtctask); |
#endif |
|
#ifdef DOORBELL_TASK |
#ifdef DISPLAY_TASK |
// 13 + 10 +9(uwrite)+4(uarthex)+2(uartstr)+2(uartchr) |
tasklist[DOORBELL_TASK] = new_task(96, doorbell_task); |
// Stack = 36 + 36 (uread/write) + 24(memcpy) + 32(uarthex)+8(uartchr) |
tasklist[DOORBELL_TASK] = new_task(256, 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); |
// Stack = 16 + 36(uread/write) + 24(memcpy) |
tasklist[DISPLAY_TASK] = new_task(128, display_task); |
tasklist[DISPLAY_TASK]->fd[FILENO_STDIN] = kopen((int)lcdpipe,pipedev); |
#endif |
#endif |
199,18 → 215,27
|
|
#ifdef KEYPAD_TASK |
// Stack = 7 + 9(uwrite) + 2*4 |
tasklist[KEYPAD_TASK] = new_task(32, keypad_task); |
// Stack = 28 + 36(uwrite) + 24(memcpy) = 88 bytes |
tasklist[KEYPAD_TASK] = new_task(128, 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); |
// Stack = 76 + 48(showbell/shownow) |
// + 36(uwrite) |
// + 8(menu_readkey) |
// + 24(memcpy) |
// +100(time_menu/dawn_menu/dusk_menu) |
// |
tasklist[MENU_TASK] = new_task(512, 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 HELLO_TASK |
tasklist[HELLO_TASK] = new_task(512, hello_task); |
tasklist[HELLO_TASK]->fd[FILENO_STDOUT]= kopen((int)txpipe,pipedev); |
#endif |
} |
|
// #define HALF_HOUR_S 1800 // Seconds per half hour |
223,60 → 248,58
const unsigned dawn = 0x060000, dusk = 0x180000; |
#endif |
|
void shownow(unsigned now) { // Uses 10 stack slots + 8 for write() |
char dmsg[9]; |
dmsg[0] = PACK(0x1b,'[','j','T'); |
dmsg[1] = PACK('i','m','e',':'); |
dmsg[2] = PACK(' ',((now>>20)&0x3)+'0', |
((now>>16)&0xf)+'0',':'); |
dmsg[3] = PACK( ((now>>12)&0xf)+'0', |
((now>> 8)&0xf)+'0', |
':', |
((now>> 4)&0xf)+'0'); |
dmsg[4] = PACK( ((now )&0xf)+'0', |
0x1b, '[', '1'); |
dmsg[5] = PACK(';','0','H',' '); |
const char basemsg[] = "\e[jTime: xx:xx:xx\e[1;0H "; |
const char nighttime[] = "Night time"; |
const char daylight[] = "Daylight!"; |
const char dbellstr[] = "Doorbell!"; |
void shownow(unsigned now) { |
char dmsg[40]; |
strcpy(dmsg, basemsg); |
|
dmsg[ 9] = ((now>>20)&0x0f)+'0'; |
dmsg[10] = ((now>>16)&0x0f)+'0'; |
// |
dmsg[12] = ((now>>12)&0x0f)+'0'; |
dmsg[13] = ((now>> 8)&0x0f)+'0'; |
// |
dmsg[15] = ((now>> 4)&0x0f)+'0'; |
dmsg[16] = ((now )&0x0f)+'0'; |
|
if ((now < dawn)||(now > dusk)) { |
dmsg[6] = PACK('N','i','g','h'); |
dmsg[7] = PACK('t',' ','t','i'); |
dmsg[8] = PACK('m','e',0,0); |
strcat(dmsg, nighttime); |
} else { |
dmsg[6] = PACK('D','a','y','l'); |
dmsg[7] = PACK('i','g','h','t'); |
dmsg[8] = PACK('!',' ',0,0); |
} write(FILENO_STDOUT, dmsg, 9); |
strcat(dmsg, daylight); |
} write(FILENO_STDOUT, dmsg, strlen(dmsg)); |
} |
|
void showbell(unsigned now) { // Uses 10 stack slots + 8 for write() |
char dmsg[9]; |
dmsg[0] = PACK(0x1b,'[','j','T'); |
dmsg[1] = PACK('i','m','e',':'); |
dmsg[2] = PACK(' ',((now>>20)&0x3)+'0', |
((now>>16)&0xf)+'0',':'); |
dmsg[3] = PACK( ((now>>12)&0xf)+'0', |
((now>> 8)&0xf)+'0', |
':', |
((now>> 4)&0xf)+'0'); |
dmsg[4] = PACK( ((now )&0xf)+'0', |
0x1b, '[', '1'); |
dmsg[5] = PACK(';','0','H',' '); |
dmsg[6] = PACK('D','o','o','r'); |
dmsg[7] = PACK('b','e','l','l'); |
dmsg[8] = PACK('!',' ',0,0); |
write(FILENO_STDOUT, dmsg, 9); |
char dmsg[40]; |
|
strcpy(dmsg, basemsg); |
|
dmsg[ 9] = ((now>>20)&0x0f)+'0'; |
dmsg[10] = ((now>>16)&0x0f)+'0'; |
// |
dmsg[12] = ((now>>12)&0x0f)+'0'; |
dmsg[13] = ((now>> 8)&0x0f)+'0'; |
// |
dmsg[15] = ((now>> 4)&0x0f)+'0'; |
dmsg[16] = ((now )&0x0f)+'0'; |
|
strcat(dmsg, dbellstr); |
write(FILENO_STDOUT, dmsg, strlen(dmsg)); |
} |
|
void uartchr(char v) { |
if (write(FILENO_STDERR, &v, 1) != 1) |
write(FILENO_STDERR, "APPLE-PANIC", 11); |
write(FILENO_STDERR, "APPLE-PANIC\r\n", 13); |
} |
|
void uartstr(const char *str) { |
int cnt=0; |
while(str[cnt]) |
cnt++; |
int cnt; |
cnt = strlen(str); |
if (cnt != write(FILENO_STDERR, str, cnt)) |
write(FILENO_STDERR, "PIPE-PANIC", 10); |
write(FILENO_STDERR, "PIPE-PANIC\r\n", 12); |
} |
|
void uarthex(int num) { |
295,11 → 318,10
#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 |
_sys->io_spio = 0x088; // Turn our light on |
else |
sys->io_spio = 0x80; // Turn light off |
_sys->io_spio = 0x80; // Turn light off |
} |
|
void doorbell_task(void) { |
310,13 → 332,12
// 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) { |
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 |
_sys->io_spio = 0x080; // Turn our light off |
event = wait(INT_BUTTON|SWINT_PPS,-1); |
|
#ifndef MENU_TASK |
340,15 → 361,15
|
// Check time: should we turn our light on or not? |
belllight((volatile unsigned)rtcclock); |
const int *sptr = sound_data; |
// uartchr('N'); |
const short *sptr = sound_data; |
while(sptr < &sound_data[NSAMPLE_WORDS]) { |
int len = &sound_data[NSAMPLE_WORDS]-sptr; |
if (len > 256) |
len = 256; |
if (len > 512) |
len = 512; |
|
// We will stall here, if the audio FIFO is full |
write(FILENO_AUX, sptr, len); |
write(FILENO_AUX, sptr, |
sizeof(sound_data[0])*len); |
sptr += len; |
|
// If the user presses the button more than |
398,83 → 419,65
#endif |
|
#ifdef MENU_TASK |
const char menustr[] = "\e[1;0H : "; |
|
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'); |
|
strcpy(str, menustr); |
if (pos>0) { |
int ch = ((now >> 20)&0x0f)+'0'; |
str[2] &= ~0x0ff0000; |
str[2] |= (ch<<16); |
str[9] = ch; |
|
if (pos > 1) { |
int ch = ((now >> 16)&0x0f)+'0'; |
str[2] &= ~0x0ff00; |
str[2] |= (ch<<8); |
ch = ((now >> 16)&0x0f)+'0'; |
str[10] = ch; |
|
if (pos > 2) { |
int ch = ((now >> 12)&0x0f)+'0'; |
str[3] &= ~0xff000000; |
str[3] |= (ch<<24); |
ch = ((now >> 12)&0x0f)+'0'; |
str[12] = ch; |
|
if (pos > 3) { |
int ch = ((now >> 8)&0x0f)+'0'; |
str[3] &= ~0x0ff0000; |
str[3] |= (ch<<16); |
str[13] = ch; |
|
if (pos > 4) { |
int ch = ((now >> 4)&0x0f)+'0'; |
str[3] &= ~0x0ff00; |
str[3] |= ':'<<8; |
str[3] &= ~0x0ff; |
str[3] |= (ch); |
ch = ((now >> 4)&0x0f)+'0'; |
str[15] = ch; |
str[14] = ':'; |
|
if (pos > 5) |
ch = (now&0x0f)+'0'; |
else |
ch = 'x'; |
str[4] &= ~0x0ff000000; |
str[4] |= (ch<<24); |
}}}}} |
str[16] = ch; |
}}}}} str[17] = '\0'; |
} |
|
const char timmenu[] = "\e[jSet current time:"; |
|
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); |
char dmsg[64]; |
strcpy(dmsg, timmenu); |
entered_menu_str(&dmsg[20], when, posn); |
write(FILENO_STDOUT, dmsg, strlen(dmsg)); |
} |
|
const char dawnmenu[] = "\e[jSet sunrise: "; |
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); |
char dmsg[64]; |
strcpy(dmsg, dawnmenu); |
entered_menu_str(&dmsg[16], when, posn); |
write(FILENO_STDOUT, dmsg, strlen(dmsg)); |
} |
|
const char duskmenu[] = "\e[;Set sunset: "; |
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); |
char dmsg[64]; |
entered_menu_str(&dmsg[15], when, posn); |
write(FILENO_STDOUT, dmsg, strlen(dmsg)); |
} |
|
int menu_readkey(void) { |
605,23 → 608,12
} dusk = newdusk; |
} |
|
const char unknownstr[] = "\e[jUnknown Cmd Key\e[1;0HA/Tm B/Dwn C/Dsk"; |
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); |
write(FILENO_STDOUT, unknownstr, strlen(unknownstr)); |
} |
void menu_task(void) { |
// Controls LED 0x08 |
631,10 → 623,8
// 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 = (volatile unsigned)rtcclock; |
while(1) { |
int event; |
672,3 → 662,14
} |
#endif |
|
|
#ifdef HELLO_TASK |
static const char *hello_string = "Hello, World!\r\n"; |
void hello_task(void) { |
while(1) { |
for(int i=0; i<15; i++) |
wait(SWINT_CLOCK, -1); |
write(FILENO_STDOUT, hello_string, strlen(hello_string)); |
} |
} |
#endif |
/kernel.c
72,12 → 72,13
|
int LAST_TASK; |
|
extern void txstr(const char *); |
|
void kernel_entry(void) { |
int nheartbeats= 0, tickcount = 0, milliseconds=0, ticks = 0; |
int audiostate = 0, buttonstate = 0; |
TASKP *tasklist, current; |
int *last_context; |
IOSPACE *sys = (IOSPACE *)IOADDR; |
|
tasklist = ksetup(); |
|
87,16 → 88,17
|
unsigned enableset = |
INT_ENABLEV(INT_BUTTON) |
|INT_ENABLEV(INT_TIMA) |
|INT_ENABLEV(INT_TIMER) |
// |INT_ENABLEV(INT_UARTRX) |
// |INT_ENABLEV(INT_UARTTX) // Needs to be turned on by driver |
// |INT_ENABLEV(INT_AUDIO // Needs to be turned on by driver) |
// |INT_ENABLEV(INT_GPIO) |
// |INT_ENABLEV(INT_TIMB); |
; |
// Then selectively turn some of them back on |
sys->io_pic = INT_ENABLE | enableset | 0x07fff; |
_sys->io_pic = INT_ENABLE | enableset | 0x07fff; |
|
txstr("HEAP: "); txhex(heap); |
|
do { |
int need_resched = 0, context_has_been_saved, pic; |
nheartbeats++; |
105,11 → 107,11
|
last_context = current->context; |
context_has_been_saved = 0; |
pic = sys->io_pic; |
pic = _sys->io_pic; |
|
if (pic & 0x8000) { // If there's an active interrupt |
// Interrupt processing |
sys->io_spio = 0x44; |
_sys->io_spio = 0x44; |
|
// First, turn off pending interrupts |
// Although we migt just write 0x7fff7fff to the |
119,18 → 121,18
// know about. |
pic &= 0x7fff; |
// Acknowledge current ints, and turn off pending ints |
sys->io_pic = INT_DISABLEV(pic)|(INT_CLEAR(pic)); |
if(pic&INT_TIMA) { |
_sys->io_pic = INT_DISABLEV(pic)|(INT_CLEAR(pic)); |
if(pic&INT_TIMER) { |
if (++ticks >= TICKS_PER_SECOND) {//(pic & SYSINT_PPS) |
// Toggle the low order LED |
tickcount++; |
ticks = 0; |
sys->io_spio = ((sys->io_spio&1)^1)|0x010; |
_sys->io_spio = ((_sys->io_spio&1)^1)|0x010; |
pic |= SWINT_CLOCK; |
} |
if (buttonstate) |
buttonstate--; |
else |
else if ((_sys->io_spio & 0x0f0)==0) |
enableset |= INT_ENABLEV(INT_BUTTON); |
} |
// |
137,12 → 139,14
if (pic&INT_BUTTON) { |
// Need to turn the button interrupt off |
enableset &= ~(INT_ENABLEV(INT_BUTTON)); |
if ((sys->io_spio&0x0f0)==0x030) |
if ((_sys->io_spio&0x0f0)==0x030) |
kpanic(); |
buttonstate = 3; |
if (buttonstate) |
pic &= ~INT_BUTTON; |
buttonstate = 50; |
} |
if (pic & INT_UARTRX) { |
int v = sys->io_uart; |
int v = _sys->io_uart; |
|
if ((v & (~0x7f))==0) { |
kpush_syspipe(rxpipe, v); |
149,44 → 153,42
|
// Local Echo |
if (pic & INT_UARTTX) { |
sys->io_uart = v; |
sys->io_pic = INT_UARTTX; |
_sys->io_uart = v; |
_sys->io_pic = INT_UARTTX; |
pic &= ~INT_UARTTX; |
} |
} |
} if (pic & INT_UARTTX) { |
int v; |
if (kpop_syspipe(txpipe, &v)==0) { |
char ch; |
if (kpop_syspipe(txpipe, &ch)==0) { |
unsigned v = ch; |
enableset |= (INT_ENABLEV(INT_UARTTX)); |
sys->io_uart= v; |
sys->io_pic = INT_UARTTX; |
_sys->io_uart= v; |
_sys->io_pic = INT_UARTTX; |
// if (v == 'W') |
// sys->io_timb = 5; |
// sys->io_watchdog = 5; |
// 75k was writing the 'e' |
} else |
enableset &= ~(INT_ENABLEV(INT_UARTTX)); |
enableset&= ~(INT_DISABLEV(INT_UARTTX)); |
} if (audiostate) { |
if (pic & INT_AUDIO) { |
int v; |
unsigned short sample; |
|
// States: |
// 0 -- not in use |
// 1 -- First sample, buffer empty |
// time to read a new sample |
// 2 -- second sample, to read new |
// 3 -- Need to turn off |
if ((audiostate & 3)==2) { |
sys->io_pwm_audio = (audiostate>>2)&0x0ffff; |
audiostate = 1; |
} else if (kpop_syspipe(pwmpipe, &v)==0) { |
audiostate = (2|(v<<2))&0x03ffff; |
sys->io_pwm_audio = (v>>16)&0x0ffff; |
// 1 -- in use |
|
if (kpop_short_syspipe(pwmpipe, &sample)==0) { |
_sys->io_pwm_audio = sample; |
_sys->io_spio = 0x022; |
// audiostate = 1; |
} else { |
audiostate = 0; |
// Turn the device off |
sys->io_pwm_audio = 0x10000; |
_sys->io_pwm_audio = 0x10000; |
// Turn the interrupts off |
enableset &= ~(INT_ENABLEV(INT_AUDIO)); |
sys->io_spio = 0x020; |
_sys->io_spio = 0x020; |
} |
|
// This particular interrupt cannot be cleared |
195,46 → 197,50
// it now. If it needs retriggering, the port |
// will retrigger itself -- despite being |
// cleared here. |
sys->io_pic = INT_AUDIO; |
}} else { // if (audiostate == 0) |
int sample; |
if (kpop_syspipe(pwmpipe, &sample)==0) { |
audiostate = (2|(sample<<2))&0x03ffff; |
sys->io_pwm_audio = 0x310000 | ((sample>>16)&0x0ffff); |
_sys->io_pic = INT_AUDIO; |
}} |
/* |
else { // if (audiostate == 0) |
unsigned short sample; |
|
if (kpop_short_syspipe(pwmpipe, &sample)==0) { |
audiostate = 1; |
_sys->io_pwm_audio = 0x310000 | sample; |
enableset |= (INT_ENABLEV(INT_AUDIO)); |
sys->io_spio = 0x022; |
sys->io_pic = INT_AUDIO; |
_sys->io_spio = 0x022; |
_sys->io_pic = INT_AUDIO; |
} // else sys->io_spio = 0x020; |
} |
*/ |
milliseconds = kpost(tasklist, pic, milliseconds); |
|
// Restart interrupts |
enableset &= (~0x0ffff); // Keep the bottom bits off |
sys->io_pic = INT_ENABLE|enableset; |
_sys->io_pic = INT_ENABLE|enableset; |
} else { |
sys->io_pic = INT_ENABLE; // Make sure interrupts are on |
int sample; |
_sys->io_pic = INT_ENABLE; // Make sure interrupts are on |
unsigned short sample; |
|
// Check for the beginning of an audio pipe. If the |
// interrupt is not enabled, we still might need to |
// enable it. |
if ((audiostate==0)&&(kpop_syspipe(pwmpipe, &sample)==0)) { |
audiostate = (2|(sample<<2))&0x03ffff; |
sys->io_pwm_audio = 0x310000 | ((sample>>16)&0x0ffff); |
sys->io_pic = INT_AUDIO; |
|
if ((audiostate==0)&&(kpop_short_syspipe(pwmpipe, &sample)==0)) { |
audiostate = 1; |
_sys->io_pwm_audio = 0x310000 | (sample); |
_sys->io_pic = INT_AUDIO; |
enableset |= (INT_ENABLEV(INT_AUDIO)); |
sys->io_spio = 0x022; |
_sys->io_spio = 0x022; |
} // else sys->io_spio = 0x020; |
|
// Or the beginning of a transmit pipe. |
if (pic & INT_UARTTX) { |
int v; |
if (kpop_syspipe(txpipe, &v)==0) { |
char ch; |
if (kpop_syspipe(txpipe, &ch)==0) { |
unsigned v = ch; |
enableset |= (INT_ENABLEV(INT_UARTTX)); |
sys->io_uart = v; |
sys->io_pic = INT_UARTTX; |
// if (v == 'W') |
// sys->io_timb = 5; |
_sys->io_uart = v; |
_sys->io_pic = INT_UARTTX; |
} else |
enableset &= ~(INT_ENABLEV(INT_UARTTX)); |
} |
244,9 → 250,9
// as syspipe() accomplishes within uwrite_syspipe() |
// (We also might've just turned them off ... ooops) |
enableset &= (~0x0ffff); // Keep the bottom bits off |
sys->io_pic = INT_ENABLE | enableset; |
_sys->io_pic = INT_ENABLE | enableset; |
} |
sys->io_spio = 0x40; |
_sys->io_spio = 0x40; |
|
int zcc = zip_ucc(); |
if (zcc & CC_TRAPBIT) { |
354,8 → 360,7
restore_context(last_context); |
} else if (zcc & (CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_ILL)) { |
current->state = SCHED_ERR; |
// current->errno = -EBUS; |
current->errno = (int)sys->io_buserr; |
current->errno = (int)_sys->io_buserr; |
save_context(last_context); |
context_has_been_saved = 1; |
kpanic(); |
409,7 → 414,7
|
int kpost(TASKP *tasklist, unsigned events, int milliseconds) { |
int i; |
if (events & INT_TIMA) |
if (events & INT_TIMER) |
milliseconds++; |
if (milliseconds<0) { |
milliseconds -= 0x80000000; |
/ksetup.c
46,15 → 46,18
#include "ktraps.h" |
#include "errno.h" |
#include "swint.h" |
#include "txfns.h" |
|
typedef unsigned size_t; |
|
extern int kntasks(void); |
extern void kinit(TASKP *tasklist); |
extern void restore_context(int *), save_context(int *); |
SYSPIPE *rxpipe, *txpipe, *keypipe, *lcdpipe, *pwmpipe, *cmdpipe; |
KDEVICE *pipedev, *txdev, *pwmdev; |
void *heap; // = _top_of_heap; // Need to wait on startup to set this |
char *heap; // = _top_of_heap; // Need to wait on startup to set this |
|
#define CONTEXT_LENGTH 80000 // 1ms |
#define CONTEXT_LENGTH (80000-1) // 1ms |
|
int LAST_TASK; |
|
61,12 → 64,12
__attribute__((cold)) |
TASKP *ksetup(void) { |
TASKP *tasklist; |
IOSPACE *sys = (IOSPACE *)IOADDR; |
volatile IOSPACE *const sys = _sys; |
|
sys->io_spio = 0x0f0; |
sys->io_timb = 0; // Turn off the watchdog timer |
sys->io_watchdog = 0; // Turn off the watchdog timer |
LAST_TASK = kntasks(); |
heap = _top_of_heap; |
heap = (char *)_top_of_heap; |
|
pipedev = sys_malloc(sizeof(KDEVICE)); |
pipedev->write = (RWFDFUN)kwrite_syspipe; |
75,26 → 78,25
|
txdev = pwmdev = pipedev; |
|
rxpipe = new_syspipe(16); //rxpipe->m_wrtask=INTERRUPT_WRITE_TASK; |
txpipe = new_syspipe(8); txpipe->m_rdtask = INTERRUPT_READ_TASK; |
keypipe = new_syspipe(16); |
lcdpipe = new_syspipe(16); |
pwmpipe = new_syspipe(128); pwmpipe->m_rdtask= INTERRUPT_READ_TASK; |
cmdpipe = new_syspipe(16); |
rxpipe = new_syspipe(64); //rxpipe->m_wrtask=INTERRUPT_WRITE_TASK; |
txpipe = new_syspipe(64); txpipe->m_rdtask = INTERRUPT_READ_TASK; |
keypipe = new_syspipe(64); |
lcdpipe = new_syspipe(64); |
pwmpipe = new_syspipe(512); pwmpipe->m_rdtask= INTERRUPT_READ_TASK; |
cmdpipe = new_syspipe(64); |
|
tasklist = sys_malloc(sizeof(TASKP)*(1+LAST_TASK)); |
kinit(tasklist); |
tasklist[LAST_TASK] = new_task(2, idle_task); |
tasklist[LAST_TASK] = new_task(8, idle_task); |
|
// Turn all interrupts off, acknowledge all at the same time |
sys->io_pic = 0x7fff7fff; |
sys->io_pic = INT_CLEARPIC; |
|
sys->io_tima = CONTEXT_LENGTH | TM_REPEAT; |
sys->io_timer = CONTEXT_LENGTH | TM_REPEAT; |
|
{ |
// Reset our wishbone scope for debug later |
SCOPE *scope = (SCOPE *)SCOPEADDR; |
scope->s_control = 2; |
_scope->s_ctrl = 2; |
} |
sys->io_spio = 0x0f1; |
|
102,15 → 104,13
} |
|
void kwait_on_buttonpress(void) { |
IOSPACE *sys = (IOSPACE *)IOADDR; |
|
// Wait on a button press before starting |
while((sys->io_spio & 0x0f0)==0) |
while((_sys->io_spio & 0x0f0)==0) |
; |
sys->io_spio = 0x0f3; |
_sys->io_spio = 0x0f3; |
for(int i=0; i<40000; i++) |
sys->io_spio = ((i>>14)&2)|0x020; |
sys->io_spio = 0x0f7; |
_sys->io_spio = ((i>>14)&2)|0x020; |
_sys->io_spio = 0x0f7; |
} |
|
// __attribute__((noreturn)) |
119,19 → 119,9
} |
|
__attribute__((malloc)) |
void *sys_malloc(int sz) { |
if (0) { |
SCOPE *s = (SCOPE *)SCOPEADDR; |
s->s_control = TRIGGER_SCOPE_NOW | (s->s_control & 0x0ffff); |
} |
|
void *sys_malloc(size_t sz) { |
void *res = heap; |
heap += sz; |
if ((int)heap > ((int)&res)-32) { |
IOSPACE *sys = (IOSPACE *)IOADDR; |
sys->io_spio = 0xf3; |
asm("break 0"); |
} |
heap = heap + ((sz+3)&-4); |
return res; |
} |
|
/ktraps.h
56,7 → 56,8
// If the timeout < 0, clears any pending timeout wakeup |
// If the timeout > 0, sets a pending timeout wakeup and |
// returns. |
// If the timeout == 0, does nothing. |
// If the timeout == 0, clears the respective interrupt |
// slash event, and does nothing more. |
TRAPID_WAIT, TRAPID_CLEAR, TRAPID_POST, |
// Yield: Yields the processor until the next scheduled time slice. |
TRAPID_YIELD, |
63,10 → 64,10
TRAPID_READ, TRAPID_WRITE, |
TRAPID_TIME, |
// Return from a kernel system call. This is necessary if ever an |
// exception triggers a syste call. In such cases, it will be |
// exception triggers a system call. In such cases, it will be |
// impossible to return the caller back to his context in a pristine |
// manner ... without help. |
// TRAPID_KRETURN |
// TRAPID_KRETURN, |
// Semaphore ID's. These allow us to run the rest of the trap |
// stuffs in kernel space |
TRAPID_SEMGET, TRAPID_SEMPUT, TRAPID_SEMNEW, |
/pipesetup.c
44,6 → 44,7
#include "syspipe.h" |
#include "zipsys.h" |
#include "ktraps.h" |
#include "txfns.h" |
|
#ifndef NULL |
#define NULL (void *)0 |
77,43 → 78,10
p->m_nwritten = 0; |
} |
|
// These routines really belong elsewhere in a uartdump.c file or some such. |
// However, until placed there, they'll stay put here for a bit longer. |
void txchr(char v) { |
volatile IOSPACE *sys = (IOSPACE *)IOADDR; |
if (v < 10) |
return; |
v &= 0x0ff; |
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 txhex(int num) { |
for(int ds=28; ds>=0; ds-=4) { |
int ch; |
ch = (num>>ds)&0x0f; |
if (ch >= 10) |
ch = 'A'+ch-10; |
else |
ch += '0'; |
txchr(ch); |
} txstr("\r\n"); |
} |
|
void pipe_panic(SYSPIPE *pipe) { |
extern void kpanic(void); |
volatile IOSPACE *sys = (IOSPACE *)IOADDR; |
|
sys->io_spio = 0x0fa; |
_sys->io_spio = 0x0fa; |
|
txstr("SYSPIPE PANIC!\r\n"); |
txstr("ADDR: "); txhex((int)pipe); |
126,7 → 94,7
SYSPIPE *new_syspipe(const unsigned int len) { |
unsigned msk; |
|
for(msk=2; msk<len; msk<<=1) |
for(msk=16; msk<len; msk<<=1) |
; |
SYSPIPE *pipe = sys_malloc(sizeof(SYSPIPE)-1+msk); |
pipe->m_mask = msk-1; |
/resetdump.s
32,7 → 32,7
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;// |
;; |
;; Copyright (C) 2015-2016, Gisselquist Technology, LLC |
;; Copyright (C) 2015-2017, 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 |
62,56 → 62,29
_start: |
; Upon reset, we must output our registers to the UART, lest we reset because |
; of a crash |
STO R0,(DBG) |
MOV PC+1,R0 |
BRA internal_kpanic |
SW R0,(DBG) |
JSR internal_kpanic |
LDI _top_of_stack,SP |
LDI kernel_entry,R0 |
BRA bootloader |
BRA _bootloader |
|
.global kpanic |
.type kpanic,@function |
kpanic: |
STO R0,(DBG) |
STO R1,1(DBG) |
STO R2,2(DBG) |
LDI 'P',R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI 'a',R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI 'n',R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI 'i',R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI 'c',R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI ':',R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI ' ',R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI '\r',R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI '\n',R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LOD 1(DBG),R1 |
LOD 2(DBG),R2 |
MOV PC+1,R0 |
JMP internal_kpanic |
SW R0,(DBG) |
SW R1,4(DBG) |
SW R2,8(DBG) |
LDI panicstr, R1 |
JSR raw_put_string |
LW 4(DBG),R1 |
LW 8(DBG),R2 |
JSR internal_kpanic |
kpanic_wait_for_button_release: |
LOD (SPIO),R0 |
LW (SPIO),R0 |
TEST 0x010,R0 |
BNZ kpanic_wait_for_button_release |
kpanic_wait_for_button: |
LOD (SPIO),R0 |
LW (SPIO),R0 |
TEST 0x010,R0 |
BZ kpanic_wait_for_button |
BRA _start |
118,191 → 91,159
HALT |
|
internal_kpanic: |
STO R1,1(DBG) |
STO R2,2(DBG) |
STO R0,3(DBG) ; Our return address |
; The original R0 is stored in (DBG) |
SW R1,4(DBG) |
SW R2,8(DBG) |
SW R0,12(DBG) ; Our return address |
|
; R0 |
LDI 0,R1 |
LOD (DBG),R2 |
MOV .Lcall0(PC),R0 |
JMP uart_put_reg_value |
.Lcall0: |
LW (DBG),R2 |
JSR uart_put_reg_value |
|
; R1 |
LDI 1,R1 |
LOD 1(DBG),R2 |
MOV .Lcall1(PC),R0 |
JMP uart_put_reg_value |
.Lcall1: |
LW 4(DBG),R2 |
JSR uart_put_reg_value |
; R2 |
LDI 2,R1 |
LOD 2(DBG),R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
LW 8(DBG),R2 |
JSR uart_put_reg_value |
; R3 |
LDI 3,R1 |
MOV R3,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; R4 |
LDI 4,R1 |
MOV R4,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; R5 |
LDI 5,R1 |
MOV R5,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; R6 |
LDI 6,R1 |
MOV R6,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; R7 |
LDI 7,R1 |
MOV R7,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; R8 |
LDI 8,R1 |
MOV R8,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; R9 |
LDI 9,R1 |
MOV R9,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; R10 |
LDI 10,R1 |
MOV R10,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; R11 |
LDI 11,R1 |
MOV R11,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; R12 |
LDI 12,R1 |
MOV R12,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; SP |
LDI 13,R1 |
MOV R13,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; uR0 |
LDI 16,R1 |
MOV uR0,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; uR1 |
LDI 17,R1 |
MOV uR1,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
LDI 18,R1 |
MOV uR2,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
LDI 19,R1 |
MOV uR3,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
LDI 20,R1 |
MOV uR4,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
LDI 21,R1 |
MOV uR5,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
LDI 22,R1 |
MOV uR6,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
LDI 23,R1 |
MOV uR7,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
LDI 24,R1 |
MOV uR8,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
LDI 25,R1 |
MOV uR9,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
LDI 26,R1 |
MOV uR10,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
LDI 27,R1 |
MOV uR11,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
LDI 28,R1 |
MOV uR12,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; uSP |
LDI 29,R1 |
MOV uSP,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; uCC |
LDI 30,R1 |
MOV uCC,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
; uPC |
LDI 31,R1 |
MOV uPC,R2 |
MOV PC+1,R0 |
JMP uart_put_reg_value |
JSR uart_put_reg_value |
|
;stack_mem_dump: |
;LDI 0,R4 |
;LDI _top_of_stack,R5 |
; LDI 0,R4 |
; LDI _top_of_stack,R5 |
;stack_mem_dump_loop: |
;MOV R4,R1 |
;LOD (R5),R2 |
;MOV PC+1,R0 |
;JMP uart_put_stack_value |
;ADD 1,R4 |
;SUB 1,R5 |
;CMP 64,R4 |
;BLT stack_mem_dump_loop |
; MOV R4,R1 |
; LW (R5),R2 |
; JSR uart_put_stack_value |
; ADD 4,R4 |
; SUB 4,R5 |
; CMP 256,R4 |
; BLT stack_mem_dump_loop |
|
; Get prepared for a proper start by setting our stack register |
LDI _top_of_stack,SP |
313,23 → 254,22
; Now, do a full dump of all memory--all registers are available to us |
dump_memory: |
LDI RAM,R5 |
LDI 0x1000,R6 |
LDI 0x0fff,R6 |
LDI 0x0f8,R7 |
STO R7,(SPIO) |
SW R7,(SPIO) |
full_mem_dump_loop: |
MOV R5,R1 |
LOD (R5),R2 |
MOV PC+1,R0 |
JMP uart_dump_mem_value |
LW (R5),R2 |
JSR uart_dump_mem_value |
LDI 0x0f2,R7 |
STO R7,(SPIO) |
SW R7,(SPIO) |
|
ADD 1,R5 |
ADD 4,R5 |
SUB 1,R6 |
BGT full_mem_dump_loop |
BGE full_mem_dump_loop |
|
LDI 0x0f5,R7 |
STO R7,(SPIO) |
SW R7,(SPIO) |
|
dump_scope: |
; Finally, do a full dump of the scope--if it had triggered |
336,10 → 276,9
; First, dump the scope control word |
LDI SCOPE,R7 ; R7 = Debugging scope address |
MOV R7,R1 |
LOD (R7),R2 |
LW (R7),R2 |
MOV R2,R5 ; R5 will not be changed by a subroutine |
MOV PC+1,R0 |
BRA uart_dump_mem_value |
JSR uart_dump_mem_value |
; Then test whether or not the scope has stopped |
LDI 0x40000000,R1 |
TEST R1,R5 |
349,116 → 288,72
LSR 20,R5 |
AND 0x1f,R5 |
LDI 1,R6 |
LSL R5,R6 |
LSL R5,R6 ; R6 is now the size (number of words) of the scope |
SUB 1,R6 ; Now it is one less than the size,2 support the BGE l8r |
; And start dumping |
ADD 1,R7 ; Get the scope data address |
ADD 4,R7 ; Get the scope data address |
dump_scope_loop: |
MOV R7,R1 |
LOD (R7),R2 |
MOV PC+1,R0 |
BRA uart_dump_mem_value |
LW (R7),R2 |
JSR uart_dump_mem_value |
SUB 1,R6 |
BGT dump_scope_loop |
BGE dump_scope_loop |
|
dump_buserr: |
; Dump a bus error address, if used |
LDI 'B',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI 'u',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI 's',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI 'E',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI 'r',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI 'r',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI ':',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI ' ',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI buserr_header, R1 |
JSR raw_put_string |
LDI BUSERR,R1 |
LOD (R1),R2 |
MOV PC+1,R0 |
BRA uart_dump_mem_value |
LW (R1),R2 |
JSR uart_dump_mem_value |
|
end_internal_panic: |
LDI '\r',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI '\n',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI '\r',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI '\n',R1 |
MOV PC+1,R0 |
BRA raw_put_uart |
LDI doublenewline,R1 |
JSR raw_put_string |
LDI 0x0ff,R7 |
STO R7,(SPIO) |
LOD 3(DBG),PC |
SW R7,(SPIO) |
LW 12(DBG),PC |
JMP R0 |
|
; R0 is return address |
; R1 is register ID |
; R2 is register to output |
; R2 is register value to output |
uart_put_reg_value: |
STO R0,4(DBG) |
STO R2,5(DBG) |
STO R3,6(DBG) |
SW R0,16(DBG) |
SW R2,20(DBG) |
SW R3,24(DBG) |
MOV R1,R2 |
LDI 'u',R1 |
CMP 16,R2 |
LDILO.LT 's',R1 |
SUB.GE 16,R2 |
MOV PC+1,R0 |
JMP raw_put_uart |
JSR raw_put_uart |
LDI '0',R1 |
CMP 10,R2 |
LDILO.GE '1',R1 |
SUB.GE 10,R2 |
MOV PC+1,R0 |
JMP raw_put_uart |
JSR raw_put_uart |
MOV R2,R1 |
AND 15,R1 |
MOV PC+1,R0 |
JMP get_hex |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI 58,R1 ; A ':' |
MOV PC+1,R0 |
JMP raw_put_uart |
LOD 5(DBG),R2 |
JSR get_hex |
JSR raw_put_uart |
LDI ':',R1 |
JSR raw_put_uart |
LW 20(DBG),R2 |
LDI 8,R3 |
uart_put_loop: |
ROL 4,R2 |
MOV R2,R1 |
AND 15,R1 |
MOV PC+1,R0 |
JMP get_hex |
MOV PC+1,R0 |
JMP raw_put_uart |
LSR 28,R1 |
LSL 4,R2 |
JSR get_hex |
JSR raw_put_uart |
SUB 1,R3 |
BNZ uart_put_loop |
LDI '\r',R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI '\n',R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LOD 4(DBG),R0 |
LOD 5(DBG),R2 |
LOD 6(DBG),R3 |
LDI newline, R1 |
JSR raw_put_string |
LW 16(DBG),R0 |
LW 20(DBG),R2 |
LW 24(DBG),R3 |
JMP R0 |
|
uart_dump_mem_value: |
466,107 → 361,109
; R1 = Memory address |
; R2 = Memory Value |
; Local: R3 = working value |
STO R0,7(DBG) |
SW R0,28(DBG) |
MOV R1,R3 ; R3 = Memory address |
MOV R2,R4 ; R4 = Memory Value |
LDI 77,R1 ; 77 = 'M' |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI 91,R1 ; 91 = '[' |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI 48,R1 ; A '0' |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI 120,R1 ; An 'x' |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI memopenstr,R1 |
JSR raw_put_string |
; Set up a loop to dump things |
ROL 16,R3 ; Ignore the first 16 bits |
LSL 16,R3 ; Ignore the first 16 bits |
LDI 4,R2 ; We're going to do four hex digits here |
; |
uart_put_mem_address_loop: |
ROL 4,R3 |
MOV R3,R1 |
AND 15,R1 |
MOV PC+1,R0 |
JMP get_hex |
MOV PC+1,R0 |
JMP raw_put_uart |
LSR 28,R1 |
LSL 4,R3 |
JSR get_hex |
JSR raw_put_uart |
SUB 1,R2 |
BNZ uart_put_mem_address_loop |
; Put some transition characters |
LDI 93,R1 ; 93 = ']' |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI 58, R1 ; A semicolon |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI 32, R1 ; A space |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI memmidstr,R1 |
JSR raw_put_string |
|
; Set up a loop to dump the memory value now |
LDI 8,R2 |
uart_put_mem_value_loop: |
ROL 4,R4 |
MOV R4,R1 |
AND 15,R1 |
MOV PC+1,R0 |
JMP get_hex |
MOV PC+1,R0 |
JMP raw_put_uart |
LSR 28,R1 |
LSL 4,R4 |
JSR get_hex |
JSR raw_put_uart |
SUB 1,R2 |
BNZ uart_put_mem_value_loop |
; Clear the line |
LDI '\r', R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI '\n', R1 |
MOV PC+1,R0 |
JMP raw_put_uart |
LDI newline,R1 |
JSR raw_put_string |
; And return from our subroutine |
LOD 7(DBG),R0 |
LW 28(DBG),R0 |
JMP R0 |
|
get_hex: |
ADD 0x30,R1 |
CMP 0x39,R1 |
ADD.GT 7,R1 ; Add 'A'-'0'-10 |
CMP 0x3a,R1 |
ADD.GE 7,R1 ; Add 'A'-'0'-10 |
JMP R0 |
|
raw_put_uart: ; R0 is return address, R1 is value to transmit |
STO R2,8(DBG) |
; R0 is the return address |
; R1 is the string address |
raw_put_string: |
SW R0,36(DBG) |
SW R2,40(DBG) |
MOV R1,R2 |
raw_put_string_next: |
LB (R2),R1 |
CMP 0,R1 |
LW.Z 36(DBG),R0 |
LW.Z 40(DBG),R2 |
RTN.Z |
ADD 1,R2 |
MOV raw_put_string_next(PC),R0 |
BRA raw_put_uart |
|
; R0 is return address, |
; R1 is value to transmit |
raw_put_uart: |
SW R2,32(DBG) |
LDI INT_UARTTX,R2 |
STO R2,(PIC) ; Clear the PIC, turn off interrupts, etc. |
SW R2,(PIC) ; Clear the PIC, turn off interrupts, etc. |
raw_put_uart_retest: |
LOD (PIC),R2 |
LW (PIC),R2 |
TEST INT_UARTTX,R2 |
BZ raw_put_uart_retest |
STO R1,(UART) |
LOD 8(DBG),R2 |
SW R1,(UART) |
LW 32(DBG),R2 |
JMP R0 |
|
.section .fixdata |
DBG: |
.byte 0,0,0,0,0,0,0,0,0 |
.int 0,0,0,0,0,0,0,0,0,0 |
|
.set INT_UARTRX, 0x040 |
.set INT_UARTTX, 0x080 |
.set PIC, 0x0100 |
.set BUSERR, 0x0101 |
.set TMRA, 0x0102 |
.set TMRB, 0x0103 |
.set PWM, 0x0104 |
.set SPIO, 0x0105 |
.set GPIO, 0x0106 |
.set UART, 0x0107 |
.set VERSION, 0x0108 |
.set SCOPE, 0x0200 |
.set SCOPED, 0x0201 |
.set CLOCK, 0x0800 |
.set CONFIG, 0x0400 |
.set TIMER, 0x0801 |
.set STOPWATCH,0x802 |
.set ALARM, 0x0803 |
.set RAM, 0x2000 |
.set PIC, 0x0400 |
.set BUSERR, 0x0404 |
.set TMRA, 0x0408 |
.set TMRB, 0x040c |
.set PWM, 0x0410 |
.set SPIO, 0x0414 |
.set GPIO, 0x0418 |
.set UART, 0x041c |
.set VERSION, 0x0420 |
.set SCOPE, 0x0800 |
.set SCOPED, 0x0804 |
.set RAM, 0x8000 |
.section .rodata |
doublenewline: |
.ascii "\r\n" |
newline: |
.asciz "\r\n" |
buserr_header: |
.string "BusErr: " |
panicstr: |
.string "Panic: \r\n" |
memopenstr: |
.string "M[0x" |
memmidstr: |
.string "]; " |
|
/syspipe.c
46,12 → 46,13
#include "syspipe.h" |
#include "zipsys.h" |
#include "ktraps.h" |
#include "string.h" |
|
#ifndef NULL |
#define NULL (void *)0 |
#endif |
|
void kpush_syspipe(SYSPIPE *pipe, int val) { |
void kpush_syspipe(SYSPIPE *pipe, char val) { |
int tst = (pipe->m_head+1)&pipe->m_mask; |
if (tst != pipe->m_tail) { |
pipe->m_buf[pipe->m_head] = val; |
62,8 → 63,15
} |
|
extern void pipe_panic(SYSPIPE *p); |
int kpop_syspipe(SYSPIPE *pipe, int *vl) { |
/* |
* kpop_syspipe |
* |
* Called from an interrupt context to pop one byte off of the syspipe. |
*/ |
int kpop_syspipe(SYSPIPE *pipe, char *vl) { |
if (pipe->m_head != pipe->m_tail) { |
// The head will *only* equal the tail if the pipe is empty. |
// We come in here, therefore, if the pipe is non-empty |
*vl = pipe->m_buf[pipe->m_tail]; |
pipe->m_tail = (pipe->m_tail+1)&pipe->m_mask; |
if (pipe->m_wrtask) |
73,12 → 81,30
return 1; // Error condition |
} |
|
/* Returns how many values are in the pipe |
/* |
* kpop_short_syspipe |
* |
* This is identical to kpop_syspipe, save that we are pulling a short value |
* off of the syspipe (i.e. a pair of chars), not just a single char. |
*/ |
/* Of course ... if it's not used, why include it? |
int kpop_short_syspipe(SYSPIPE *pipe, unsigned short *vl) { |
if (pipe->m_head == pipe->m_tail) |
return 1; // Error condition |
|
unsigned short *sptr = (unsigned short *)&pipe->m_buf[pipe->m_tail]; |
// sv = pipe->m_buf[pipe->m_tail]; |
*vl = *sptr;; |
pipe->m_tail = (pipe->m_tail+2)&pipe->m_mask; |
if (pipe->m_wrtask) |
pipe->m_wrtask->state = SCHED_READY; |
return 0; |
} |
|
/* |
int len_syspipe(SYSPIPE *p) { |
return (p->m_head-p->m_tail) & p->m_mask; |
} */ |
|
/* Returns how many empty spaces are in the pipe |
*/ |
int num_avail_syspipe(SYSPIPE *p) { |
96,7 → 122,8
// Another task may write to the pipe during this call. If the pipe becomes |
// full, that task will block. |
// |
static int uread_syspipe(TASKP tsk __attribute__((__unused__)), SYSPIPE *p, int *dst, int len) { |
static int uread_syspipe(TASKP tsk __attribute__((__unused__)), |
SYSPIPE *p, char *dst, int len) { |
int nleft= len, h; |
if (len == 0) { |
// We'll only get here if we were released from within a |
116,9 → 143,8
int ln1 = p->m_mask+1 - p->m_tail; // Navail to be read |
ln1 = (ln1 > nleft) ? nleft : ln1; |
if (ln1 > 0) { |
register int *src = &p->m_buf[p->m_tail]; |
for(int i=0; i<ln1; i++) |
*dst++ = *src++; |
memcpy(dst, &p->m_buf[p->m_tail], ln1); |
dst += ln1; |
|
p->m_nread += ln1; |
nleft -= ln1; |
144,9 → 170,8
int ln1 = h - p->m_tail; |
ln1 = (ln1 < nleft) ? ln1 : nleft; |
|
int *src = &p->m_buf[p->m_tail]; |
for(int i=0; i<ln1; i++) |
*dst++ = *src++; |
memcpy(dst, &p->m_buf[p->m_tail], ln1); |
dst += ln1; |
|
p->m_nread += ln1; |
nleft -= ln1; |
172,7 → 197,8
// pointer. It can change from one time through our loop |
// to the next. |
if (((volatile SYSPIPE *)p)->m_wrtask) { |
int *src, ln; |
int ln; |
char *src; |
|
// If the head changed before the write task blocked, |
// then go around again and copy some more before |
189,11 → 215,11
ln = nleft; |
if (p->m_wrtask->context[4] < nleft) |
ln = p->m_wrtask->context[4]; |
src = (int *)p->m_wrtask->context[3]; |
src = (char *)p->m_wrtask->context[3]; |
memcpy(dst, src, ln); |
dst += ln; |
src += ln; |
|
for(int i=0; i<ln; i++) |
*dst++ = *src++; |
|
p->m_nwritten += ln; |
p->m_nread += ln; |
|
244,7 → 270,7
} |
|
static int uwrite_syspipe(TASKP tsk __attribute__((__unused__)), |
SYSPIPE *p, int *src, int len) { |
SYSPIPE *p, char *src, int len) { |
int nleft = len; |
|
// The kernel guarantees, before we come into here, that we have a |
263,9 → 289,8
int ln = nleft; |
if (ln > p->m_rdtask->context[4]) |
ln = p->m_rdtask->context[4]; |
int *dst = (int *)p->m_rdtask->context[3]; |
for(int i=0; i<ln; i++) |
*dst++ = *src++; |
memcpy((char *)p->m_rdtask->context[3], src, ln); |
src += ln; |
p->m_nread += ln; |
p->m_rdtask->context[3]+= ln; |
p->m_rdtask->context[4]-= ln; |
318,34 → 343,17
// so that it remains consistent under interrupt |
// conditions. |
int ln = p->m_mask+1-p->m_head; |
int *dst = &p->m_buf[p->m_head]; |
if (ln > nleft) ln = nleft; |
if (ln > navail) ln = navail; |
|
for(int i=0; i<ln; i++) |
*dst++ = *src++; |
memcpy((void *)&p->m_buf[p->m_head], src, ln); |
src += ln; |
|
p->m_head = (p->m_head+ln)&p->m_mask; |
nleft -= ln; |
p->m_nwritten += ln; |
navail -= ln; |
nleft -= ln; |
p->m_nwritten += ln; |
navail -= ln; |
} |
|
/* |
// Write into the rest of the pipe |
if ((0 == p->m_head)&&(nleft>0)&&(navail>0)) { |
int ln = navail; |
if (nleft < ln) |
ln = nleft; |
int *dst = &p->m_buf[p->m_head]; |
|
for(int i=0; i<ln; i++) |
*dst++ = *src++; |
|
p->m_head += ln; |
p->m_nwritten += ln; |
nleft -= ln; |
}*/ |
} |
|
if ((nleft > 0)&&(navail == 0)) { |
371,7 → 379,7
} |
|
// This will be called from a kernel (interrupt) context |
void kread_syspipe(TASKP tsk, int dev, int *dst, int len) { |
void kread_syspipe(TASKP tsk, int dev, char *dst, int len) { |
SYSPIPE *p = (SYSPIPE *)dev; |
if (p->m_rdtask != NULL) { |
// If the pipe already has a read task, then we fail |
415,7 → 423,7
} |
} |
|
void kwrite_syspipe(TASKP tsk, int dev, int *src, int len) { |
void kwrite_syspipe(TASKP tsk, int dev, char *src, int len) { |
SYSPIPE *p = (SYSPIPE *)dev; |
if (p->m_wrtask != NULL) { |
// If the pipe already has a write task, then we fail |
/syspipe.h
46,7 → 46,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// Copyright (C) 2015-2017, 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 |
73,8 → 73,10
#ifndef SYSPIPE_H |
#define SYSPIPE_H |
|
extern void *sys_malloc(int sz); |
typedef unsigned size_t; |
|
extern void *sys_malloc(size_t sz); |
|
typedef struct { |
unsigned int m_mask; |
int m_head, m_tail; |
83,14 → 85,15
int dummy; |
int m_error; |
|
int m_buf[1]; |
char m_buf[1]; |
} SYSPIPE; |
|
SYSPIPE *new_syspipe(const unsigned int len); |
extern void kread_syspipe( TASKP tsk, int dev, int *dst, int len); |
extern void kwrite_syspipe(TASKP tsk, int dev, int *src, int len); |
void kpush_syspipe(SYSPIPE *p, int val); |
int kpop_syspipe(SYSPIPE *p, int *val); |
extern void kread_syspipe( TASKP tsk, int dev, char *dst, int len); |
extern void kwrite_syspipe(TASKP tsk, int dev, char *src, int len); |
void kpush_syspipe(SYSPIPE *p, char val); |
int kpop_syspipe(SYSPIPE *p, char *val); |
int kpop_short_syspipe(SYSPIPE *p, unsigned short *val); |
extern int num_avail_syspipe(SYSPIPE *p); |
extern int len_syspipe(SYSPIPE *p); |
|
/taskp.c
39,6 → 39,7
#include "ksched.h" |
#include "kfildes.h" |
#include "taskp.h" |
#include "txfns.h" |
|
extern void *sys_malloc(int sz); |
TASKP new_task(unsigned ln, VENTRYP entry) { |
47,11 → 48,11
|
for(i=0; (unsigned)i<sizeof(struct TASK_S)+ln; i++) |
((unsigned int *)tsk)[i] = 0; |
tsk->context[ 0] = (int)((long)(int *)idle_task); |
tsk->context[ 0] = (int)(idle_task); |
tsk->context[12] = (int)&tsk->user_data[ln]; // Set the stack pointer |
tsk->context[13] = (int)&tsk->user_data[ln]; // Set the stack pointer |
tsk->context[14] = 0x20; // GIE bit only |
tsk->context[15] = (int)((long)(int *)entry); |
tsk->context[15] = (int)((int *)entry); |
tsk->user_heap = &tsk->user_data[0]; |
tsk->state = SCHED_READY; |
|
/ziplib.c
5,5 → 5,7
do { |
*p++ = c; |
} while(n-- > 0); |
|
return s; |
} |
|
/zipsys.h
79,13 → 79,11
#endif |
|
static inline void DISABLE_INTS(void) { |
IOSPACE *sys = (IOSPACE *)IOADDR; |
sys->io_pic = 0; |
_sys->io_pic = 0; |
} |
|
static inline void ENABLE_INTS(void) { |
IOSPACE *sys = (IOSPACE *)IOADDR; |
sys->io_pic = INT_ENABLE; |
_sys->io_pic = INT_ENABLE; |
} |
|
#endif |