URL
https://opencores.org/ocsvn/s6soc/s6soc/trunk
Subversion Repositories s6soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 48 to Rev 49
- ↔ Reverse comparison
Rev 48 → Rev 49
/s6soc/trunk/bench/cpp/Makefile
6,8 → 6,9
# |
# Purpose: This makefile builds the final verilator simulation of the |
# zipsystem. Specifically, it builds the final C++ portion |
# of the simulator, and thus the final simulator executable. |
# of the simulator, and thus the final simulator executable. |
# |
# This simulator depends upon the libelf library. |
# |
# Creator: Dan Gisselquist, Ph.D. |
# Gisselquist Technology, LLC |
14,7 → 15,7
# |
################################################################################ |
# |
# Copyright (C) 2015, 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 |
35,37 → 36,59
all: zip_sim |
|
CXX := g++ |
FLAGS := -Wall -Og -g |
CFLAGS := -Wall -Og -g |
OBJDIR := obj-pc |
SWHOST := ../../sw/host |
RTLD := ../../rtl |
INCS := -I$(RTLD)/obj_dir/ -I$(RTLD) -I/usr/share/verilator/include \ |
-I$(SWHOST) |
SOURCES := zip_sim.cpp twoc.cpp qspiflashsim.cpp uartsim.cpp |
VLIB := /usr/share/verilator/include/verilated.cpp |
RAWLIB := $(VLIB) $(RTLD)/obj_dir/Vbusmaster__ALL.a |
RTLOBJD := $(RTLD)/obj_dir |
VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT | head -1 | sed -e " s/^.*=\s*//"') |
VROOT := $(VERILATOR_ROOT) |
VINCS := -I$(VROOT)/include -I$(VROOT)/include/vltstd |
INCS := -I$(RTLOBJD) -I$(RTLD) -I$(VROOT)/include -I$(SWHOST) $(VINCS) |
SOURCES := zip_sim.cpp twoc.cpp qspiflashsim.cpp uartsim.cpp zipelf.cpp byteswap.cpp |
VLSRCS := verilated.cpp verilated_vcd_c.cpp |
VLOBJS := $(OBJDIR)/verilated.o $(OBJDIR)/verilated_vcd_c.o |
VLIB := $(addprefix $(VROOT)/include/,$(VLSRCS)) |
RAWLIB := $(RTLOBJD)/Vbusmaster__ALL.a |
OBJECTS := $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(SOURCES) $(VLSRCS))) |
LIBS := $(RAWLIB) -lelf |
TESTF := $(ZASM)/z.out |
DHRYSTONEF := ../asm/zipdhry.z |
|
zip_sim: $(SOURCES) $(RAWLIB) testb.h |
$(CXX) $(FLAGS) $(INCS) $(SOURCES) $(LIBS) -o $@ |
$(OBJDIR)/%.o: %.cpp |
$(CXX) $(CFLAGS) $(INCS) -c $< -o $@ |
|
# .PHONY: stest |
# stest: zippy_tb |
# ./zippy_tb -s $(TESTF) |
$(OBJDIR)/%.o: $(VROOT)/include/%.cpp |
$(CXX) $(CFLAGS) $(INCS) -c $< -o $@ |
|
# .PHONY: itest |
# itest: zippy_tb |
# ./zippy_tb $(TESTF) |
zip_sim: $(OBJECTS) |
$(CXX) $(CFLAGS) $(INCS) $(OBJECTS) $(LIBS) -o $@ |
|
# .PHONY: test |
# test: zippy_tb stest |
# ./zippy_tb -a $(TESTF) |
|
# .PHONY: dhrystone |
# dhrystone: zippy_tb |
# ./zippy_tb -a $(DHRYSTONEF) |
|
|
define build-depends |
@echo "Building dependencies" |
@$(CXX) $(CFLAGS) $(INCS) -MM $(VLIB) $(SOURCES) > $(OBJDIR)/xdepends.txt |
@sed -e 's/^.*.o: /$(OBJDIR)\/&/' < $(OBJDIR)/xdepends.txt > $(OBJDIR)/depends.txt |
@rm $(OBJDIR)/xdepends.txt |
endef |
|
tags: $(VLIB) $(SOURCES) |
@ctags $(SOURCES) $(VLIB) |
|
.PHONY: depends |
depends: tags $(OBJDIR)/ |
$(build-depends) |
|
$(OBJDIR)/: |
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR)/; fi" |
|
$(OBJDIR)/depends.txt: $(OBJDIR)/ depends |
|
.PHONY: clean |
clean: |
rm ./zip_sim |
rm -rf $(OBJDIR)/ |
rm -f ./zip_sim |
|
-include $(OBJDIR)/depends.txt |
/s6soc/trunk/bench/cpp/byteswap.cpp
0,0 → 1,86
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: byteswap.cpp |
// |
// Project: OpenArty, an entirely open SoC based upon the Arty platform |
// |
// Purpose: |
// |
// 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 <stdint.h> |
#include "byteswap.h" |
|
uint32_t |
byteswap(uint32_t v) { |
uint32_t r = 0; |
|
r = (v & 0x0ff); |
r <<= 8; v >>= 8; |
r |= (v & 0x0ff); |
r <<= 8; v >>= 8; |
r |= (v & 0x0ff); |
r <<= 8; v >>= 8; |
r |= (v & 0x0ff); |
|
return r; |
} |
|
uint32_t |
buildword(const unsigned char *p) { |
uint32_t r = 0; |
|
r = (*p++); r <<= 8; |
r |= (*p++); r <<= 8; |
r |= (*p++); r <<= 8; |
r |= (*p ); |
|
return r; |
} |
|
uint32_t |
buildswap(const unsigned char *p) { |
uint32_t r = 0; |
|
r = p[3]; r <<= 8; |
r |= p[2]; r <<= 8; |
r |= p[1]; r <<= 8; |
r |= p[0]; |
|
return r; |
} |
|
void |
byteswapbuf(int ln, uint32_t *buf) { |
for(int i=0; i<ln; i++) |
buf[i] = byteswap(buf[i]); |
} |
|
|
/s6soc/trunk/bench/cpp/byteswap.h
0,0 → 1,54
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: byteswap.h |
// |
// Project: OpenArty, an entirely open SoC based upon the Arty platform |
// |
// Purpose: |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#ifndef BYTESWAP_H |
#define BYTESWAP_H |
|
#include <stdint.h> |
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
extern uint32_t byteswap(uint32_t v); |
extern void byteswapbuf(int ln, uint32_t *buf); |
#else |
#define byteswap(A) (A) |
#define byteswapbuf(A, B) |
#endif |
|
extern uint32_t buildword(const unsigned char *p); |
extern uint32_t buildswap(const unsigned char *p); |
|
#endif |
/s6soc/trunk/bench/cpp/qspiflashsim.cpp
1,4 → 1,4
/////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// Filename: spiflashsim.cpp |
14,12 → 14,12
// environment, where this simulator can be used in place of |
// the actual hardware. |
// |
// Creator: Dan Gisselquist |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, 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 |
32,7 → 32,7
// 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 |
// 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. |
// |
40,7 → 40,9
// http://www.gnu.org/licenses/gpl.html |
// |
// |
/////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include <stdio.h> |
#include <string.h> |
#include <assert.h> |
49,7 → 51,8
#include "regdefs.h" |
#include "qspiflashsim.h" |
|
#define MEMBYTES (FLASHWORDS<<2) |
#define MEMBYTES (1<<24) |
#define MEMMASK ((MEMBYTES)-1) |
|
static const unsigned DEVID = 0x0115, |
DEVESD = 0x014, |
75,7 → 78,7
m_write_count = 0; |
m_ireg = m_oreg = 0; |
m_sreg = 0x01c; |
m_creg = 0x001; // Iinitial creg on delivery |
m_creg = 0x003; // Initial creg on delivery--assumes quad mode enabled |
m_quad_mode = false; |
m_mode_byte = 0; |
|
84,6 → 87,7
|
void QSPIFLASHSIM::load(const unsigned addr, const char *fname) { |
FILE *fp; |
int nr = 0; |
size_t len; |
|
if (addr >= MEMBYTES) |
91,7 → 95,6
len = MEMBYTES-addr*4; |
|
if (NULL != (fp = fopen(fname, "r"))) { |
int nr = 0; |
nr = fread(&m_mem[addr], sizeof(char), len, fp); |
fclose(fp); |
if (nr == 0) { |
104,15 → 107,10
} |
} |
|
void QSPIFLASHSIM::write(const unsigned addr, const unsigned len, const uint32_t *buf) { |
char *ptr; |
if ((addr+len < SPIFLASH)||(addr >= SPIFLASH+MEMBYTES/4)) |
return; |
printf("FLASH: Copying into memory at S6Add4 %08x, my addr %08x, %d values\n", |
addr, (addr-SPIFLASH)<<2, len<<2); |
ptr = &m_mem[(addr-SPIFLASH)<<2]; |
memcpy(ptr, buf, len<<2); |
printf("%02x %02x %02x %02x\n", ptr[0]&0x0ff, ptr[1]&0x0ff, ptr[2]&0x0ff, ptr[3]&0x0ff); |
void QSPIFLASHSIM::write(const unsigned offset, const unsigned len, const char *buf) { |
uint32_t moff = (offset & (MEMBYTES-1)); |
|
memcpy(&m_mem[moff], buf, len); |
} |
|
#define QOREG(A) m_oreg = ((m_oreg & (~0x0ff))|(A&0x0ff)) |
230,9 → 228,9
assert(m_quad_mode); |
if (m_count == 24) { |
if (m_debug) printf("QSPI: Entering from Quad-Read Idle to Quad-Read\n"); |
if (m_debug) printf("QSPI: QI/O Idle Addr = %02x\n", m_ireg&0x0ffffff); |
m_addr = (m_ireg) & 0x0ffffff; |
assert((m_addr & 0xfc00000)==0); |
if (m_debug) printf("QSPI: QI/O Idle Addr = %02x\n", m_ireg&MEMMASK); |
m_addr = (m_ireg) & MEMMASK; |
assert((m_addr & (~(MEMMASK)))==0); |
m_state = QSPIF_QUAD_READ; |
} m_oreg = 0; |
} else if (m_count == 8) { |
374,7 → 372,7
break; |
case QSPIF_RDID: |
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffffff; |
m_addr = m_ireg & MEMMASK; |
if (m_debug) printf("READID, ADDR = %08x\n", m_addr); |
QOREG((DEVID>>8)); |
if (m_debug) printf("QSPI: READING ID, %02x\n", (DEVID>>8)&0x0ff); |
398,15 → 396,15
break; |
case QSPIF_FAST_READ: |
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffffff; |
m_addr = m_ireg & MEMMASK; |
if (m_debug) printf("FAST READ, ADDR = %08x\n", m_addr); |
QOREG(0x0c3); |
assert((m_addr & 0xfc00000)==0); |
if (m_addr & (~(MEMMASK))) { |
printf("QSPI: ADDR = %08x ? !!\n", m_addr); |
} assert((m_addr & (~(MEMMASK)))==0); |
} else if ((m_count >= 40)&&(0 == (m_sreg&0x01))) { |
//if (m_count == 40) |
//printf("DUMMY BYTE COMPLETE ...\n"); |
QOREG(m_mem[m_addr++]); |
// if (m_debug) printf("SPIF[%08x] = %02x\n", m_addr-1, m_oreg); |
if (m_debug) printf("SPIF[%08x] = %02x\n", m_addr-1, m_oreg); |
} else m_oreg = 0; |
break; |
case QSPIF_QUAD_READ_CMD: |
414,17 → 412,18
// that changes the timings, else we'd use quad_Read |
// below |
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffffff; |
// printf("FAST READ, ADDR = %08x\n", m_addr); |
// printf("QSPI: QUAD READ, ADDR = %06x\n", m_addr); |
assert((m_addr & 0xfc00000)==0); |
m_addr = m_ireg & MEMMASK; |
if (m_debug) printf("QSPI: QUAD READ, ADDR = %06x\n", m_addr); |
assert((m_addr & (~(MEMMASK)))==0); |
} else if (m_count == 32+24) { |
m_mode_byte = (m_ireg>>16) & 0x0ff; |
// printf("QSPI: MODE BYTE = %02x\n", m_mode_byte); |
if (m_debug) printf("QSPI: MODE BYTE = %02x\n", m_mode_byte); |
// Send the first byte in the response ... since it's time to start sending bytes |
QOREG(m_mem[m_addr++]); |
} else if ((m_count > 32+24)&&(0 == (m_sreg&0x01))) { |
QOREG(m_mem[m_addr++]); |
// printf("QSPIF[%08x]/QR = %02x\n", |
// m_addr-1, m_oreg); |
if (m_debug) printf("QSPIF[%08x]/QR = %02x\n", |
m_addr-1, m_oreg); |
} else m_oreg = 0; |
break; |
case QSPIF_QUAD_READ: |
433,14 → 432,14
// printf("QSPI/QR: MODE BYTE = %02x\n", m_mode_byte); |
} else if ((m_count >= 32+16)&&(0 == (m_sreg&0x01))) { |
QOREG(m_mem[m_addr++]); |
// printf("QSPIF[%08x]/QR = %02x\n", m_addr-1, m_oreg & 0x0ff); |
if (m_debug) printf("QSPIF[%08x]/QR = %02x\n", m_addr-1, m_oreg & 0x0ff); |
} else m_oreg = 0; |
break; |
case QSPIF_PP: |
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffffff; |
m_addr = m_ireg & MEMMASK; |
if (m_debug) printf("QSPI: PAGE-PROGRAM ADDR = %06x\n", m_addr); |
assert((m_addr & 0xfc00000)==0); |
assert((m_addr & (~(MEMMASK)))==0); |
// m_page = m_addr >> 8; |
for(int i=0; i<256; i++) |
m_pmem[i] = 0x0ff; |
451,10 → 450,10
} break; |
case QSPIF_QPP: |
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffffff; |
m_addr = m_ireg & MEMMASK; |
m_quad_mode = true; |
if (m_debug) printf("QSPI/QR: PAGE-PROGRAM ADDR = %06x\n", m_addr); |
assert((m_addr & 0xfc00000)==0); |
assert((m_addr & (~(MEMMASK)))==0); |
// m_page = m_addr >> 8; |
for(int i=0; i<256; i++) |
m_pmem[i] = 0x0ff; |
467,7 → 466,7
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffc000; |
if (m_debug) printf("SECTOR_ERASE ADDRESS = %08x\n", m_addr); |
assert((m_addr & 0xfc00000)==0); |
assert((m_addr & (~(MEMMASK)))==0); |
} break; |
case QSPIF_RELEASE: |
if (m_count >= 32) { |
/s6soc/trunk/bench/cpp/qspiflashsim.h
1,4 → 1,4
/////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: spiflashsim.h |
// |
9,12 → 9,12
// board by Digilent. As such, it is defined by 32 Mbits of |
// memory (4 Mbyte). |
// |
// Creator: Dan Gisselquist |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
/////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, 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 |
27,7 → 27,7
// 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 |
// 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. |
// |
35,7 → 35,9
// http://www.gnu.org/licenses/gpl.html |
// |
// |
/////////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#ifndef QSPIFLASHSIM_H |
#define QSPIFLASHSIM_H |
|
76,7 → 78,7
QSPIFLASHSIM(void); |
void load(const char *fname) { load(0, fname); } |
void load(const unsigned addr, const char *fname); |
void write(const unsigned addr, const unsigned len, const uint32_t *buf); |
void write(const unsigned addr, const unsigned len, const char *buf); |
void debug(const bool dbg) { m_debug = dbg; } |
bool debug(void) const { return m_debug; } |
int operator()(const int csn, const int sck, const int dat); |
/s6soc/trunk/bench/cpp/testb.h
12,7 → 12,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, 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 |
37,25 → 37,56
#ifndef TESTB_H |
#define TESTB_H |
|
#include <stdio.h> |
#include <stdint.h> |
#include <verilated_vcd_c.h> |
|
template <class VA> class TESTB { |
public: |
VA *m_core; |
VerilatedVcdC* m_trace; |
unsigned long m_tickcount; |
|
TESTB(void) { m_core = new VA; } |
virtual ~TESTB(void) { delete m_core; m_core = NULL; } |
TESTB(void) : m_trace(NULL), m_tickcount(0l) { |
m_core = new VA; |
Verilated::traceEverOn(true); |
} |
virtual ~TESTB(void) { |
if (m_trace) m_trace->close(); |
delete m_core; |
m_core = NULL; |
} |
|
virtual void opentrace(const char *vcdname) { |
m_trace = new VerilatedVcdC; |
m_core->trace(m_trace, 99); |
m_trace->open(vcdname); |
} |
|
virtual void closetrace(void) { |
if (m_trace) { |
m_trace->close(); |
m_trace = NULL; |
} |
} |
|
virtual void eval(void) { |
m_core->eval(); |
} |
|
virtual void tick(void) { |
m_tickcount++; |
|
//if((m_trace)&&(m_tickcount)) m_trace->dump(10*m_tickcount-4); |
eval(); |
if ((m_trace)&&(m_tickcount)) m_trace->dump(10*m_tickcount-2); |
m_core->i_clk = 1; |
eval(); |
if (m_trace) m_trace->dump(10*m_tickcount); |
m_core->i_clk = 0; |
eval(); |
if (m_trace) m_trace->dump(10*m_tickcount+5); |
|
m_tickcount++; |
} |
|
virtual void reset(void) { |
62,7 → 93,6
m_core->i_rst = 1; |
tick(); |
m_core->i_rst = 0; |
m_tickcount = 0l; |
// printf("RESET\n"); |
} |
}; |
/s6soc/trunk/bench/cpp/uartsim.cpp
1,69 → 1,349
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: uartsim.cpp |
// |
// Filename: uartsim.cpp |
// Project: wbuart32, a full featured UART with simulator |
// |
// Project: FPGA library development (S6 development board) |
// Purpose: To forward a Verilator simulated UART link over a TCP/IP pipe. |
// |
// Purpose: To emulate the external parameters of a UART device, providing |
// the UART output to, and input from, the command |
// console/terminal while also providing the controller with |
// appropriate busy lines as necessary. |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
// Creator: Dan Gisselquist |
// Gisselquist Tecnology, LLC |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright: 2016 |
// 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 |
// 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 <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <sys/types.h> |
#include <sys/socket.h> |
#include <poll.h> |
#include <unistd.h> |
#include <fcntl.h> |
#include <stdio.h> |
#include <arpa/inet.h> |
#include <signal.h> |
#include <ctype.h> |
|
#include "uartsim.h" |
|
UARTSIM::UARTSIM(int baud_counts, int fdin, int fdout) { |
int fctl_flags; |
void UARTSIM::setup_listener(const int port) { |
struct sockaddr_in my_addr; |
|
m_fdin = fdin; |
m_fdout = fdout; |
m_baud_counts = baud_counts; |
signal(SIGPIPE, SIG_IGN); |
|
m_tx_busy_count = 0; |
m_rx_busy_count = -1; |
printf("Listening on port %d\n", port); |
|
// Set the linux O_NONBLOCK on fdin |
fctl_flags = fcntl(fdin, F_GETFL, 0); |
fcntl(fdin, F_SETFL, fctl_flags | O_NONBLOCK); |
m_skt = socket(AF_INET, SOCK_STREAM, 0); |
if (m_skt < 0) { |
perror("Could not allocate socket: "); |
exit(-1); |
} |
|
// Set the reuse address option |
{ |
int optv = 1, er; |
er = setsockopt(m_skt, SOL_SOCKET, SO_REUSEADDR, &optv, sizeof(optv)); |
if (er != 0) { |
perror("SockOpt Err:"); |
exit(-1); |
} |
} |
|
memset(&my_addr, 0, sizeof(struct sockaddr_in)); // clear structure |
my_addr.sin_family = AF_INET; |
// Use *all* internet ports to this computer, allowing connections from |
// any/every one of them. |
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); |
my_addr.sin_port = htons(port); |
|
if (bind(m_skt, (struct sockaddr *)&my_addr, sizeof(my_addr))!=0) { |
perror("BIND FAILED:"); |
exit(-1); |
} |
|
if (listen(m_skt, 1) != 0) { |
perror("Listen failed:"); |
exit(-1); |
} |
} |
|
int UARTSIM::rx(unsigned char &data) { |
if (m_rx_busy_count >= 0) { |
if (m_rx_busy_count-- == 0) { |
data = (unsigned char)m_rx_next; |
return 1; |
UARTSIM::UARTSIM(const int port) { |
m_conrd = m_conwr = m_skt = -1; |
if (port == 0) { |
m_conrd = STDIN_FILENO; |
m_conwr = STDOUT_FILENO; |
} else |
setup_listener(port); |
setup(25); // Set us up for (default) 8N1 w/ a baud rate of CLK/25 |
m_rx_baudcounter = 0; |
m_tx_baudcounter = 0; |
m_rx_state = RXIDLE; |
m_tx_state = TXIDLE; |
} |
|
void UARTSIM::kill(void) { |
fflush(stdout); |
|
// Quickly double check that we aren't about to close stdin/stdout |
if (m_conrd == STDIN_FILENO) |
m_conwr = -1; |
if (m_conwr == STDOUT_FILENO) |
m_conwr = -1; |
// Close any active connection |
if (m_conrd >= 0) close(m_conrd); |
if ((m_conwr >= 0)&&(m_conwr != m_conrd)) close(m_conwr); |
if (m_skt >= 0) close(m_skt); |
|
m_conrd = m_conwr = m_skt = -1; |
} |
|
void UARTSIM::setup(unsigned isetup) { |
if (isetup != m_setup) { |
m_setup = isetup; |
m_baud_counts = (isetup & 0x0ffffff); |
m_nbits = 8-((isetup >> 28)&0x03); |
m_nstop =((isetup >> 27)&1)+1; |
m_nparity = (isetup >> 26)&1; |
m_fixdp = (isetup >> 25)&1; |
m_evenp = (isetup >> 24)&1; |
} |
} |
|
int UARTSIM::nettick(int i_tx) { |
int o_rx = 1; |
|
if ((m_conrd < 0)&&(m_conwr<0)&&(m_skt>=0)) { |
// Can we accept a connection? |
struct pollfd pb; |
|
pb.fd = m_skt; |
pb.events = POLLIN; |
poll(&pb, 1, 0); |
|
if (pb.revents & POLLIN) { |
m_conrd = accept(m_skt, 0, 0); |
m_conwr = m_conrd; |
|
if (m_conrd < 0) |
perror("Accept failed:"); |
} |
} |
|
if (read(m_fdin, &m_rx_next, 1) > 0) |
m_rx_busy_count = m_baud_counts; |
if ((!i_tx)&&(m_last_tx)) |
m_rx_changectr = 0; |
else m_rx_changectr++; |
m_last_tx = i_tx; |
|
return 0; |
if (m_rx_state == RXIDLE) { |
if (!i_tx) { |
m_rx_state = RXDATA; |
m_rx_baudcounter =m_baud_counts+m_baud_counts/2-1; |
m_rx_baudcounter -= m_rx_changectr; |
m_rx_busy = 0; |
m_rx_data = 0; |
} |
} else if (m_rx_baudcounter <= 0) { |
if (m_rx_busy >= (1<<(m_nbits+m_nparity+m_nstop-1))) { |
m_rx_state = RXIDLE; |
if (m_conwr >= 0) { |
char buf[1]; |
buf[0] = (m_rx_data >> (32-m_nbits-m_nstop-m_nparity))&0x0ff; |
if (1 != send(m_conwr, buf, 1, 0)) { |
close(m_conwr); |
m_conrd = m_conwr = -1; |
} |
} |
} else { |
m_rx_busy = (m_rx_busy << 1)|1; |
// Low order bit is transmitted first, in this |
// order: |
// Start bit (1'b1) |
// bit 0 |
// bit 1 |
// bit 2 |
// ... |
// bit N-1 |
// (possible parity bit) |
// stop bit |
// (possible secondary stop bit) |
m_rx_data = ((i_tx&1)<<31) | (m_rx_data>>1); |
} m_rx_baudcounter = m_baud_counts-1; |
} else |
m_rx_baudcounter--; |
|
if (m_tx_state == TXIDLE) { |
struct pollfd pb; |
pb.fd = m_conrd; |
pb.events = POLLIN; |
if (poll(&pb, 1, 0) < 0) |
perror("Polling error:"); |
if (pb.revents & POLLIN) { |
char buf[1]; |
if (1 == recv(m_conrd, buf, 1, MSG_DONTWAIT)) { |
m_tx_data = (-1<<(m_nbits+m_nparity+1)) |
// << nstart_bits |
|((buf[0]<<1)&0x01fe); |
if (m_nparity) { |
int p; |
|
// If m_nparity is set, we need to then |
// create the parity bit. |
if (m_fixdp) |
p = m_evenp; |
else { |
p = (m_tx_data >> 1)&0x0ff; |
p = p ^ (p>>4); |
p = p ^ (p>>2); |
p = p ^ (p>>1); |
p &= 1; |
p ^= m_evenp; |
} |
m_tx_data |= (p<<(m_nbits+m_nparity)); |
} |
m_tx_busy = (1<<(m_nbits+m_nparity+m_nstop+1))-1; |
m_tx_state = TXDATA; |
o_rx = 0; |
m_tx_baudcounter = m_baud_counts-1; |
} |
} |
} else if (m_tx_baudcounter <= 0) { |
m_tx_data >>= 1; |
m_tx_busy >>= 1; |
if (!m_tx_busy) |
m_tx_state = TXIDLE; |
else |
m_tx_baudcounter = m_baud_counts-1; |
o_rx = m_tx_data&1; |
} else { |
m_tx_baudcounter--; |
o_rx = m_tx_data&1; |
} |
|
return o_rx; |
} |
|
int UARTSIM::tx(int stb, char data) { |
if (m_tx_busy_count > 0) { |
int UARTSIM::fdtick(int i_tx) { |
int o_rx = 1; |
|
// This write may block--if so, we don't care. Just write it. |
if (--m_tx_busy_count == 0) |
if (write(m_fdout, &m_tx_data, 1) != 1) |
perror("O/S Write Err:"); |
return 1; |
} else if (stb) { |
m_tx_data = data; |
m_tx_busy_count = m_baud_counts; |
if ((!i_tx)&&(m_last_tx)) |
m_rx_changectr = 0; |
else m_rx_changectr++; |
m_last_tx = i_tx; |
|
if (m_rx_state == RXIDLE) { |
if (!i_tx) { |
m_rx_state = RXDATA; |
m_rx_baudcounter =m_baud_counts+m_baud_counts/2-1; |
m_rx_baudcounter -= m_rx_changectr; |
m_rx_busy = 0; |
m_rx_data = 0; |
} |
} else if (m_rx_baudcounter <= 0) { |
if (m_rx_busy >= (1<<(m_nbits+m_nparity+m_nstop-1))) { |
m_rx_state = RXIDLE; |
if (m_conwr >= 0) { |
char buf[1]; |
buf[0] = (m_rx_data >> (32-m_nbits-m_nstop-m_nparity))&0x0ff; |
if (1 != write(m_conwr, buf, 1)) { |
fprintf(stderr, "ERR while attempting to write out--closing output port\n"); |
perror("UARTSIM::write() "); |
m_conrd = m_conwr = -1; |
} |
} |
} else { |
m_rx_busy = (m_rx_busy << 1)|1; |
// Low order bit is transmitted first, in this |
// order: |
// Start bit (1'b1) |
// bit 0 |
// bit 1 |
// bit 2 |
// ... |
// bit N-1 |
// (possible parity bit) |
// stop bit |
// (possible secondary stop bit) |
m_rx_data = ((i_tx&1)<<31) | (m_rx_data>>1); |
} m_rx_baudcounter = m_baud_counts-1; |
} else |
m_rx_baudcounter--; |
|
if ((m_tx_state == TXIDLE)&&(m_conrd >= 0)) { |
struct pollfd pb; |
pb.fd = m_conrd; |
pb.events = POLLIN; |
if (poll(&pb, 1, 0) < 0) |
perror("Polling error:"); |
if (pb.revents & POLLIN) { |
char buf[1]; |
int nr; |
if (1==(nr = read(m_conrd, buf, 1))) { |
m_tx_data = (-1<<(m_nbits+m_nparity+1)) |
// << nstart_bits |
|((buf[0]<<1)&0x01fe); |
if (m_nparity) { |
int p; |
|
// If m_nparity is set, we need to then |
// create the parity bit. |
if (m_fixdp) |
p = m_evenp; |
else { |
p = (m_tx_data >> 1)&0x0ff; |
p = p ^ (p>>4); |
p = p ^ (p>>2); |
p = p ^ (p>>1); |
p &= 1; |
p ^= m_evenp; |
} |
m_tx_data |= (p<<(m_nbits+m_nparity)); |
} |
m_tx_busy = (1<<(m_nbits+m_nparity+m_nstop+1))-1; |
m_tx_state = TXDATA; |
o_rx = 0; |
m_tx_baudcounter = m_baud_counts-1; |
} else if (nr < 0) { |
fprintf(stderr, "ERR while attempting to read in--closing input port\n"); |
perror("UARTSIM::read() "); |
m_conrd = -1; |
} // and we really don't care if nr == 0 except that |
// the poll above is supposed to keep it from happening |
} |
} else if (m_tx_baudcounter == 0) { |
m_tx_data >>= 1; |
m_tx_busy >>= 1; |
if (!m_tx_busy) |
m_tx_state = TXIDLE; |
else |
m_tx_baudcounter = m_baud_counts-1; |
o_rx = m_tx_data&1; |
} else { |
m_tx_baudcounter--; |
o_rx = m_tx_data&1; |
} |
|
return 0; |
return o_rx; |
} |
|
|
/s6soc/trunk/bench/cpp/uartsim.h
1,33 → 1,132
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: uartsim.h |
// |
// Filename: uartsim.h |
// Project: wbuart32, a full featured UART with simulator |
// |
// Project: FPGA library development (S6 development board) |
// Purpose: To forward a Verilator simulated UART link over a TCP/IP pipe. |
// |
// Purpose: To emulate the external parameters of a UART device, providing |
// the UART output to, and input from, the command |
// console/terminal while also providing the controller with |
// appropriate busy lines as necessary. |
// This file provides the description of the interface between the UARTSIM |
// and the rest of the world. See below for more detailed descriptions. |
// |
// Creator: Dan Gisselquist |
// Gisselquist Tecnology, LLC |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
// Copyright: 2016 |
//////////////////////////////////////////////////////////////////////////////// |
// |
// 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 |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory. Run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#ifndef UARTSIM_H |
#define UARTSIM_H |
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <sys/types.h> |
#include <sys/socket.h> |
#include <poll.h> |
#include <unistd.h> |
#include <arpa/inet.h> |
#include <signal.h> |
|
class UARTSIM { |
private: |
int m_tx_busy_count, m_baud_counts, m_rx_busy_count; |
int m_fdin, m_fdout; |
char m_rx_next, m_tx_data; |
#define TXIDLE 0 |
#define TXDATA 1 |
#define RXIDLE 0 |
#define RXDATA 1 |
|
class UARTSIM { |
// The file descriptors: |
// m_skt is the socket/port we are listening on |
// m_conrd is the file descriptor to read from |
// m_conwr is the file descriptor to write to |
int m_skt, m_conrd, m_conwr; |
// |
// The m_setup register is the 29'bit control register used within |
// the core. |
unsigned m_setup; |
// And the pieces of the setup register broken out. |
int m_nparity, m_fixdp, m_evenp, m_nbits, m_nstop, m_baud_counts; |
|
// UART state |
int m_rx_baudcounter, m_rx_state, m_rx_busy, |
m_rx_changectr, m_last_tx; |
int m_tx_baudcounter, m_tx_state, m_tx_busy; |
unsigned m_rx_data, m_tx_data; |
|
// setup_listener is an attempt to encapsulate all of the network |
// related setup stuff. |
void setup_listener(const int port); |
|
// nettick() gets called if we are connected to a network, and |
int nettick(const int i_tx); |
// fdtick() if we are not. |
int fdtick(const int i_tx); |
|
// We'll use the file descriptor for the listener socket to determine |
// whether we are connected to the network or not. If not connected |
// to the network, then we assume m_conrd and m_conwr refer to |
// your more traditional file descriptors, and use them as such. |
int tick(const int i_tx) { |
if (m_skt >= 0) |
return nettick(i_tx); |
else |
return fdtick(i_tx); |
} |
|
public: |
UARTSIM(int baud_counts, int fdin = STDIN_FILENO, |
int fdout=STDOUT_FILENO); |
int rx(unsigned char &data); |
int tx(int stb, char data); |
// |
// The UARTSIM constructor takes one argument: the port on the |
// localhost to listen in on. Once started, connections may be made |
// to this port to get the output from the port. |
UARTSIM(const int port); |
|
// kill() closes any active connection and the socket. Once killed, |
// no further output will be sent to the port. |
void kill(void); |
|
// setup() busts out the bits from isetup to the various internal |
// parameters. It is ideally only called between bits at appropriate |
// transition intervals. |
void setup(unsigned isetup); |
|
// The operator() function is called on every tick. The input is the |
// the output txuart transmit wire from the device. The output is to |
// be connected to the the rxuart receive wire into the device. This |
// makes hookup and operation very simple. |
// |
// This is the most appropriate simulation entry function if the |
// setup register will never change. |
// |
int operator()(int i_tx) { |
return tick(i_tx); } |
|
// If there is a possibility that the core might change the UART setup, |
// then it makes sense to include that current setup when calling the |
// tick operator. |
int operator()(int i_tx, unsigned isetup) { |
setup(isetup); return tick(i_tx); } |
}; |
|
|
#endif |
/s6soc/trunk/bench/cpp/zip_sim.cpp
52,6 → 52,8
// #include "twoc.h" |
#include "qspiflashsim.h" |
#include "uartsim.h" |
#include "zipelf.h" |
#include "byteswap.h" |
|
typedef uint32_t BUSW; |
|
65,14 → 67,44
unsigned operator()(const unsigned o_kpd) { return 0; } |
}; |
|
// Add a reset line, since Vbusmaster doesn't have one |
class Vbusmasterr : public Vbusmaster { |
public: |
int i_rst; |
}; |
#define tx_busy v__DOT__tcvuart__DOT__r_busy |
#define rx_stb v__DOT__rx_stb |
#define uart_setup v__DOT__tcvuart__DOT__r_setup |
#define cpu_regset v__DOT__swic__DOT__thecpu__DOT__regset |
#define cpu_gie v__DOT__swic__DOT__thecpu__DOT__r_gie |
#define cpu_ipc v__DOT__swic__DOT__thecpu__DOT__ipc |
#define cpu_upc v__DOT__swic__DOT__thecpu__DOT__r_upc |
#define cpu_op_Av v__DOT__swic__DOT__thecpu__DOT__r_op_Av |
#define cpu_op_Bv v__DOT__swic__DOT__thecpu__DOT__r_op_Bv |
#define cpu_iflags v__DOT__swic__DOT__thecpu__DOT__w_iflags |
#define cpu_uflags v__DOT__swic__DOT__thecpu__DOT__w_uflags |
#define cpu_pf_valid v__DOT__swic__DOT__thecpu__DOT__pf_valid |
#define cpu_pf_pc v__DOT__swic__DOT__thecpu__DOT__pf_pc |
#define cpu_pf_instruction_pc v__DOT__swic__DOT__thecpu__DOT__pf_instruction_pc |
#define cpu_pf_instruction v__DOT__swic__DOT__thecpu__DOT__pf_instruction |
#define cpu_op_valid v__DOT__swic__DOT__thecpu__DOT__op_valid |
#define cpu_op_sim v__DOT__swic__DOT__thecpu__DOT__op_sim |
#define cpu_sim_immv v__DOT__swic__DOT__thecpu__DOT__op_sim_immv |
#define cpu_alu_ce v__DOT__swic__DOT__thecpu__DOT__alu_ce |
// |
#define pic_gie v__DOT__pic__DOT__r_gie |
#define pic_int_enable v__DOT__pic__DOT__r_int_enable |
#define pic_any v__DOT__pic__DOT__r_any |
#define pic_int_state v__DOT__pic__DOT__r_int_state |
#define wb_cyc v__DOT__wb_cyc |
#define wb_stb v__DOT__wb_stb |
#define wb_we v__DOT__wb_we |
#define wb_data v__DOT__swic__DOT__thecpu__DOT__mem_data |
#define wb_addr v__DOT__w_zip_addr |
// |
#define wb_ack v__DOT__wb_ack |
#define wb_stall v__DOT__wb_stall |
#define wb_idata v__DOT__wb_idata |
// |
#define watchdog_int v__DOT__watchdog_int |
|
// No particular "parameters" need definition or redefinition here. |
class ZIPSIM_TB : public TESTB<Vbusmasterr> { |
class ZIPSIM_TB : public TESTB<Vbusmaster> { |
public: |
QSPIFLASHSIM m_flash; |
UARTSIM m_uart; |
79,12 → 111,17
GPIOSIM m_gpio; |
KEYPADSIM m_keypad; |
unsigned m_last_led; |
unsigned m_last_gpio, m_last_pf_pc; |
time_t m_start_time; |
FILE *m_dbg; |
|
ZIPSIM_TB(void) : m_uart(0x2b6) { |
ZIPSIM_TB(int serial_port, bool debug) : m_uart(serial_port) { |
m_start_time = time(NULL); |
m_dbg = fopen("dbg.txt","w"); |
if (debug) |
m_dbg = fopen("dbg.txt","w"); |
else m_dbg = NULL; |
|
m_last_led = m_last_gpio = m_last_pf_pc = -1; |
} |
|
void reset(void) { |
91,11 → 128,135
m_flash.debug(false); |
} |
|
void close(void) { |
closetrace(); |
} |
|
void dump(const uint32_t *regp) { |
uint32_t uccv, iccv; |
fflush(stderr); |
fflush(stdout); |
printf("ZIPM--DUMP: "); |
if (m_core->cpu_gie) |
printf("Interrupts-enabled\n"); |
else |
printf("Supervisor mode\n"); |
printf("\n"); |
|
iccv = m_core->cpu_iflags; |
uccv = m_core->cpu_uflags; |
|
printf("sR0 : %08x ", regp[0]); |
printf("sR1 : %08x ", regp[1]); |
printf("sR2 : %08x ", regp[2]); |
printf("sR3 : %08x\n",regp[3]); |
printf("sR4 : %08x ", regp[4]); |
printf("sR5 : %08x ", regp[5]); |
printf("sR6 : %08x ", regp[6]); |
printf("sR7 : %08x\n",regp[7]); |
printf("sR8 : %08x ", regp[8]); |
printf("sR9 : %08x ", regp[9]); |
printf("sR10: %08x ", regp[10]); |
printf("sR11: %08x\n",regp[11]); |
printf("sR12: %08x ", regp[12]); |
printf("sSP : %08x ", regp[13]); |
printf("sCC : %08x ", iccv); |
printf("sPC : %08x\n",m_core->cpu_ipc); |
|
printf("\n"); |
|
printf("uR0 : %08x ", regp[16]); |
printf("uR1 : %08x ", regp[17]); |
printf("uR2 : %08x ", regp[18]); |
printf("uR3 : %08x\n",regp[19]); |
printf("uR4 : %08x ", regp[20]); |
printf("uR5 : %08x ", regp[21]); |
printf("uR6 : %08x ", regp[22]); |
printf("uR7 : %08x\n",regp[23]); |
printf("uR8 : %08x ", regp[24]); |
printf("uR9 : %08x ", regp[25]); |
printf("uR10: %08x ", regp[26]); |
printf("uR11: %08x\n",regp[27]); |
printf("uR12: %08x ", regp[28]); |
printf("uSP : %08x ", regp[29]); |
printf("uCC : %08x ", uccv); |
printf("uPC : %08x\n",m_core->cpu_upc); |
printf("\n"); |
fflush(stderr); |
fflush(stdout); |
} |
|
void execsim(const uint32_t imm) { |
uint32_t *regp = m_core->cpu_regset; |
int rbase; |
rbase = (m_core->cpu_gie)?16:0; |
|
fflush(stdout); |
if ((imm & 0x03fffff)==0) |
return; |
// fprintf(stderr, "SIM-INSN(0x%08x)\n", imm); |
if ((imm & 0x0fffff)==0x00100) { |
// SIM Exit(0) |
close(); |
exit(0); |
} else if ((imm & 0x0ffff0)==0x00310) { |
// SIM Exit(User-Reg) |
int rcode; |
rcode = regp[(imm&0x0f)+16] & 0x0ff; |
close(); |
exit(rcode); |
} else if ((imm & 0x0ffff0)==0x00300) { |
// SIM Exit(Reg) |
int rcode; |
rcode = regp[(imm&0x0f)+rbase] & 0x0ff; |
close(); |
exit(rcode); |
} else if ((imm & 0x0fff00)==0x00100) { |
// SIM Exit(Imm) |
int rcode; |
rcode = imm & 0x0ff; |
close(); |
exit(rcode); |
} else if ((imm & 0x0fffff)==0x002ff) { |
// Full/unconditional dump |
printf("SIM-DUMP\n"); |
dump(regp); |
} else if ((imm & 0x0ffff0)==0x00200) { |
// Dump a register |
int rid = (imm&0x0f)+rbase; |
printf("%8ld @%08x R[%2d] = 0x%08x\n", m_tickcount, |
m_core->cpu_ipc, rid, regp[rid]); |
} else if ((imm & 0x0ffff0)==0x00210) { |
// Dump a user register |
int rid = (imm&0x0f); |
printf("%8ld @%08x uR[%2d] = 0x%08x\n", m_tickcount, |
m_core->cpu_ipc, rid, regp[rid+16]); |
} else if ((imm & 0x0ffff0)==0x00230) { |
// SOUT[User Reg] |
int rid = (imm&0x0f)+16; |
printf("%c", regp[rid]&0x0ff); |
} else if ((imm & 0x0fffe0)==0x00220) { |
// SOUT[User Reg] |
int rid = (imm&0x0f)+rbase; |
printf("%c", regp[rid]&0x0ff); |
} else if ((imm & 0x0fff00)==0x00400) { |
// SOUT[Imm] |
printf("%c", imm&0x0ff); |
} else { // if ((insn & 0x0f7c00000)==0x77800000) |
uint32_t immv = imm & 0x03fffff; |
// Simm instruction that we dont recognize |
// if (imm) |
// printf("SIM 0x%08x\n", immv); |
printf("SIM 0x%08x (ipc = %08x, upc = %08x)\n", immv, |
m_core->cpu_ipc, m_core->cpu_upc); |
} fflush(stdout); |
} |
|
void tick(void) { |
if ((m_tickcount & ((1<<28)-1))==0) { |
double ticks_per_second = m_tickcount; |
time_t nsecs = (time(NULL)-m_start_time); |
if (nsecs > 0) { |
if ((nsecs > 0)&&(ticks_per_second>0)) { |
ticks_per_second /= (double)nsecs; |
printf(" ******** %.6f TICKS PER SECOND\n", |
ticks_per_second); |
119,348 → 280,82
m_core->i_kp_row = m_keypad(m_core->o_kp_col); |
|
// And the UART |
m_core->i_rx_stb = m_uart.rx(m_core->i_rx_data); |
m_core->i_tx_busy = m_uart.tx(m_core->o_tx_stb, m_core->o_tx_data); |
m_core->i_uart_cts_n = 0; |
m_uart.setup(m_core->uart_setup); |
m_core->i_uart = m_uart(m_core->o_uart); |
|
TESTB<Vbusmasterr>::tick(); |
TESTB<Vbusmaster>::tick(); |
|
if (m_core->o_led != m_last_led) { |
printf("LED: %08x\n", m_core->o_led); |
m_last_led = m_core->o_led; |
if ((m_core->o_led != m_last_led)||(m_core->o_gpio != m_last_gpio)||(m_core->cpu_pf_pc != m_last_pf_pc)) { |
printf("LED: %x\tGPIO: %04x\tPF-PC = %08x\r", m_core->o_led, |
m_core->o_gpio, m_core->cpu_pf_pc); |
fflush(stdout); |
m_last_led = m_core->o_led; |
m_last_gpio = m_core->o_gpio; |
} |
|
if (m_core->watchdog_int) { |
printf("\nWATCHDOG-INT!!! CPU-sPC = %08x, TICKS = %08lx\n", m_core->cpu_ipc, m_tickcount); |
} |
|
if (m_dbg) fprintf(m_dbg, "PC: %08x:%08x [%08x:%08x:%08x:%08x:%08x],%08x,%08x,%d,%08x,%08x (%x,%x/0x%08x)\n", |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__ipc, |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__upc, |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__regset[0], |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__regset[1], |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__regset[2], |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__regset[3], |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__regset[15], |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__instruction_decoder__DOT__r_I, |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__r_opB, |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__instruction_decoder__DOT__w_dcdR_pc, |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__r_opA, |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__wr_reg_vl, |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__w_iflags, |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__w_uflags, |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__pf_pc |
); |
if ((m_core->v__DOT__wb_cyc)&&(m_dbg)) |
if (m_dbg) fprintf(m_dbg, "%10ld - PC: %08x:%08x [%08x:%08x:%08x:%08x:%08x],%08x,%08x,%d,%08x,%08x (%x,%x/0x%08x)\n", |
m_tickcount, |
m_core->cpu_ipc, |
m_core->cpu_upc, |
m_core->cpu_regset[0], |
m_core->cpu_regset[1], |
m_core->cpu_regset[2], |
m_core->cpu_regset[3], |
m_core->cpu_regset[15], |
m_core->v__DOT__swic__DOT__thecpu__DOT__instruction_decoder__DOT__r_I, |
m_core->cpu_op_Bv, |
m_core->v__DOT__swic__DOT__thecpu__DOT__instruction_decoder__DOT__w_dcdR_pc, |
m_core->cpu_op_Av, |
m_core->v__DOT__swic__DOT__thecpu__DOT__wr_gpreg_vl, |
m_core->cpu_iflags, |
m_core->cpu_uflags, |
m_core->cpu_pf_pc); |
if ((!m_core->o_qspi_cs_n)&&(m_dbg)) |
fprintf(m_dbg, "QSPI: [CS,SCK,DAT (MOD)] = %d,%d,%02x,%d -> %04x %7s, state= %x/(%d)\n", |
m_core->o_qspi_cs_n, |
m_core->o_qspi_sck, |
m_core->o_qspi_dat, |
m_core->o_qspi_mod, |
m_core->i_qspi_dat, |
(m_core->v__DOT__flashmem__DOT__quad_mode_enabled)?"(quad)":"", |
m_core->v__DOT__flashmem__DOT__state, |
m_core->v__DOT__flashmem__DOT__lldriver__DOT__state); |
|
if ((m_core->wb_cyc)&&(m_dbg)) |
fprintf(m_dbg, "WB: %s/%s/%s[@0x%08x] %08x ->%s/%s %08x\n", |
(m_core->v__DOT__wb_cyc)?"CYC":" ", |
(m_core->v__DOT__wb_stb)?"STB":" ", |
(m_core->v__DOT__wb_we )?"WE ":" ", |
(m_core->v__DOT__w_zip_addr), |
(m_core->v__DOT__wb_data), |
(m_core->v__DOT__wb_ack)?"ACK":" ", |
(m_core->v__DOT__wb_stall)?"STL":" ", |
(m_core->v__DOT__wb_idata) |
(m_core->wb_cyc)?"CYC":" ", |
(m_core->wb_stb)?"STB":" ", |
(m_core->wb_we )?"WE ":" ", |
(m_core->wb_addr), |
(m_core->wb_data), |
(m_core->wb_ack)?"ACK":" ", |
(m_core->wb_stall)?"STL":" ", |
(m_core->wb_idata) |
); |
if (m_dbg) |
fprintf(m_dbg, "PIC: %3s(%4x) %3s(%4x)%s\n", |
(m_core->v__DOT__pic__DOT__r_gie)?"GIE":"", |
(m_core->v__DOT__pic__DOT__r_int_enable), |
(m_core->v__DOT__pic__DOT__r_any)?"ANY":"", |
(m_core->v__DOT__pic__DOT__r_int_state), |
(m_core->v__DOT__pic__DOT__r_interrupt)?" ---> INT!":""); |
|
if ((m_core->v__DOT__thecpu__DOT__thecpu__DOT__pf_valid)&&(m_dbg)) |
if ((m_core->cpu_pf_valid)&&(m_dbg)) |
fprintf(m_dbg, "PC: %08x - %08x, uart=%d,%d, pic = %d,%04x,%0d,%04x\n", |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__instruction_pc, |
m_core->v__DOT__thecpu__DOT__thecpu__DOT__instruction, |
m_core->i_rx_stb, m_core->i_tx_busy, |
m_core->v__DOT__pic__DOT__r_gie, |
m_core->v__DOT__pic__DOT__r_int_enable, |
m_core->v__DOT__pic__DOT__r_any, |
m_core->v__DOT__pic__DOT__r_int_state); |
} |
}; |
m_core->cpu_pf_instruction_pc, |
m_core->cpu_pf_instruction, |
m_core->rx_stb, m_core->tx_busy, |
m_core->pic_gie, |
m_core->pic_int_enable, |
m_core->pic_any, |
m_core->pic_int_state); |
|
ZIPSIM_TB *tb; |
|
bool iself(const char *fname) { |
FILE *fp; |
bool ret = true; |
|
if ((!fname)||(!fname[0])) |
return false; |
|
fp = fopen(fname, "rb"); |
|
if (!fp) return false; |
if (0x7f != fgetc(fp)) ret = false; |
if ('E' != fgetc(fp)) ret = false; |
if ('L' != fgetc(fp)) ret = false; |
if ('F' != fgetc(fp)) ret = false; |
fclose(fp); |
return ret; |
} |
|
long fgetwords(FILE *fp) { |
// Return the number of words in the current file, and return the |
// file as though it had never been adjusted |
long fpos, flen; |
fpos = ftell(fp); |
if (0 != fseek(fp, 0l, SEEK_END)) { |
fprintf(stderr, "ERR: Could not determine file size\n"); |
perror("O/S Err:"); |
exit(-2); |
} flen = ftell(fp); |
if (0 != fseek(fp, fpos, SEEK_SET)) { |
fprintf(stderr, "ERR: Could not seek on file\n"); |
perror("O/S Err:"); |
exit(-2); |
} flen /= sizeof(BUSW); |
return flen; |
} |
|
class SECTION { |
public: |
unsigned m_start, m_len; |
BUSW m_data[1]; |
// SIM instruction(s) |
if ((m_core->cpu_op_sim)&&(m_core->cpu_op_valid) |
&&(m_core->cpu_alu_ce)) |
execsim(m_core->cpu_sim_immv); |
} |
}; |
|
SECTION **singlesection(int nwords) { |
fprintf(stderr, "NWORDS = %d\n", nwords); |
size_t sz = (2*(sizeof(SECTION)+sizeof(SECTION *)) |
+(nwords-1)*(sizeof(BUSW))); |
char *d = (char *)malloc(sz); |
SECTION **r = (SECTION **)d; |
memset(r, 0, sz); |
r[0] = (SECTION *)(&d[2*sizeof(SECTION *)]); |
r[0]->m_len = nwords; |
r[1] = (SECTION *)(&r[0]->m_data[r[0]->m_len]); |
r[0]->m_start = 0; |
r[1]->m_start = 0; |
r[1]->m_len = 0; |
|
return r; |
} |
|
SECTION **rawsection(const char *fname) { |
SECTION **secpp, *secp; |
unsigned num_words; |
FILE *fp; |
int nr; |
|
fp = fopen(fname, "r"); |
if (fp == NULL) { |
fprintf(stderr, "Could not open: %s\n", fname); |
exit(-1); |
} |
|
if ((num_words=fgetwords(fp)) > FLASHWORDS) { |
fprintf(stderr, "File overruns flash memory\n"); |
exit(-1); |
} |
secpp = singlesection(num_words); |
secp = secpp[0]; |
secp->m_start = RESET_ADDRESS; |
secp->m_len = num_words; |
nr= fread(secp->m_data, sizeof(BUSW), num_words, fp); |
if (nr != (int)num_words) { |
fprintf(stderr, "Could not read entire file\n"); |
perror("O/S Err:"); |
exit(-2); |
} assert(secpp[1]->m_len == 0); |
|
return secpp; |
} |
|
unsigned byteswap(unsigned n) { |
unsigned r; |
|
r = (n&0x0ff); n>>= 8; |
r = (r<<8) | (n&0x0ff); n>>= 8; |
r = (r<<8) | (n&0x0ff); n>>= 8; |
r = (r<<8) | (n&0x0ff); n>>= 8; |
|
return r; |
} |
|
#include <libelf.h> |
#include <gelf.h> |
|
void elfread(const char *fname, unsigned &entry, SECTION **§ions) { |
Elf *e; |
int fd, i; |
size_t n; |
char *id; |
Elf_Kind ek; |
GElf_Ehdr ehdr; |
GElf_Phdr phdr; |
const bool dbg = false; |
|
if (elf_version(EV_CURRENT) == EV_NONE) { |
fprintf(stderr, "ELF library initialization err, %s\n", elf_errmsg(-1)); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if ((fd = open(fname, O_RDONLY, 0)) < 0) { |
fprintf(stderr, "Could not open %s\n", fname); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if ((e = elf_begin(fd, ELF_C_READ, NULL))==NULL) { |
fprintf(stderr, "Could not run elf_begin, %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
ek = elf_kind(e); |
if (ek == ELF_K_ELF) { |
; // This is the kind of file we should expect |
} else if (ek == ELF_K_AR) { |
fprintf(stderr, "Cannot run an archive!\n"); |
exit(EXIT_FAILURE); |
} else if (ek == ELF_K_NONE) { |
; |
} else { |
fprintf(stderr, "Unexpected ELF file kind!\n"); |
exit(EXIT_FAILURE); |
} |
|
if (gelf_getehdr(e, &ehdr) == NULL) { |
fprintf(stderr, "getehdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if ((i=gelf_getclass(e)) == ELFCLASSNONE) { |
fprintf(stderr, "getclass() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if ((id = elf_getident(e, NULL)) == NULL) { |
fprintf(stderr, "getident() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if (i != ELFCLASS32) { |
fprintf(stderr, "This is a 64-bit ELF file, ZipCPU ELF files are all 32-bit\n"); |
exit(EXIT_FAILURE); |
} |
|
if (dbg) { |
printf(" %-20s 0x%jx\n", "e_type", (uintmax_t)ehdr.e_type); |
printf(" %-20s 0x%jx\n", "e_machine", (uintmax_t)ehdr.e_machine); |
printf(" %-20s 0x%jx\n", "e_version", (uintmax_t)ehdr.e_version); |
printf(" %-20s 0x%jx\n", "e_entry", (uintmax_t)ehdr.e_entry); |
printf(" %-20s 0x%jx\n", "e_phoff", (uintmax_t)ehdr.e_phoff); |
printf(" %-20s 0x%jx\n", "e_shoff", (uintmax_t)ehdr.e_shoff); |
printf(" %-20s 0x%jx\n", "e_flags", (uintmax_t)ehdr.e_flags); |
printf(" %-20s 0x%jx\n", "e_ehsize", (uintmax_t)ehdr.e_ehsize); |
printf(" %-20s 0x%jx\n", "e_phentsize", (uintmax_t)ehdr.e_phentsize); |
printf(" %-20s 0x%jx\n", "e_shentsize", (uintmax_t)ehdr.e_shentsize); |
printf("\n"); |
} |
|
|
// Check whether or not this is an ELF file for the ZipCPU ... |
if (ehdr.e_machine != 0x0dadd) { |
fprintf(stderr, "This is not a ZipCPU ELF file\n"); |
exit(EXIT_FAILURE); |
} |
|
// Get our entry address |
entry = ehdr.e_entry; |
|
|
// Now, let's go look at the program header |
if (elf_getphdrnum(e, &n) != 0) { |
fprintf(stderr, "elf_getphdrnum() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
unsigned total_octets = 0, current_offset=0, current_section=0; |
for(i=0; i<(int)n; i++) { |
total_octets += sizeof(SECTION *)+sizeof(SECTION); |
|
if (gelf_getphdr(e, i, &phdr) != &phdr) { |
fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
if (dbg) { |
printf(" %-20s 0x%x\n", "p_type", phdr.p_type); |
printf(" %-20s 0x%jx\n", "p_offset", phdr.p_offset); |
printf(" %-20s 0x%jx\n", "p_vaddr", phdr.p_vaddr); |
printf(" %-20s 0x%jx\n", "p_paddr", phdr.p_paddr); |
printf(" %-20s 0x%jx\n", "p_filesz", phdr.p_filesz); |
printf(" %-20s 0x%jx\n", "p_memsz", phdr.p_memsz); |
printf(" %-20s 0x%x [", "p_flags", phdr.p_flags); |
|
if (phdr.p_flags & PF_X) printf(" Execute"); |
if (phdr.p_flags & PF_R) printf(" Read"); |
if (phdr.p_flags & PF_W) printf(" Write"); |
printf("]\n"); |
printf(" %-20s 0x%jx\n", "p_align", phdr.p_align); |
} |
|
total_octets += phdr.p_memsz; |
} |
|
char *d = (char *)malloc(total_octets + sizeof(SECTION)+sizeof(SECTION *)); |
memset(d, 0, total_octets); |
|
SECTION **r = sections = (SECTION **)d; |
current_offset = (n+1)*sizeof(SECTION *); |
current_section = 0; |
|
for(i=0; i<(int)n; i++) { |
r[i] = (SECTION *)(&d[current_offset]); |
|
if (gelf_getphdr(e, i, &phdr) != &phdr) { |
fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
if (dbg) { |
printf(" %-20s 0x%jx\n", "p_offset", phdr.p_offset); |
printf(" %-20s 0x%jx\n", "p_vaddr", phdr.p_vaddr); |
printf(" %-20s 0x%jx\n", "p_paddr", phdr.p_paddr); |
printf(" %-20s 0x%jx\n", "p_filesz", phdr.p_filesz); |
printf(" %-20s 0x%jx\n", "p_memsz", phdr.p_memsz); |
printf(" %-20s 0x%x [", "p_flags", phdr.p_flags); |
|
if (phdr.p_flags & PF_X) printf(" Execute"); |
if (phdr.p_flags & PF_R) printf(" Read"); |
if (phdr.p_flags & PF_W) printf(" Write"); |
printf("]\n"); |
|
printf(" %-20s 0x%jx\n", "p_align", phdr.p_align); |
} |
|
current_section++; |
|
r[i]->m_start = phdr.p_vaddr; |
r[i]->m_len = phdr.p_filesz/ sizeof(BUSW); |
|
current_offset += phdr.p_memsz + sizeof(SECTION); |
|
// Now, let's read in our section ... |
if (lseek(fd, phdr.p_offset, SEEK_SET) < 0) { |
fprintf(stderr, "Could not seek to file position %08lx\n", phdr.p_offset); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if (phdr.p_filesz > phdr.p_memsz) |
phdr.p_filesz = 0; |
if (read(fd, r[i]->m_data, phdr.p_filesz) != (int)phdr.p_filesz) { |
fprintf(stderr, "Didnt read entire section\n"); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} |
|
// Next, we need to byte swap it from big to little endian |
for(unsigned j=0; j<r[i]->m_len; j++) |
r[i]->m_data[j] = byteswap(r[i]->m_data[j]); |
|
if (dbg) for(unsigned j=0; j<r[i]->m_len; j++) |
fprintf(stderr, "ADR[%04x] = %08x\n", r[i]->m_start+j, |
r[i]->m_data[j]); |
} |
|
r[i] = (SECTION *)(&d[current_offset]); |
r[current_section]->m_start = 0; |
r[current_section]->m_len = 0; |
|
elf_end(e); |
close(fd); |
} |
|
|
void usage(void) { |
fprintf(stderr, "Usage: zip_sim flash_program\n"); |
} |
467,36 → 362,70
|
int main(int argc, char **argv) { |
Verilated::commandArgs(argc, argv); |
tb = new ZIPSIM_TB; |
const char *codef = NULL; |
ZIPSIM_TB *tb; |
const char *codef = NULL, *trace_file = NULL; |
bool debug_flag = false; |
int serial_port = -1; |
|
for(int argn=1; argn<argc; argn++) { |
if (argv[argn][0] == '-') { |
usage(); |
exit(-1); |
} else |
if (argv[argn][0] == '-') for (int j=1; |
(j<512)&&(argv[argn][j]); j++) { |
switch(tolower(argv[argn][j])) { |
case 'c': break; // no comms to copy to stdout break; |
case 'd': debug_flag = true; |
if (trace_file == NULL) |
trace_file = "trace.vcd"; |
break; |
case 'p': break; // S6 has no fpga command port |
case 's': serial_port=atoi(argv[++argn]); j=1000; break; |
case 't': trace_file = (argn+1<argc)?argv[++argn]:NULL;j=1000; break; |
case 'h': usage(); exit(EXIT_SUCCESS); break; |
default: |
fprintf(stderr, "ERR: Unexpected flag, -%c\n\n", |
argv[argn][j]); |
usage(); exit(EXIT_FAILURE); |
} |
} else if (iself(argv[argn])) { |
codef = argv[argn]; |
} else { |
fprintf(stderr, "ERR: Unknown/unexpected argument: %s\n", |
argv[argn]); |
exit(EXIT_FAILURE); |
} |
} |
|
if ((!codef)||(!codef[0])) |
fprintf(stderr, "No executable code filename found!\n"); |
|
if (serial_port < 0) { |
printf("Using the terminal as a SERIAL port\n"); |
serial_port = 0; |
} |
tb = new ZIPSIM_TB(serial_port, debug_flag); |
|
if (access(codef, R_OK)!=0) |
fprintf(stderr, "Cannot read code filename, %s\n", codef); |
|
if (iself(codef)) { |
SECTION **secpp, *secp; |
BUSW entry; |
ELFSECTION **secpp, *secp; |
BUSW entry; |
elfread(codef, entry, secpp); |
|
assert(entry == RESET_ADDRESS); |
|
for(int i=0; secpp[i]->m_len; i++) { |
secp = secpp[i]; |
tb->m_flash.write(secp->m_start, secp->m_len, secp->m_data); |
tb->m_flash.write(secp->m_start, secp->m_len, (char *)&secp->m_data); |
} |
} else { |
tb->m_flash.load(RESET_ADDRESS, codef); |
fprintf(stderr, "%s is not a ZipCPU ELF executable\n", codef); |
exit(EXIT_FAILURE); |
} |
|
// if (debug_flag) { } |
if (trace_file) |
tb->opentrace(trace_file); |
|
tb->reset(); |
|
while(1) |
/s6soc/trunk/bench/cpp/zipelf.cpp
0,0 → 1,251
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: zipelf.cpp |
// |
// Project: OpenArty, an entirely open SoC based upon the Arty platform |
// |
// Purpose: |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// 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 |
// 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 <stdlib.h> |
#include <stdio.h> |
#include <stdint.h> |
#include <unistd.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <fcntl.h> |
#include <libelf.h> |
#include <assert.h> |
#include <gelf.h> |
#include <string.h> |
|
#include "zipelf.h" |
|
bool |
iself(const char *fname) |
{ |
FILE *fp; |
bool ret = true; |
fp = fopen(fname, "rb"); |
|
if (!fp) return false; |
if (0x7f != fgetc(fp)) ret = false; |
if ('E' != fgetc(fp)) ret = false; |
if ('L' != fgetc(fp)) ret = false; |
if ('F' != fgetc(fp)) ret = false; |
fclose(fp); |
return ret; |
} |
|
void elfread(const char *fname, unsigned &entry, ELFSECTION **§ions) |
{ |
Elf *e; |
int fd, i; |
size_t n; |
char *id; |
Elf_Kind ek; |
GElf_Ehdr ehdr; |
GElf_Phdr phdr; |
const bool dbg = false; |
|
if (elf_version(EV_CURRENT) == EV_NONE) { |
fprintf(stderr, "ELF library initialization err, %s\n", elf_errmsg(-1)); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if ((fd = open(fname, O_RDONLY, 0)) < 0) { |
fprintf(stderr, "Could not open %s\n", fname); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if ((e = elf_begin(fd, ELF_C_READ, NULL))==NULL) { |
fprintf(stderr, "Could not run elf_begin, %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
ek = elf_kind(e); |
if (ek == ELF_K_ELF) { |
; // This is the kind of file we should expect |
} else if (ek == ELF_K_AR) { |
fprintf(stderr, "Cannot run an archive!\n"); |
exit(EXIT_FAILURE); |
} else if (ek == ELF_K_NONE) { |
; |
} else { |
fprintf(stderr, "Unexpected ELF file kind!\n"); |
exit(EXIT_FAILURE); |
} |
|
if (gelf_getehdr(e, &ehdr) == NULL) { |
fprintf(stderr, "getehdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if ((i=gelf_getclass(e)) == ELFCLASSNONE) { |
fprintf(stderr, "getclass() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if ((id = elf_getident(e, NULL)) == NULL) { |
fprintf(stderr, "getident() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if (i != ELFCLASS32) { |
fprintf(stderr, "This is a 64-bit ELF file, ZipCPU ELF files are all 32-bit\n"); |
exit(EXIT_FAILURE); |
} |
|
if (dbg) { |
printf(" %-20s 0x%jx\n", "e_type", (uintmax_t)ehdr.e_type); |
printf(" %-20s 0x%jx\n", "e_machine", (uintmax_t)ehdr.e_machine); |
printf(" %-20s 0x%jx\n", "e_version", (uintmax_t)ehdr.e_version); |
printf(" %-20s 0x%jx\n", "e_entry", (uintmax_t)ehdr.e_entry); |
printf(" %-20s 0x%jx\n", "e_phoff", (uintmax_t)ehdr.e_phoff); |
printf(" %-20s 0x%jx\n", "e_shoff", (uintmax_t)ehdr.e_shoff); |
printf(" %-20s 0x%jx\n", "e_flags", (uintmax_t)ehdr.e_flags); |
printf(" %-20s 0x%jx\n", "e_ehsize", (uintmax_t)ehdr.e_ehsize); |
printf(" %-20s 0x%jx\n", "e_phentsize", (uintmax_t)ehdr.e_phentsize); |
printf(" %-20s 0x%jx\n", "e_shentsize", (uintmax_t)ehdr.e_shentsize); |
printf("\n"); |
} |
|
|
// Check whether or not this is an ELF file for the ZipCPU ... |
if (ehdr.e_machine != 0x0dad1) { |
fprintf(stderr, "This is not a ZipCPU/8 ELF file\n"); |
exit(EXIT_FAILURE); |
} |
|
// Get our entry address |
entry = ehdr.e_entry; |
|
|
// Now, let's go look at the program header |
if (elf_getphdrnum(e, &n) != 0) { |
fprintf(stderr, "elf_getphdrnum() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
assert(n != 0); |
|
unsigned total_octets = 0, current_offset=0, current_section=0; |
for(i=0; i<(int)n; i++) { |
total_octets += sizeof(ELFSECTION *)+sizeof(ELFSECTION); |
|
if (gelf_getphdr(e, i, &phdr) != &phdr) { |
fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
if (dbg) { |
printf(" %-20s 0x%x\n", "p_type", phdr.p_type); |
printf(" %-20s 0x%jx\n", "p_offset", phdr.p_offset); |
printf(" %-20s 0x%jx\n", "p_vaddr", phdr.p_vaddr); |
printf(" %-20s 0x%jx\n", "p_paddr", phdr.p_paddr); |
printf(" %-20s 0x%jx\n", "p_filesz", phdr.p_filesz); |
printf(" %-20s 0x%jx\n", "p_memsz", phdr.p_memsz); |
printf(" %-20s 0x%x [", "p_flags", phdr.p_flags); |
|
if (phdr.p_flags & PF_X) printf(" Execute"); |
if (phdr.p_flags & PF_R) printf(" Read"); |
if (phdr.p_flags & PF_W) printf(" Write"); |
printf("]\n"); |
printf(" %-20s 0x%jx\n", "p_align", phdr.p_align); |
} |
|
total_octets += phdr.p_memsz; |
} |
|
char *d = (char *)malloc(total_octets + sizeof(ELFSECTION)+sizeof(ELFSECTION *)); |
memset(d, 0, total_octets); |
|
ELFSECTION **r = sections = (ELFSECTION **)d; |
current_offset = (n+1)*sizeof(ELFSECTION *); |
current_section = 0; |
|
for(i=0; i<(int)n; i++) { |
r[i] = (ELFSECTION *)(&d[current_offset]); |
|
if (gelf_getphdr(e, i, &phdr) != &phdr) { |
fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
if (dbg) { |
printf(" %-20s 0x%jx\n", "p_offset", phdr.p_offset); |
printf(" %-20s 0x%jx\n", "p_vaddr", phdr.p_vaddr); |
printf(" %-20s 0x%jx\n", "p_paddr", phdr.p_paddr); |
printf(" %-20s 0x%jx\n", "p_filesz", phdr.p_filesz); |
printf(" %-20s 0x%jx\n", "p_memsz", phdr.p_memsz); |
printf(" %-20s 0x%x [", "p_flags", phdr.p_flags); |
|
if (phdr.p_flags & PF_X) printf(" Execute"); |
if (phdr.p_flags & PF_R) printf(" Read"); |
if (phdr.p_flags & PF_W) printf(" Write"); |
printf("]\n"); |
|
printf(" %-20s 0x%jx\n", "p_align", phdr.p_align); |
} |
|
current_section++; |
|
r[i]->m_start = phdr.p_paddr; |
r[i]->m_len = phdr.p_filesz; |
|
current_offset += phdr.p_memsz + sizeof(ELFSECTION); |
|
// Now, let's read in our section ... |
if (lseek(fd, phdr.p_offset, SEEK_SET) < 0) { |
fprintf(stderr, "Could not seek to file position %08lx\n", phdr.p_offset); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if (phdr.p_filesz > phdr.p_memsz) |
phdr.p_filesz = 0; |
if (read(fd, r[i]->m_data, phdr.p_filesz) != (int)phdr.p_filesz) { |
fprintf(stderr, "Didnt read entire section\n"); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} |
|
/* |
// Next, we need to byte swap it from big to little endian |
for(unsigned j=0; j<r[i]->m_len; j++) |
r[i]->m_data[j] = byteswap(r[i]->m_data[j]); |
*/ |
|
if (dbg) for(unsigned j=0; j<r[i]->m_len; j++) |
fprintf(stderr, "ADR[%04x] = %02x\n", r[i]->m_start+j, |
r[i]->m_data[j] & 0x0ff); |
} |
|
r[i] = (ELFSECTION *)(&d[current_offset]); |
r[current_section]->m_start = 0; |
r[current_section]->m_len = 0; |
|
elf_end(e); |
close(fd); |
} |
|
/s6soc/trunk/bench/cpp/zipelf.h
0,0 → 1,53
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: zipelf.h |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// 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 |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory. Run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#ifndef ZIPELF_H |
#define ZIPELF_H |
|
#include <stdint.h> |
|
class ELFSECTION { |
public: |
uint32_t m_start, m_len; |
char m_data[4]; |
}; |
|
bool iself(const char *fname); |
void elfread(const char *fname, uint32_t &entry, ELFSECTION **§ions); |
|
#endif |
s6soc/trunk/bench/cpp
Property changes :
Added: svn:ignore
## -0,0 +1 ##
+zip_sim