URL
https://opencores.org/ocsvn/s6soc/s6soc/trunk
Subversion Repositories s6soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/s6soc
- from Rev 26 to Rev 27
- ↔ Reverse comparison
Rev 26 → Rev 27
/trunk/sw/zipos/cmodram.ld
0,0 → 1,73
/******************************************************************************* |
* |
* Filename: cmodram.ld |
* |
* Project: Cmod S6 ZipCPU demonstration |
* |
* Purpose: This script provides a description of the Cmod S6 Zip CPU |
* build for the purposes of where to place memory when linking. |
* |
* This script is different from the cmod.ld script in that this script |
* places specific pieces of code into RAM rather than FLASH. This is to |
* speed up those particular pieces of code. This script also depends |
* upon a bootloader to load the RAM sections into RAM with their initial |
* values. |
* |
* Creator: Dan Gisselquist, Ph.D. |
* Gisselquist Technology, LLC |
* |
******************************************************************************** |
* |
* Copyright (C) 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. |
* |
* License: GPL, v3, as defined and found on www.gnu.org, |
* http://www.gnu.org/licenses/gpl.html |
* |
* |
*******************************************************************************/ |
|
ENTRY(_start) |
|
MEMORY |
{ |
blkram (wx) : ORIGIN = 0x002000, LENGTH = 0x001000 |
flash (rx) : ORIGIN = 0x400000, LENGTH = 0x400000 |
} |
|
_top_of_stack = ORIGIN(blkram) + LENGTH(blkram) - 1; |
|
SECTIONS |
{ |
. = 0x0480000; |
.rocode 0x0480000 : { *(.start) |
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) |
} > blkram AT> flash |
.data : { *(.fixdata) *(.data) *(COMMON) |
load_image_end = . ; |
} > blkram AT> flash |
.bss : { *(.bss) bss_image_end = . ; } > blkram |
_top_of_heap = .; |
} |
/trunk/sw/zipos/syspipe.h
80,6 → 80,7
int m_head, m_tail; |
volatile TASKP m_rdtask, m_wrtask; |
unsigned int m_nread, m_nwritten; |
int dummy; |
int m_error; |
|
int m_buf[1]; |
/trunk/sw/zipos/doorbell.c
170,11 → 170,14
|
#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; |
204,6 → 207,7
#include "../dev/samples.c" |
|
const unsigned dawn = 0x060000, dusk = 0x180000; |
int nwritten = 0, nread = 0, nstarts = 0; |
|
void shownow(unsigned now) { // Uses 10 stack slots + 8 for write() |
char dmsg[9]; |
256,6 → 260,31
sys->io_spio = 0x80; // Turn light off |
} |
|
void uartchr(char v) { |
if (write(FILENO_STDERR, &v, 1) != 1) |
write(FILENO_STDERR, "APPLE-PANIC", 11); |
} |
|
void uartstr(const char *str) { |
int cnt=0; |
while(str[cnt]) |
cnt++; |
if (cnt != write(FILENO_STDERR, str, cnt)) |
write(FILENO_STDERR, "PIPE-PANIC", 10); |
} |
|
void uarthex(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'; |
uartchr(ch); |
} uartstr("\r\n\0"); |
} |
|
void doorbell_task(void) { |
// Controls LED 0x08 |
|
268,6 → 297,7
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 |
290,15 → 320,24
// Check time: should we turn our light on or not? |
belllight(rtcclock); |
const int *sptr = sound_data; |
sys->io_uart = 'N'; |
// uartchr('N'); |
while(sptr < &sound_data[NSAMPLE_WORDS]) { |
int len = &sound_data[NSAMPLE_WORDS]-sptr; |
if (len > 256) |
len = 256; |
|
// We stall here, if the audio FIFO is full |
/* |
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 |
// our light counter. |
317,7 → 356,7
} |
} |
|
sys->io_uart = 'D'; |
uartchr('D'); |
|
// Next state: the doorbell is no longer ringing, but |
// we have yet to return to normal--the light is still |
331,10 → 370,27
if (event&INT_BUTTON) { |
when = (volatile unsigned)rtcclock; |
showbell(when); |
sys->io_uart = 'S'; |
uartchr('B'); |
} |
} |
|
// uartstr("\r\n"); |
uartstr("\r\nNWritten: "); uarthex(nwritten); |
uartstr("NRead : "); uarthex(nread); |
uartstr("NStarts : "); uarthex(nstarts); |
nwritten = nread = nstarts = 0; |
} |
} |
#endif |
|
|
|
/* |
|
|
NWritten: 000018E7 |
NRead : 000018E7 |
NStarts : 00000001 |
|
|
*/ |
/trunk/sw/zipos/zipsys.h
85,7 → 85,7
|
static inline void ENABLE_INTS(void) { |
IOSPACE *sys = (IOSPACE *)IOADDR; |
sys->io_pic = 0x80000000; |
sys->io_pic = INT_ENABLE; |
} |
|
#endif |
/trunk/sw/zipos/ksetup.c
0,0 → 1,134
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: ksetup.c |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// 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. |
// |
// 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 "zipsys.h" |
#include "board.h" |
#include "ksched.h" |
#include "kfildes.h" |
#include "taskp.h" |
#include "syspipe.h" |
#include "ktraps.h" |
#include "errno.h" |
#include "swint.h" |
|
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 |
|
#define CONTEXT_LENGTH 100000 // 1ms |
|
int LAST_TASK; |
|
TASKP *ksetup(void) { |
TASKP *tasklist; |
IOSPACE *sys = (IOSPACE *)IOADDR; |
|
sys->io_spio = 0x0f0; |
sys->io_timb = 0; // Turn off the watchdog timer |
LAST_TASK = kntasks(); |
heap = _top_of_heap; |
|
pipedev = sys_malloc(sizeof(KDEVICE)); |
pipedev->write = (RWFDFUN)kwrite_syspipe; |
pipedev->read = (RWFDFUN)kread_syspipe; |
pipedev->close = NULL; |
|
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(256); pwmpipe->m_rdtask= INTERRUPT_READ_TASK; |
cmdpipe = new_syspipe(16); |
|
tasklist = sys_malloc(sizeof(TASKP)*(1+LAST_TASK)); |
kinit(tasklist); |
tasklist[LAST_TASK] = new_task(2, idle_task); |
|
// Turn all interrupts off, acknowledge all at the same time |
sys->io_pic = 0x7fff7fff; |
|
sys->io_tima = CONTEXT_LENGTH | TM_REPEAT; |
|
{ |
// Reset our wishbone scope for debug later |
SCOPE *scope = (SCOPE *)SCOPEADDR; |
scope->s_control = 2; |
} |
sys->io_spio = 0x0f1; |
|
return tasklist; |
} |
|
void kwait_on_buttonpress(void) { |
IOSPACE *sys = (IOSPACE *)IOADDR; |
|
// Wait on a button press before starting |
while((sys->io_spio & 0x0f0)==0) |
; |
sys->io_spio = 0x0f3; |
for(int i=0; i<40000; i++) |
sys->io_spio = ((i>>14)&2)|0x020; |
sys->io_spio = 0x0f7; |
} |
|
void kuserexit(int a) { |
syscall(TRAPID_EXIT, a, 0, 0); |
} |
|
void *sys_malloc(int sz) { |
{ |
SCOPE *s = (SCOPE *)SCOPEADDR; |
s->s_control = TRIGGER_SCOPE_NOW | (s->s_control & 0x0ffff); |
} |
|
void *res = heap; |
heap += sz; |
if ((int)heap > ((int)&res)-32) { |
IOSPACE *sys = (IOSPACE *)IOADDR; |
sys->io_spio = 0xf3; |
asm("break 0"); |
} |
return res; |
} |
|
/trunk/sw/zipos/pipesetup.c
0,0 → 1,137
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: pipesetup.c |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: The routines in this file were split from syspipe.c for the |
// purposes of limiting the amount of RAM memory a process would |
// use. Specifically, these routines are not time critical and hence can |
// run from FLASH, whereas the other set must run from block RAM. |
// |
// 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 "errno.h" |
#include "board.h" |
#include "taskp.h" |
#include "syspipe.h" |
#include "zipsys.h" |
#include "ktraps.h" |
|
#ifndef NULL |
#define NULL (void *)0 |
#endif |
|
// Since this is only called with new_syspipe, we're good here |
static void clear_syspipe(SYSPIPE *p) { |
p->m_head = 0; |
p->m_tail = 0; |
p->m_error = 0; |
|
for(int i=0; i<=(int)p->m_mask; i++) |
p->m_buf[i] = 0; |
|
if ((p->m_rdtask)&&(p->m_rdtask != INTERRUPT_READ_TASK)) { |
p->m_rdtask->context[1] = p->m_nread; |
if (p->m_nread == 0) |
p->m_rdtask->errno = -EFAULT; |
p->m_rdtask->state = SCHED_READY; |
} else if (p->m_wrtask) { |
p->m_wrtask->context[1] = p->m_nwritten; |
if (p->m_nwritten == 0) |
p->m_wrtask->errno = -EFAULT; |
p->m_wrtask->state = SCHED_READY; |
} |
|
if (p->m_rdtask != INTERRUPT_READ_TASK) |
p->m_rdtask = 0; |
p->m_wrtask = 0; |
p->m_nread = 0; |
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; |
|
txstr("SYSPIPE PANIC!\r\n"); |
txstr("ADDR: "); txhex((int)pipe); |
txstr("MASK: "); txhex(pipe->m_mask); |
txstr("HEAD: "); txhex(pipe->m_head); |
txstr("TAIL: "); txhex(pipe->m_tail); |
kpanic(); |
} |
|
SYSPIPE *new_syspipe(const unsigned int len) { |
unsigned msk; |
|
for(msk=2; msk<len; msk<<=1) |
; |
SYSPIPE *pipe = sys_malloc(sizeof(SYSPIPE)-1+msk); |
pipe->m_mask = msk-1; |
pipe->m_rdtask = pipe->m_wrtask = 0; |
clear_syspipe(pipe); |
return pipe; |
} |
|
/trunk/sw/zipos/kernel.c
68,58 → 68,25
void kwrite_txuart(TASKP tsk, int dev, int *dst, int len); |
int kpost(TASKP *task, unsigned events, int milliseconds); |
TASKP kschedule(int LAST_TASK, TASKP *tasklist, TASKP last); |
extern TASKP *ksetup(void); |
|
int LAST_TASK; |
|
extern int nwritten, nread, nstarts; |
|
void kernel_entry(void) { |
int nheartbeats= 0, tickcount = 0, milliseconds=0, ticks = 0; |
int audiostate = 0; |
int audiostate = 0, buttonstate = 0; |
TASKP *tasklist, current; |
int *last_context; |
IOSPACE *sys = (IOSPACE *)IOADDR; |
sys->io_spio = 0x0f0; |
sys->io_timb = 0; // Turn off the watchdog timer |
LAST_TASK = kntasks(); |
heap = _top_of_heap; |
|
pipedev = sys_malloc(sizeof(KDEVICE)); |
pipedev->write = (RWFDFUN)kwrite_syspipe; |
pipedev->read = (RWFDFUN)kread_syspipe; |
pipedev->close = NULL; |
tasklist = ksetup(); |
|
/* |
txdev = sys_malloc(sizeof(KDEVICE)); |
txdev->write = (RWFDFUN)kwrite_txuart; |
txdev->read = (RWFDFUN)kread_syspipe; |
txdev->close = NULL; |
|
pwmdev = sys_malloc(sizeof(KDEVICE)); |
pwmdev->write = (RWFDFUN)kwrite_audio; |
pwmdev->read = (RWFDFUN)kread_syspipe; |
pwmdev->close = NULL; |
*/ |
|
txdev = pwmdev = pipedev; |
|
rxpipe = new_syspipe(16); //rxpipe->m_wrtask=INTERRUPT_WRITE_TASK; |
txpipe = new_syspipe(16); txpipe->m_rdtask = INTERRUPT_READ_TASK; |
keypipe = new_syspipe(16); |
lcdpipe = new_syspipe(16); |
pwmpipe = new_syspipe(256); pwmpipe->m_rdtask= INTERRUPT_READ_TASK; |
cmdpipe = new_syspipe(16); |
|
tasklist = sys_malloc(sizeof(TASKP)*(1+LAST_TASK)); |
kinit(tasklist); |
tasklist[LAST_TASK] = new_task(2, idle_task); |
|
|
// current = tasklist[0]; |
current = tasklist[LAST_TASK]; |
current = tasklist[0]; |
restore_context(current->context); |
last_context = current->context; |
|
// Turn all interrupts off, acknowledge all at the same time |
sys->io_pic = 0x7fff7fff; |
unsigned enableset = |
INT_ENABLEV(INT_BUTTON) |
|INT_ENABLEV(INT_TIMA) |
130,48 → 97,13
// |INT_ENABLEV(INT_TIMB); |
; |
// Then selectively turn some of them back on |
sys->io_pic = INT_ENABLE | enableset; |
sys->io_pic = INT_ENABLE | enableset | 0x07fff; |
|
sys->io_tima = CONTEXT_LENGTH | TM_REPEAT; |
|
sys->io_spio = 0x0f1; |
if (1) { |
// Reset our wishbone scope for debug later |
SCOPE *scope = (SCOPE *)SCOPEADDR; |
scope->s_control = 12; |
} |
|
if (0) { |
// Wait on a button press before starting |
while((sys->io_spio & 0x0f0)==0) |
; |
sys->io_spio = 0xf3; |
for(int i=0; i<0x40000; i++) |
sys->io_spio = ((i>>14)&2)|0x20; |
sys->io_spio = 0xf7; |
} |
sys->io_pic = 0x7fff|INT_ENABLE; |
|
do { |
int need_resched = 0, context_has_been_saved, pic; |
nheartbeats++; |
|
if (0) { |
int v = 0xe4, p = sys->io_pic; |
if (p < 0) // LED 4 if interrupts enabled |
v &= ~4; |
if(p & 0x8000) // LED 8 if any already active |
v |= 8; |
sys->io_spio = v; |
} |
|
// if (sys->io_timb == 0) |
// sys->io_timb = 1600000000; // CONTEXT_LENGTH; |
// sys->io_timb = (sys->io_tima & 0x7fffffff) + 350; |
// sys->io_spio = 0x0e0; |
zip_rtu(); |
// sys->io_spio = 0xe2; |
// sys->io_timb = CONTEXT_LENGTH; |
|
last_context = current->context; |
context_has_been_saved = 0; |
199,6 → 131,10
sys->io_spio = ((sys->io_spio&1)^1)|0x010; |
pic |= SWINT_CLOCK; |
} |
if (buttonstate) |
buttonstate--; |
else |
enableset |= INT_ENABLEV(INT_BUTTON); |
} |
// |
if (pic&INT_BUTTON) { |
206,9 → 142,8
enableset &= ~(INT_ENABLEV(INT_BUTTON)); |
if ((sys->io_spio&0x0f0)==0x030) |
kpanic(); |
} else // We can turn it back on when the button |
// is released |
enableset |= INT_ENABLEV(INT_BUTTON); |
buttonstate = 3; |
} |
if (pic & INT_UARTRX) { |
int v = sys->io_uart; |
|
216,18 → 151,23
kpush_syspipe(rxpipe, v); |
|
// Local Echo |
if (pic & INT_UARTTX) |
if (pic & INT_UARTTX) { |
sys->io_uart = v; |
sys->io_pic = INT_UARTTX; |
pic &= ~INT_UARTTX; |
} |
} |
} if (pic & INT_UARTTX) { |
if (kpop_syspipe(txpipe, (int *)&sys->io_uart)==0) { |
int v; |
if (kpop_syspipe(txpipe, &v)==0) { |
enableset |= (INT_ENABLEV(INT_UARTTX)); |
sys->io_uart= v; |
sys->io_pic = INT_UARTTX; |
} else { |
if (txpipe->m_wrtask) |
txpipe->m_wrtask->state = SCHED_READY; |
// if (v == 'W') |
// sys->io_timb = 5; |
// 75k was writing the 'e' |
} else |
enableset &= ~(INT_ENABLEV(INT_UARTTX)); |
} |
} if (audiostate) { |
if (pic & INT_AUDIO) { |
int v; |
243,6 → 183,7
} 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 |
255,13 → 196,17
// This particular interrupt cannot be cleared |
// until the port has been written to. Hence, |
// now that we've written to the port, we clear |
// it now. |
// 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 v; |
if (kpop_syspipe(pwmpipe, &v)==0) { |
audiostate = (2|(v<<2))&0x03ffff; |
sys->io_pwm_audio = 0x310000 | ((v>>16)&0x0ffff); |
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)); |
sys->io_spio = 0x022; |
sys->io_pic = INT_AUDIO; |
273,34 → 218,34
sys->io_pic = INT_ENABLE|enableset; |
} else { |
sys->io_pic = INT_ENABLE; // Make sure interrupts are on |
int v; |
int 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, &v)==0)) { |
audiostate = (2|(v<<2))&0x03ffff; |
sys->io_pwm_audio = 0x310000 | ((v>>16)&0x0ffff); |
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; |
enableset |= (INT_ENABLEV(INT_AUDIO)); |
sys->io_spio = 0x022; |
nstarts++; |
nread++; |
} // else sys->io_spio = 0x020; |
|
// Or the beginning of a transmit pipe. |
if (pic & INT_UARTTX) { |
if (kpop_syspipe(txpipe, (int *)&sys->io_uart)==0) { |
int v; |
if (kpop_syspipe(txpipe, &v)==0) { |
enableset |= (INT_ENABLEV(INT_UARTTX)); |
sys->io_uart = v; |
sys->io_pic = INT_UARTTX; |
} else { |
if (txpipe->m_wrtask) |
txpipe->m_wrtask = SCHED_READY; |
// if (v == 'W') |
// sys->io_timb = 5; |
} else |
enableset &= ~(INT_ENABLEV(INT_UARTTX)); |
} |
} |
|
// What if the interrupt bit for the buttons is off? |
if ((sys->io_spio & 0x0f0)==0) |
enableset |= INT_ENABLEV(INT_BUTTON); |
|
// What if someone left interrupts off? |
// This might happen as part of a wait trap call, such |
// as syspipe() accomplishes within uwrite_syspipe() |
503,50 → 448,4
} return milliseconds; |
} |
|
void kuserexit(int a) { |
syscall(TRAPID_EXIT, a, 0, 0); |
} |
|
void *sys_malloc(int sz) { |
{ |
SCOPE *s = (SCOPE *)SCOPEADDR; |
s->s_control = TRIGGER_SCOPE_NOW | (s->s_control & 0x0ffff); |
} |
|
void *res = heap; |
heap += sz; |
if ((int)heap > ((int)&res)-32) { |
IOSPACE *sys = (IOSPACE *)IOADDR; |
sys->io_spio = 0xf3; |
asm("break 0"); |
} |
return res; |
} |
|
/* |
// This won't work. Once we apply an rtu(), there will be an immediate |
// interrupt before the task has had a chance to fill in a first value. By |
// instead waiting until the task comes back from it's first task swap, perhaps |
// having stalled it's pipe, then we can get our interrupt up and running. |
// Not only that, but at that time we'll have plenty of info to stuff into the |
// interrupt as well. |
void kwrite_audio(TASKP tsk, int dev, int *dst, int len) { |
kwrite_syspipe(tsk,dev,dst,len); |
if (tsk->context[15] == (int)uwrite_syspipe) { |
IOSPACE *io = (IOSPACE *)IOADDR; |
// Turn our audio interrupt on. |
io->pic = INT_ENABLEV(INT_AUDIO); |
} |
} |
|
void kwrite_txuart(TASKP tsk, int dev, int *dst, int len) { |
kwrite_syspipe(tsk,dev,dst,len); |
if (tsk->context[15] == (int)uwrite_syspipe) { |
IOSPACE *io = (IOSPACE *)IOADDR; |
// Turn our UART transmit interrupt on. |
io->pic = INT_ENABLEV(INT_UARTTX); |
} |
} |
|
*/ |
|
/trunk/sw/zipos/resetdump.s
66,7 → 66,8
MOV PC+1,R0 |
BRA internal_kpanic |
LDI _top_of_stack,SP |
BRA kernel_entry |
LDI kernel_entry,R0 |
BRA bootloader |
|
.global kpanic |
.type kpanic,@function |
105,6 → 106,15
LOD 2(DBG),R2 |
MOV PC+1,R0 |
JMP internal_kpanic |
kpanic_wait_for_button_release: |
LOD (SPIO),R0 |
TEST 0x010,R0 |
BNZ kpanic_wait_for_button_release |
kpanic_wait_for_button: |
LOD (SPIO),R0 |
TEST 0x010,R0 |
BZ kpanic_wait_for_button |
BRA _start |
HALT |
|
internal_kpanic: |
/trunk/sw/zipos/bootloader.c
0,0 → 1,59
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: bootloader.c |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: To copy into RAM, upon boot, sections from the FLASH that |
// need to be placed into RAM. This also handles setting initial |
// values. |
// |
// 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" |
|
// 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; |
|
for(int i=0; i<len; i++) |
mem[i] = flash[i]; |
// 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; |
} |
|
/trunk/sw/zipos/syspipe.c
51,33 → 51,6
#define NULL (void *)0 |
#endif |
|
static void clear_syspipe(SYSPIPE *p) { |
p->m_head = 0; |
p->m_tail = 0; |
p->m_error = 0; |
|
for(int i=0; i<=(int)p->m_mask; i++) |
p->m_buf[i] = 0; |
|
if ((p->m_rdtask)&&(p->m_rdtask != INTERRUPT_READ_TASK)) { |
p->m_rdtask->context[1] = p->m_nread; |
if (p->m_nread == 0) |
p->m_rdtask->errno = -EFAULT; |
p->m_rdtask->state = SCHED_READY; |
} else if (p->m_wrtask) { |
p->m_wrtask->context[1] = p->m_nwritten; |
if (p->m_nwritten == 0) |
p->m_wrtask->errno = -EFAULT; |
p->m_wrtask->state = SCHED_READY; |
} |
|
if (p->m_rdtask != INTERRUPT_READ_TASK) |
p->m_rdtask = 0; |
p->m_wrtask = 0; |
p->m_nread = 0; |
p->m_nwritten = 0; |
} |
|
void kpush_syspipe(SYSPIPE *pipe, int val) { |
int tst = (pipe->m_head+1)&pipe->m_mask; |
if (tst != pipe->m_tail) { |
88,79 → 61,35
} else pipe->m_error = 1; |
} |
|
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; |
|
txstr("SYSPIPE PANIC!\r\n"); |
txstr("ADDR: "); txhex((int)pipe); |
txstr("MASK: "); txhex(pipe->m_mask); |
txstr("HEAD: "); txhex(pipe->m_head); |
txstr("TAIL: "); txhex(pipe->m_tail); |
kpanic(); |
} |
|
extern void pipe_panic(SYSPIPE *p); |
int kpop_syspipe(SYSPIPE *pipe, int *vl) { |
if (pipe->m_head != pipe->m_tail) { |
*vl = pipe->m_buf[pipe->m_tail]; |
pipe->m_tail++; |
if ((unsigned)pipe->m_tail > pipe->m_mask) |
pipe->m_tail = 0; |
pipe->m_tail = (pipe->m_tail+1)&pipe->m_mask; |
if (pipe->m_wrtask) |
pipe->m_wrtask->state = SCHED_READY; |
return 0; |
} return 1; // Error condition |
} |
return 1; // Error condition |
} |
|
SYSPIPE *new_syspipe(const unsigned int len) { |
unsigned msk; |
|
for(msk=2; msk<len; msk<<=1) |
; |
SYSPIPE *pipe = sys_malloc(sizeof(SYSPIPE)-1+msk); |
pipe->m_mask = msk-1; |
pipe->m_rdtask = pipe->m_wrtask = 0; |
clear_syspipe(pipe); |
return pipe; |
} |
|
/* Returns how many values are in the pipe |
*/ |
/* Of course ... if it's not used, why include it? |
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) { |
return (p->m_mask + p->m_tail-p->m_head) & p->m_mask; |
// if (head+1 == tail) PIPE is full |
// (mask+tail-tail+1)=mask+1 &mask = 0 |
// if (head == tail) PIPE is empty |
// (mask+tail-tail)=mask & mask = mask |
// if (head == tail+2) PIPE has two within it |
// (mask+tail-tail-2)=mask-2 & mask = mask-2 |
// |
return (p->m_tail-p->m_head-1) & p->m_mask; |
} |
|
// This will be called from a user context. |
193,9 → 122,11
|
p->m_nread += ln1; |
nleft -= ln1; |
p->m_tail += ln1; |
if ((unsigned)p->m_tail > p->m_mask) |
p->m_tail = 0; |
|
int nt = p->m_tail+ln1; |
if ((unsigned)nt > p->m_mask) |
nt = 0; |
p->m_tail = nt; |
} |
|
// nleft is either zero, or tail |
219,9 → 150,10
|
p->m_nread += ln1; |
nleft -= ln1; |
p->m_tail += ln1; |
if (p->m_tail == (int)p->m_mask+1) |
p->m_tail = 0; |
int nt = p->m_tail+ln1; // nt = new tail value |
if ((unsigned)nt > p->m_mask) |
nt = 0; |
p->m_tail = nt; |
|
if (nleft & -2) |
exit(nleft); |
311,7 → 243,8
return len; |
} |
|
static int uwrite_syspipe(TASKP tsk __attribute__((__unused__)), SYSPIPE *p, int *src, int len) { |
static int uwrite_syspipe(TASKP tsk __attribute__((__unused__)), |
SYSPIPE *p, int *src, int len) { |
int nleft = len; |
|
// The kernel guarantees, before we come into here, that we have a |
327,8 → 260,6
if (rdtask == INTERRUPT_READ_TASK) { |
// We need to copy everything to the buffer |
} else if (rdtask) { |
// #warning "The previous code should have worked" |
// if (((unsigned)rdtask+1) & -2) |
int ln = nleft; |
if (ln > p->m_rdtask->context[4]) |
ln = p->m_rdtask->context[4]; |
371,7 → 302,9
} |
|
// Copy whatever we have into the pipe's buffer |
if ((nleft <= num_avail_syspipe(p))||(rdtask == INTERRUPT_READ_TASK)) { |
int navail = num_avail_syspipe(p); |
if ((nleft <= navail) |
||((rdtask == INTERRUPT_READ_TASK)&&(navail>0))) { |
// Either there is no immediate reader task, or |
// the reader has been exhausted, but we've go |
// more to write. |
381,23 → 314,27
// rest of our buffer will fit. |
|
{ // Write into the first half of the pipe |
// Be careful not to change head until all is written |
// 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++; |
|
p->m_head += ln; |
p->m_head = (p->m_head+ln)&p->m_mask; |
nleft -= ln; |
p->m_nwritten += ln; |
if (p->m_head > (int)p->m_mask) |
p->m_head = 0; |
navail -= ln; |
} |
|
/* |
// Write into the rest of the pipe |
if (nleft > 0) { |
int ln = num_avail_syspipe(p); |
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]; |
408,13 → 345,13
p->m_head += ln; |
p->m_nwritten += ln; |
nleft -= ln; |
} |
}*/ |
} |
|
if (nleft > 0) { |
if ((nleft > 0)&&(navail == 0)) { |
if (rdtask == INTERRUPT_READ_TASK) { |
DISABLE_INTS(); |
if (num_avail_syspipe(p)==0) |
if (0==num_avail_syspipe(p)) |
wait(0,-1); |
else ENABLE_INTS(); |
} else { |
/trunk/sw/zipos/Makefile
45,14 → 45,14
DEVSRCSR:= display.c keypad.c rtcsim.c |
DEVSRCS := $(addprefix ../dev/,$(DEVSRCSR)) |
DEVOBJS := $(addprefix $(OBJDIR)/,$(subst .c,.o,$(DEVSRCSR))) |
SOURCES := kernel.c syspipe.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 # 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 -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 cmod.ld -Wl,-Map,$(OBJDIR)/doorbell.map |
LDFLAGS := -T cmodram.ld -Wl,-Map,$(OBJDIR)/doorbell.map |
|
all: $(OBJDIR)/ doorbell |
$(OBJDIR)/: |
76,7 → 76,7
$(OBJDIR)/resetdump.o: resetdump.s |
$(AS) $^ -o $@ |
|
doorbell: $(OBJECTS) cmod.ld |
doorbell: $(OBJECTS) cmodram.ld |
$(CC) $(LDFLAGS) $(OBJECTS) -o $@ |
|
$(OBJDIR)/doorbell.txt: doorbell |