diff options
Diffstat (limited to 'src/lib/ppc405lib/string_stream.c')
-rw-r--r-- | src/lib/ppc405lib/string_stream.c | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/src/lib/ppc405lib/string_stream.c b/src/lib/ppc405lib/string_stream.c new file mode 100644 index 0000000..1dfc439 --- /dev/null +++ b/src/lib/ppc405lib/string_stream.c @@ -0,0 +1,410 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/lib/ppc405lib/string_stream.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +// $Id: string_stream.c,v 1.2 2014/02/03 01:30:25 daviddu Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/string_stream.c,v $ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2013 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- + +/// \file string_stream.c +/// \brief Implementations of string streams. +/// +/// \bug Need to work out overwrite/multiple-write protection. + +#include "ssx.h" +#include "string_stream.h" + + +// 'Flush' a string stream by making it empty + +static int +string_stream_fflush(FILE* stream) +{ + StringStream* string = (StringStream*) stream; + + string->next_read = 0; + string->next_write = 0; + string->flags &= ~STRING_STREAM_FULL; + return 0; +} + + +// Read the remaining tail (if any) of the circular buffer, assuming the +// buffer is not empty. + +static size_t +read_tail(StringStream* string, void* buf, size_t size) +{ + size_t read, remainder; + + read = 0; + if (string->next_read >= string->next_write) { + + remainder = string->size - string->next_read; + read = MIN(size, remainder); + memcpy(buf, (void *)(&(string->data[string->next_read])), read); + if (read != remainder) { + string->next_read += read; + } else { + string->next_read = 0; + } + } + return read; +} + + +// Read the area (if any) from the read pointer to the write pointer + +static size_t +read_head(StringStream* string, void* buf, size_t size) +{ + size_t read, remainder; + + read = 0; + if (string->next_write > string->next_read) { + + remainder = string->next_write - string->next_read; + read = MIN(size, remainder); + memcpy(buf, (void *)(&(string->data[string->next_read])), read); + string->next_read += read; + } + return read; +} + + +// Read as much data as possible from a circular buffer. Return -EAGAIN if the +// buffer would underflow. + +static int +string_stream_sread(FILE* stream, void* buf, size_t size, size_t* read) +{ + StringStream *string = (StringStream *)stream; + size_t were_read; + int rc; + + if ((string->next_read == string->next_write) && + !(string->flags & STRING_STREAM_FULL)) { + were_read = 0; + } else { + were_read = read_tail(string, buf, size); + if (were_read != size) { + were_read += read_head(string, buf + were_read, size - were_read); + } + } + if (were_read != 0) { + string->flags &= ~STRING_STREAM_FULL; + } + *read = were_read; + if (were_read < size) { + rc = -EAGAIN; + } else { + rc = 0; + } + return rc; +} + + + + +// Write the remaining tail (if any) of the circular buffer, assuming the +// buffer is not full. + +static size_t +write_tail(StringStream* string, const void* buf, size_t size) +{ + size_t written, remainder; + + written = 0; + if (string->next_write >= string->next_read) { + + remainder = string->size - string->next_write; // string->size is the size of the stream(our buffer) + written = MIN(size, remainder); + // memcpy(void *dest, const void *src, size_t n) from /lib/memcpy.c + memcpy((void *)(&(string->data[string->next_write])), buf, written); + if (written != remainder) { + string->next_write += written; + } else { + string->next_write = 0; + } + } + return written; +} + +// Write the area (if any) from the write pointer to the read pointer + +static size_t +write_head(StringStream* string, const void* buf, size_t size) +{ + size_t written, remainder; + + written = 0; + if (string->next_read > string->next_write) { + + remainder = string->next_read - string->next_write; + written = MIN(size, remainder); + memcpy((void *)(&(string->data[string->next_write])), buf, written); + string->next_write += written; + } + return written; +} + + +// Write as much data as possible to a circular buffer. Return -EAGAIN if the +// buffer would overflow. + +static int +circular_swrite(FILE* stream, const void* buf, size_t size, size_t* written) +{ + StringStream *string = (StringStream *)stream; + size_t wrote; + int rc; + + if (string->flags & STRING_STREAM_FULL) { + wrote = 0; + } else { + wrote = write_tail(string, buf, size); + if (wrote != size) { + wrote += write_head(string, buf + wrote, size - wrote); + } + } + if ((wrote != 0) && (string->next_read == string->next_write)) { + string->flags |= STRING_STREAM_FULL; + } + *written = wrote; + if (wrote < size) { + rc = -EAGAIN; + } else { + rc = 0; + } + return rc; +} + + +// Effectively write all data to a circular buffer with wrapping semantics. + +static int +wrapping_swrite(FILE* stream, const void* buf, size_t size, size_t* written) +{ + StringStream *string = (StringStream *)stream; + size_t wrote; + int rc; + + if (size >= string->size) { // If size of data >= size of buffer + + // If the amount of data will fill or overflow the entire buffer size + // then we effectively fill the buffer with the final bytes of data. + + string->next_read = 0; + string->next_write = 0; + string->flags |= STRING_STREAM_FULL; + memcpy((void *)string->data, buf + (size - string->size), size); + + } else { + + // If the string is not full, try to fill it with the + // circular_swrite(). + + if (string->flags & STRING_STREAM_FULL) { + wrote = 0; + rc = -EAGAIN; + } else { + rc = circular_swrite(stream, buf, size, &wrote); + } + if (rc) { + + // The string is full and we need to overflow. We know that size + // is less than the buffer size, and the next_read == next_write. + // Mark the stream not full so a new circular write will work, and + // at the end reset the full condition. + + string->flags &= ~STRING_STREAM_FULL; + rc = circular_swrite(stream, buf + wrote, size - wrote, &wrote); + if (rc) { + SSX_PANIC(STRING_STREAM_BUG); + } + string->next_read = string->next_write; + string->flags |= STRING_STREAM_FULL; + } + } + *written = size; + return 0; +} + + +static int +linear_swrite(FILE* stream, const void* buf, size_t size, size_t* written) +{ + // buf and size correspond to the data we are passing to our own buffer + uint32_t bit_0_mask = 0x80000000; + StringStream *string = (StringStream *)stream; + size_t wrote = 0; // right aligned + // int rc; + uint32_t num_bytes_written; + // uint32_t register_contents; + + + //if (wrote != size) { + // register_contents = in32(PMC_PORE_SCRATCH_REG1); + // register_contents = register_contents & bit_0_mask; + + //if (!register_contents) { + // Before writing to SRAM, flush everything so it will write to the top + // of the buffer each time + string_stream_fflush(stream); + + // Write printk statement to SRAM + // wrote will contain the number of bytes written + + wrote += write_tail(string, buf + wrote, size - wrote); + // if wrote != size, tell Tcl to read the whole buffer, When Tcl is done loop back to write_tail + // buf= buf+wrote + // size= size - wrote + // continue loop until size = 0 + + // Sync + eieio(); + + // Store "wrote" to register + // Set bit 0 to 1 + // out32(addr, data) + num_bytes_written = (uint32_t)wrote | bit_0_mask; + out32( PMC_PORE_SCRATCH_REG1 , num_bytes_written ); + + // Sync + eieio(); + //} + //} + + // outside of loop, set *written = wrote (which is equal to size once all data has been copied to our buffer) + *written = wrote; + return 0; + +} + + +int +_string_stream_create(StringStream* stream, + void* buf, size_t size, int flags, + int (*swrite)(FILE* stream, + const void* buf, + size_t size, + size_t* written)) +{ + FILE* file = (FILE*)stream; + int rc; + + if (SSX_ERROR_CHECK_API) { + SSX_ERROR_IF((stream == 0) || + ((buf == 0) && (size != 0)), + STRING_STREAM_INVALID_ARGUMENT); + } + + rc = FILE_create(file, flags); + + if (!rc) { + file->swrite = swrite; + file->sread = string_stream_sread; + file->fflush = string_stream_fflush; + stream->data = buf; + stream->size = size; + stream->next_read = 0; + stream->next_write = 0; + stream->flags = 0; + } + return rc; +} + + +int +circular_stream_create(CircularStream* stream, + void* buf, size_t size, int flags) +{ + return _string_stream_create(stream, buf, size, flags, circular_swrite); +} + + +int +wrapping_stream_create(CircularStream* stream, + void* buf, size_t size, int flags) +{ + return _string_stream_create(stream, buf, size, flags, wrapping_swrite); +} + + +int +linear_stream_create(CircularStream* stream, + void* buf, size_t size, int flags) +{ + FILE* file = (FILE*)stream; + int rc; + + rc = _string_stream_create(stream, buf, size, flags, linear_swrite); + if (!rc) { + + file->sread = NULL; + // Write to register where location of buffer is + out32( PMC_PORE_SCRATCH_REG1, (uint32_t)buf); + } + return rc; +} + + +// InputStream uses string_stream_sread(), however returns EOF once all data +// has been read. + +static int +input_stream_sread(FILE* stream, void* buf, size_t size, size_t* read) +{ + int rc; + + rc = string_stream_sread(stream, buf, size, read); + if (rc == -EAGAIN) { + rc = EOF; + } + + return rc; +} + + +// For simplicity (and ease of maintainence) we create a normal string stream +// then overwrite a few key fields. + +int +input_stream_create(StringStream* stream, void* buf, size_t size, int flags) +{ + int rc; + + rc = _string_stream_create(stream, buf, size, flags, 0); + if (!rc) { + stream->stream.sread = input_stream_sread; + stream->stream.fflush = 0; + stream->flags = STRING_STREAM_FULL; + } + return rc; +} + + |