OpenCores
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 26 to Rev 27
    Reverse comparison

Rev 26 → Rev 27

/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 = .;
}
/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];
/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
 
 
*/
/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
/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;
}
 
/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;
}
 
/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);
}
}
 
*/
 
/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:
/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;
}
 
/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 {
/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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.