URL
https://opencores.org/ocsvn/openarty/openarty/trunk
Subversion Repositories openarty
Compare Revisions
- This comparison shows the changes necessary to convert path
/openarty/trunk/bench
- from Rev 33 to Rev 34
- ↔ Reverse comparison
Rev 33 → Rev 34
/cpp/Makefile
37,18 → 37,23
## |
|
CXX := g++ |
FLAGS := -Wall -Og -g |
OBJDIR := obj-pc |
RTLD := ../../rtl |
VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT | head -1 | sed -e " s/^.*=\s*//"') |
VROOT := $(VERILATOR_ROOT) |
GFXFLAGS:= `pkg-config gtkmm-3.0 --cflags` |
GFXLIBS := `pkg-config gtkmm-3.0 --cflags --libs` |
FLAGS := -Wall -Og -g |
INCS := -I$(RTLD)/obj_dir/ -I$(RTLD) -I$(VROOT)/include |
SOURCES := eqspiflashsim.cpp eqspiflash_tb.cpp enetctrlsim.cpp \ |
SOURCES := fastmaster_tb.cpp eqspiflashsim.cpp eqspiflash_tb.cpp \ |
oledsim.cpp enetctrlsim.cpp \ |
memsim.cpp sdspisim.cpp uartsim.cpp ddrsdramsim.cpp |
HEADERS := ddrsdramsim.h enetctrlsim.h eqspiflashsim.h memsim.h \ |
oledsim.h pipecmdr.h port.h sdspisim.h testb.h uartsim.h |
VOBJDR := $(RTLD)/obj_dir |
VLIB := $(VROOT)/include/verilated.cpp |
SIMSRCS := enetctrlsim.cpp eqspiflashsim.cpp \ |
memsim.cpp sdspisim.cpp uartsim.cpp |
memsim.cpp sdspisim.cpp uartsim.cpp oledsim.cpp |
SIMOBJ := $(subst .cpp,.o,$(SIMSRCS)) |
SIMOBJS:= $(addprefix $(OBJDIR)/,$(SIMOBJ)) |
all: $(OBJDIR)/ busmaster_tb eqspiflash_tb enetctrl_tb |
57,8 → 62,26
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi" |
|
$(OBJDIR)/%.o: %.cpp |
$(CXX) $(FLAGS) -c $^ -o $@ |
$(CXX) $(FLAGS) -c $< -o $@ |
|
.PHONY: oledsim.o |
oledsim.o: $(OBJDIR)/oledsim.o |
$(OBJDIR)/oledsim.o: oledsim.cpp |
$(CXX) $(FLAGS) $(GFXFLAGS) -c $< -o $@ |
|
# While busmaster_tb.o isnt really dependent upon fastmaster_tb.o, this |
# makes certain that all of the dependencies of fastmaster_tb are captured |
# in busmaster. Hence, if fastmaster_tb is remade/rebuilt because one of |
# its dependencies change, so too is busmaster_tb. |
# |
$(OBJDIR)/busmaster_tb.o: fastmaster_tb.cpp |
$(CXX) $(FLAGS) $(GFXFLAGS) $(INCS) -c $< -o $@ |
|
$(OBJDIR)/fastmaster_tb.o: fastmaster_tb.cpp |
$(CXX) -DFASTCLK $(FLAGS) $(GFXFLAGS) $(INCS) -c $< -o $@ |
|
|
|
eqspiflash_tb: eqspiflash_tb.cpp $(OBJDIR)/eqspiflashsim.o $(VOBJDR)/Veqspiflash__ALL.a |
$(CXX) $(FLAGS) $(INCS) $^ $(VOBJDR)/Veqspiflash__ALL.a $(VLIB) -o $@ |
|
65,15 → 88,37
enetctrl_tb: enetctrl_tb.cpp $(OBJDIR)/enetctrlsim.o $(VOBJDR)/Venetctrl__ALL.a |
$(CXX) $(FLAGS) $(INCS) $^ $(VOBJDR)/Venetctrl__ALL.a $(VLIB) -o $@ |
|
fastmaster_tb:fastmaster_tb.cpp $(SIMOBJS) $(VOBJDR)/Vfastmaster__ALL.a |
$(CXX) -DFASTCLK $(FLAGS) $(INCS) $^ $(VOBJDR)/Vfastmaster__ALL.a $(VLIB) -o $@ |
busmaster_tb:fastmaster_tb.cpp $(SIMOBJS) $(VOBJDR)/Vbusmaster__ALL.a |
$(CXX) $(FLAGS) $(INCS) $^ $(VOBJDR)/Vbusmaster__ALL.a $(VLIB) -o $@ |
fastmaster_tb: $(OBJDIR)/fastmaster_tb.o $(SIMOBJS) $(VOBJDR)/Vfastmaster__ALL.a |
$(CXX) $(GFXLIBS) $^ $(VOBJDR)/Vfastmaster__ALL.a $(VLIB) -o $@ |
busmaster_tb: $(OBJDIR)/busmaster_tb.o $(SIMOBJS) $(VOBJDR)/Vbusmaster__ALL.a |
$(CXX) $(GFXLIBS) $(INCS) $^ $(VOBJDR)/Vbusmaster__ALL.a $(VLIB) $(GFXLIBS) -o $@ |
|
define build-depends |
@echo "Building dependency file(s)" |
@$(CXX) $(GFXFLAGS) $(INCS) -MM $(SOURCES) > $(OBJDIR)/xdepends.txt |
@sed -e 's/^.*.o: /$(OBJDIR)\/&/' < $(OBJDIR)/xdepends.txt \ |
| sed -e 's/fastmaster_tb.o/busmaster_tb.o/g' \ |
> $(OBJDIR)/depends.txt |
@rm $(OBJDIR)/xdepends.txt |
endef |
|
tags: $(SOURCES) $(HEADERS) |
@echo "Generating tags" |
@ctags $(SOURCES) $(HEADERS) |
|
.PHONY: clean |
clean: |
rm -rf $(OBJDIR)/ |
rm -f ./eqspiflash_tb |
rm -f ./enetctrl_tb |
rm -f ./fastmaster_tb |
rm -f ./busmaster_tb |
|
.PHONY: depends |
depends: |
$(build-depends) |
|
$(OBJDIR)/depends.txt: $(OBJDIR)/ $(SOURCES) $(HEADERS) |
$(build-depends) |
|
-include $(OBJDIR)/depends.txt |
/cpp/fastmaster_tb.cpp
63,6 → 63,9
#include "uartsim.h" |
#include "enetctrlsim.h" |
#include "memsim.h" |
// #ifdef OLEDSIM |
#include "oledsim.h" |
// #endif |
|
#include "port.h" |
|
77,11 → 80,16
ENETCTRLSIM *m_mid; |
UARTSIM m_uart; |
MEMSIM m_ram; |
#ifdef OLEDSIM_H |
OLEDWIN m_oled; |
#endif |
|
unsigned m_last_led, m_last_pic, m_last_tx_state, m_net_ticks; |
time_t m_start_time; |
bool m_last_writeout, m_cpu_started; |
int m_last_bus_owner, m_busy; |
unsigned long m_gps_err, m_gps_step, m_gps_newstep; |
unsigned m_gps_stepc; |
|
TESTBENCH(void) : PIPECMDR(FPGAPORT), |
m_uart(FPGAPORT+1), m_ram(1<<26) |
89,6 → 97,9
m_start_time = time(NULL); |
m_mid = new ENETCTRLSIM; |
m_cpu_started =false; |
#ifdef OLEDSIM_H |
Glib::signal_idle().connect(sigc::mem_fun((*this),&TESTBENCH::on_tick)); |
#endif |
} |
|
void setsdcard(const char *fn) { |
97,6 → 108,11
printf("LOADING SDCARD FROM: \'%s\'\n", fn); |
} |
|
bool on_tick(void) { |
tick(); |
return true; // Keep going 'til the kingdom comes |
} |
|
void tick(void) { |
if ((m_tickcount & ((1<<28)-1))==0) { |
double ticks_per_second = m_tickcount; |
109,6 → 125,12
} |
|
// Set up the bus before any clock tick |
#ifdef OLEDSIM_H |
m_oled(m_core->o_oled_pmoden, m_core->o_oled_reset_n, |
m_core->o_oled_vccen, m_core->o_oled_cs_n, |
m_core->o_oled_sck, m_core->o_oled_dcn, |
m_core->o_oled_mosi); |
#endif |
m_core->i_qspi_dat = m_flash(m_core->o_qspi_cs_n, |
m_core->o_qspi_sck, m_core->o_qspi_dat); |
|
159,6 → 181,8
#ifdef DEBUGGING_OUTPUT |
bool writeout = false; |
|
/* |
// Ethernet triggers |
if (m_core->o_net_tx_en) |
writeout = true; |
if (m_core->v__DOT__netctrl__DOT__n_rx_busy) |
167,12 → 191,66
writeout = true; |
if (m_core->v__DOT__netctrl__DOT__w_rxwr) |
writeout = true; |
*/ |
|
/* |
// GPS Clock triggers |
if (m_core->v__DOT__ppsck__DOT__tick) |
writeout = true; |
if (m_core->v__DOT__gps_step != m_gps_step) { |
writeout = true; |
// printf("STEP"); |
} if (m_core->v__DOT__gps_err != m_gps_err) { |
writeout = true; |
// printf("ERR"); |
} if (m_core->v__DOT__ppsck__DOT__step_correction != m_gps_stepc) { |
writeout = true; |
// printf("DSTP"); |
} if (m_core->v__DOT__ppsck__DOT__getnewstep__DOT__genblk2__DOT__genblk1__DOT__r_out != m_gps_newstep) |
writeout = true; |
*/ |
m_gps_step = m_core->v__DOT__gps_step; |
m_gps_err = m_core->v__DOT__gps_err; |
m_gps_stepc= m_core->v__DOT__ppsck__DOT__step_correction; |
m_gps_newstep=m_core->v__DOT__ppsck__DOT__getnewstep__DOT__genblk2__DOT__genblk1__DOT__r_out; |
|
if (m_core->o_oled_cs_n == 0) |
writeout = true; |
if (m_core->o_oled_sck == 0) |
writeout = true; |
if (m_core->v__DOT__rgbctrl__DOT__dev_wr) |
writeout = true; |
if (m_core->v__DOT__rgbctrl__DOT__r_busy) |
writeout = true; |
if (m_core->v__DOT__rgbctrl__DOT__dev_busy) |
writeout = true; |
|
|
/* |
if (m_core->v__DOT__ppsck__DOT__err_tick) |
writeout = true; |
if (m_core->v__DOT__ppsck__DOT__sub_tick) |
writeout = true; |
if (m_core->v__DOT__ppsck__DOT__shift_tick) |
writeout = true; |
if (m_core->v__DOT__ppsck__DOT__fltr_tick) |
writeout = true; |
if (m_core->v__DOT__ppsck__DOT__config_tick) |
writeout = true; |
if (m_core->v__DOT__ppsck__DOT__mpy_sync) |
writeout = true; |
if (m_core->v__DOT__ppsck__DOT__mpy_sync_two) |
writeout = true; |
if (m_core->v__DOT__ppsck__DOT__delay_step_clk) |
writeout = true; |
*/ |
|
// if (m_core->v__DOT__wbu_cyc) |
// writeout = true; |
// if (m_core->v__DOT__dwb_cyc) |
// writeout = true; |
|
// Write out if the CPU is active at all |
if (m_core->v__DOT__zippy__DOT__genblk11__DOT__thecpu__DOT__master_ce) |
writeout = true; |
if (m_core->v__DOT__zippy__DOT__genblk11__DOT__thecpu__DOT__dbgv) |
396,6 → 474,8
} |
*/ |
|
/* |
// Network debugging |
printf("ETH[TX:%s%s%x%s]", |
(m_core->i_net_tx_clk)?"CK":" ", |
(m_core->o_net_tx_en)?" ":"(", |
463,6 → 543,8
(m_core->v__DOT__netctrl__DOT__rxmaci__DOT__r_p)&0x0ff, |
m_core->v__DOT__netctrl__DOT__w_rxmacd, |
(m_core->v__DOT__netctrl__DOT__w_rxmac)?"!":" "); |
*/ |
|
/* |
// Flash debugging support |
printf("%s/%s %s %s[%s%s%s%s%s] %s@%08x[%08x/%08x] -- SPI %s%s[%x/%x](%d,%d)", |
532,6 → 614,68
*/ |
|
|
/* |
// Debugging the GPS tracking circuit |
printf("COUNT %016lx STEP %016lx+%08x->%016lx ERR %016lx %s", |
m_core->v__DOT__gps_now, |
m_core->v__DOT__gps_step, |
m_core->v__DOT__ppsck__DOT__step_correction, |
m_core->v__DOT__ppsck__DOT__getnewstep__DOT__genblk2__DOT__genblk1__DOT__r_out, |
m_core->v__DOT__gps_err, |
(m_core->v__DOT__ppsck__DOT__tick)?"TICK":" "); |
*/ |
|
|
// Debug the OLED |
|
{ const char *pwr; int pwrk; |
if (m_core->o_oled_pmoden) { |
if (!m_core->o_oled_reset_n) |
pwr = "RST"; |
else if (m_core->o_oled_vccen) |
pwr = "ON "; |
else |
pwr = "VIO"; |
} else if (m_core->o_oled_vccen) { |
pwr = "ERR"; |
} else |
pwr = "OFF"; |
pwrk = (m_core->o_oled_reset_n)?4:0; |
pwrk|= (m_core->o_oled_vccen)?2:0; |
pwrk|= (m_core->o_oled_pmoden); |
// First the top-level ports |
printf(" OLED[%s/%d,%s%s%s-%d]", |
pwr, pwrk, |
(!m_core->o_oled_cs_n)?"CS":" ", |
(m_core->o_oled_sck)?"CK":" ", |
(m_core->o_oled_dcn)?"/D":"/C", |
(m_core->o_oled_mosi)); |
} |
// Now the low-level internals |
printf("LL["); |
switch(m_core->v__DOT__rgbctrl__DOT__lwlvl__DOT__state){ |
case 0: printf("I,"); break; |
case 1: printf("S,"); break; |
case 2: printf("B,"); break; |
case 3: printf("R,"); break; |
case 4: printf("!,"); break; |
case 5: printf(".,"); break; |
default: printf("U%d", |
m_core->v__DOT__rgbctrl__DOT__lwlvl__DOT__state); |
} |
printf("%2d,%s%2d,%08x]", |
m_core->v__DOT__rgbctrl__DOT__lwlvl__DOT__spi_len, |
(m_core->v__DOT__rgbctrl__DOT__lwlvl__DOT__pre_last_counter)?"P":" ", |
|
m_core->v__DOT__rgbctrl__DOT__lwlvl__DOT__counter, |
m_core->v__DOT__rgbctrl__DOT__lwlvl__DOT__r_word); |
printf("[%s%s%s/%2d/%d]", |
(m_core->v__DOT__rgbctrl__DOT__dev_wr)?"W":" ", |
(m_core->v__DOT__rgbctrl__DOT__r_busy)?"BSY":" ", |
(m_core->v__DOT__rgbctrl__DOT__dev_busy)?"D-BSY":" ", |
m_core->v__DOT__rgbctrl__DOT__r_len, |
m_core->v__DOT__rgbctrl__DOT__dev_len); |
|
printf("\n"); fflush(stdout); |
} m_last_writeout = writeout; |
#endif |
547,6 → 691,9
} |
|
int main(int argc, char **argv) { |
#ifdef OLEDSIM_H |
Gtk::Main main_instance(argc, argv); |
#endif |
Verilated::commandArgs(argc, argv); |
tb = new TESTBENCH; |
|
558,8 → 705,12
else |
tb->setsdcard("/dev/zero"); |
|
#ifdef OLEDSIM_H |
Gtk::Main::run(tb->m_oled); |
#else |
while(1) |
tb->tick(); |
#endif |
|
exit(0); |
} |
/cpp/oledsim.cpp
0,0 → 1,531
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: oledsim.cpp |
// |
// Project: OpenArty, an entirely open SoC based upon the Arty platform |
// |
// Purpose: The goal of this module is very specifically to simulate the |
// PModOLEDrgb using a GTKMM controlled window. I'm doing this on |
// an Linux computer with X-Windows, although one GTKMM selling point is |
// that it should work in Windows as well. I won't vouch for that, as I |
// haven't tested under windows. |
// |
// Either way, this controller only implements *some* of the OLED commands. |
// There were just too many commands for me to be able to write them in the |
// short order that I needed to get a test up and running. Therefore, this |
// simulator will validate all commands and assure you they are valid |
// commands, but it will only respond to some. For specifics, see the |
// do_command() section below. |
// |
// You may notice a lot of assert() calls within this code. This is half |
// the purpose of the code: to verify that interactions, when the take |
// place, are valid. The sad problem and effect of this is simply that |
// when bugs are present, the error/warning messages are not that complete. |
// If you find yourself dealing with such an error, please feel free to |
// explain the assert better before asserting, and then send your |
// contributions back to me so that others can benefit from your work. |
// (Don't you love the GPL?) |
// |
// 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 "oledsim.h" |
|
const int OLEDSIM::OLED_HEIGHT = 64, OLEDSIM::OLED_WIDTH = 96; |
|
const int MICROSECOND = 81, |
tMINRESET = 3 * MICROSECOND, // 3 uS |
tCYCLE = 13, // 150 * NANOSECOND, clock cycle time |
tAS = 4, // 40 * NANOSECOND, address setup time |
tAH = 4, // 40 * NANOSECOND, address hold time |
tCSS = 7, // 75 * NANOSECOND, chip select setup |
tCSH = 5, // 60 * NANOSECOND, chip select hold |
tCLKL = 7, // 75 * NANOSECOND, time the clock must be low |
tCLKH = 7; // 75 * NANOSECOND, time the clock must be high |
|
void OLEDSIM::on_realize() { |
Gtk::DrawingArea::on_realize(); |
|
// We'll be doing all of our drawing on an off-screen bit map. Here, |
// let's allocate that pixel map ... |
m_pix = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24, |
OLED_WIDTH, OLED_HEIGHT); |
|
// and a graphics context to be used when drawing to it. |
m_gc = Cairo::Context::create(m_pix); |
|
// We'll start the pixel map filled with all black, as this is what |
// my device looks like when I'm not doing anything with it. |
m_gc->set_source_rgb(0.0,0.0,0.0); // Black |
m_gc->rectangle(0, 0, OLED_WIDTH, OLED_HEIGHT); |
m_gc->fill(); |
} |
|
void OLEDSIM::get_preferred_width_vfunc(int &min, int &nw) const { |
// GTKMM wants to know how big we want our window to be. |
// Let's request a window twice as big as we need, but insist that |
// it never be smaller than one pixel output per one pixel input. |
// |
min = OLED_WIDTH; |
nw = OLED_WIDTH * 2; |
} |
|
void OLEDSIM::get_preferred_height_vfunc(int &min, int &nw) const { |
// |
// Same thing as above, but this time for height, not width. |
// |
min = OLED_HEIGHT; |
nw = OLED_HEIGHT * 2; |
} |
|
void OLEDSIM::get_preferred_width_for_height_vfunc(int h, int &min, int &nw) const { |
min = OLED_WIDTH; |
int k = (h+(OLED_HEIGHT/2))/OLED_HEIGHT; |
if (k <= 0) |
k = 1; |
nw = OLED_WIDTH * k; |
} |
|
void OLEDSIM::get_preferred_height_for_width_vfunc(int w, int &min, int &nw) const { |
min = OLED_HEIGHT; |
int k = (w+(OLED_WIDTH/2))/OLED_WIDTH; |
if (k <= 0) |
k = 1; |
nw = OLED_HEIGHT * k; |
} |
|
/* |
* This is our simulation function. This is the function that gets called at |
* every tick of our controller within Verilator. At each tick (and not twice |
* per tick), the outputs are gathered and sent our way. Here, we just decode |
* the power and reset outputs, and send everything else to handle_io(). |
*/ |
void OLEDSIM::operator()(const int iopwr, const int rstn, const int dpwr, |
const int csn, const int sck, const int dcn, const int mosi) { |
if (!iopwr) { |
if (m_state != OLED_OFF) { |
m_state = OLED_OFF; |
clear_to(0.0); |
queue_draw_area(0,0,get_width(), get_height()); |
} |
assert(!dpwr); |
} else if (!rstn) { |
if (m_state != OLED_RESET) { |
m_state = OLED_RESET; |
m_locked = true; |
clear_to(0.1); |
m_reset_clocks = 0; |
queue_draw_area(0,0,get_width(), get_height()); |
} if (m_reset_clocks < tMINRESET) |
m_reset_clocks++; |
assert(csn); |
assert(sck); |
} else if (dpwr) { |
if (m_state != OLED_POWERED) { |
m_state = OLED_POWERED; |
queue_draw_area(0,0,get_width(), get_height()); |
if (!csn) { |
printf("OLED-ERR: CSN=%d, SCK=%d, DCN=%d, MOSI=%d, from %d,%d,%d\n", |
csn, sck, dcn, mosi, |
m_last_csn, m_last_sck, m_last_dcn); |
} |
assert(csn); // Can't power up with SPI active. |
} |
|
handle_io(csn, sck, dcn, mosi); |
} else { |
if (m_state != OLED_VIO) { |
m_state = OLED_VIO; |
queue_draw_area(0,0,OLED_WIDTH, OLED_HEIGHT); |
} |
handle_io(csn, sck, dcn, mosi); |
} |
} |
|
/* handle_io() |
* |
* We only enter this function if the I/O is powered up and the device is out |
* of reset. The device may (or may not) be on. Our purpose here is to decode |
* the SPI commands into a byte sequence, kept in m_data with a length given by |
* m_idx. Once a command has completed, we call do_command() to actually |
* process the values received, the arguments, etc. and do something with them. |
* |
*/ |
void OLEDSIM::handle_io(const int csn, const int sck, const int dcn, const int mosi) { |
if ((csn != m_last_csn)||(sck != m_last_sck)||(dcn != m_last_dcn)) |
printf("OLED: HANDLE-IO(%d,%d,%d,%d) @[%d]%d\n", |
csn, sck, dcn, mosi, m_idx, m_bitpos); |
if (csn) { |
// CSN is high when the chip isn't selected. |
if (!m_last_csn) { |
// If the chip was just selected, it then means that our |
// command just completed. Let's process it here. |
printf("OLED: Ending a command\n"); |
assert(m_idx > 0); |
assert((m_bitpos&7)==0); |
do_command(m_last_dcn, m_idx, m_data); |
|
m_bitpos = 0; |
m_idx = 0; |
for(int i=0; i<8; i++) |
m_data[i] = 0; |
assert(m_last_sck); |
} if (!sck) |
printf("OLED: CSN = %d, SCK = %d, DCN = %d, MOSI = %d, from %d, %d, %d\n", |
csn, sck, dcn, mosi, |
m_last_csn, m_last_sck, m_last_dcn); |
assert(sck); |
m_bitpos = 0; |
m_idx = 0; |
} else { |
if (m_last_csn) { |
assert((sck)&&(m_last_sck)); |
assert(m_last_sck); |
printf("OLED: Starting a command\n"); |
} |
|
/* |
if (m_last_dcn != dcn) { |
m_address_counts = 0; |
} m_address_counts++; |
*/ |
|
if ((sck)&&(!m_last_sck)) { |
m_bitpos++; |
m_data[m_idx] = (m_data[m_idx]<<1)|mosi; |
printf("OLED: Accepted bit: m_data[%d] = %02x\n", |
m_idx, m_data[m_idx]); |
if (m_bitpos >= 8) { |
m_idx++; |
m_bitpos &= 7; |
} |
assert(m_idx < 3+4+4); |
// assert(m_address_count > tCSS); |
} else if ((!sck)&&(m_last_sck)) { |
} |
} |
|
m_last_csn = csn; |
m_last_sck = sck; |
m_last_dcn = dcn; |
} |
|
void OLEDSIM::do_command(const int dcn, const int len, char *data) { |
assert(len > 0); |
assert(len <= 11); |
|
printf("OLED: RECEIVED CMD(%02x) ", data[0]&0x0ff); |
if (len > 1) { |
printf(" - "); |
for(int i=1; i<len-1; i++) |
printf("%02x:", data[i]&0x0ff); |
printf("%02x", data[len-1]&0x0ff); |
printf("\n"); |
} |
|
if (dcn) { |
// Do something with the pixmap |
double dr, dg, db; |
|
if (m_format == OLED_65kCLR) { |
int r, g, b; |
assert(len == 2); |
r = (data[0]>>3)&0x01f; |
g = ((data[0]<<3)&0x038)|((data[1]>>5)&0x07); |
b = ((data[1] )&0x01f); |
|
dr = r / 31.0; |
dg = g / 63.0; |
db = b / 31.0; |
} else { |
printf("OLED: UNSUPPORTED COLOR FORMAT!\n"); |
dr = dg = db = 0.0; |
} set_gddram(m_col, m_row, dr, dg, db); |
if (!m_vaddr_inc) { |
m_col++; |
if (m_col > m_col_end) { |
m_col = m_col_start; |
m_row++; |
if (m_row > m_row_end) |
m_row = m_row_start; |
} |
} else { |
m_row++; |
if (m_row > m_row_end) { |
m_row = m_row_start; |
m_col++; |
if (m_col > m_col_end) |
m_col = m_col_start; |
} |
} |
} else if (m_locked) { |
if ((len == 2)&&((data[0]&0x0ff) == 0x0fd)&&(data[1] == 0x12)) { |
m_locked = false; |
printf("OLED: COMMANDS UNLOCKED\n"); |
} else { |
printf("OLED: COMMAND IGNORED, IC LOCKED\n"); |
} |
} else { |
// Command word |
switch((data[0])&0x0ff) { |
case 0x15: // Setup column start and end address |
assert(len == 3); |
assert((data[1]&0x0ff) <= 95); |
assert((data[2]&0x0ff) <= 95); |
m_col_start = data[1]&0x0ff; |
m_col_end = data[2]&0x0ff; |
assert(m_col_end >= m_col_start); |
m_col = m_col_start; |
break; |
case 0x75: // Setup row start and end address |
assert(len == 3); |
assert((data[1]&0x0ff) <= 63); |
assert((data[2]&0x0ff) <= 63); |
assert(m_row_end >= m_row_start); |
m_row_start = data[1]&0x0ff; |
m_row_end = data[2]&0x0ff; |
break; |
case 0x81: // Set constrast for all color "A" segment |
assert(len == 2); |
break; |
case 0x82: // Set constrast for all color "B" segment |
assert(len == 2); |
break; |
case 0x83: // Set constrast for all color "C" segment |
assert(len == 2); |
break; |
case 0x87: // Set master current attenuation factor |
assert(len == 2); |
break; |
case 0x8a: // Set second pre-charge speed, color A |
assert(len == 2); |
break; |
case 0x8b: // Set second pre-charge speed, color B |
assert(len == 2); |
break; |
case 0x8c: // Set second pre-charge speed, color C |
assert(len == 2); |
break; |
case 0xa0: // Set driver remap and color depth |
assert(len == 2); |
m_vaddr_inc = (data[1]&1)?true:false; |
// m_fliplr = (data[1]&2)?true:false; |
if ((data[1] & 0x0c0)==0) |
m_format = OLED_256CLR; |
else if ((data[1] & 0x0c0)==0x40) |
m_format = OLED_65kCLR; |
// else if ((data[1] & 0x0c0)==0x80) |
// m_format = OLED_65kCLRTWO; |
|
break; |
case 0xa1: // Set display start line register by row |
assert(len == 2); |
break; |
case 0xa2: // Set vertical offset by com |
assert(len == 2); |
break; |
case 0xa4: // Set display mode |
case 0xa5: // Fallthrough |
case 0xa6: // Fallthrough |
case 0xa7: // Fallthrough |
assert(len == 1); |
break; |
case 0xa8: // Set multiplex ratio |
assert(len == 2); |
break; |
case 0xab: // Dim Mode setting |
assert(len == 6); |
break; |
case 0xad: |
assert(len == 2); |
assert((data[1]&0x0fe)==0x08e); |
break; |
case 0xac: |
case 0xae: |
case 0xaf: |
assert(len == 1); |
break; |
case 0xb0: // Power save mode |
assert((len == 2)&&((data[1] == 0x1a)||(data[1] == 0x0b))); |
break; |
case 0xb1: // Phase 1 and 2 period adjustment |
assert(len == 2); |
break; |
case 0xb3: // Displaky clock divider/oscillator frequency |
assert(len == 2); |
break; |
case 0xb8: // Set gray scale table |
assert(0 && "Gray scale table not implemented"); |
break; |
case 0xb9: // Enable Linear Gray Scale table |
assert(len == 1); |
break; |
case 0xbb: // Set pre-charge level |
assert(len == 2); |
break; |
case 0xbc: // NOP |
case 0xbd: // NOP |
assert(len == 1); |
case 0xbe: // Set V_COMH |
assert(len == 2); |
break; |
case 0xe3: // NOP |
assert(len == 1); |
break; |
case 0xfd: // Set command lock |
assert(len == 2); |
if (data[1] == 0x16) { |
m_locked = true; |
printf("OLED: COMMANDS NOW LOCKED\n"); |
} |
break; |
case 0x21: // Draw Line |
assert(len == 8); |
break; |
case 0x22: // Draw Rectangle |
assert(len == 11); |
break; |
case 0x23: // Copy |
assert(len == 7); |
break; |
case 0x24: // Dim Window |
assert(len == 5); |
break; |
case 0x25: // Clear Window |
assert(len == 5); |
break; |
case 0x26: // Fill Enable/Disable |
assert(len == 2); |
// if (data[0]&1) |
// m_drect_fills = 1; |
assert((data[1] & 0x10)==0); |
break; |
case 0x27: // Continuous horizontal and vertical scrolling setup |
assert(len == 6); |
break; |
case 0x2e: // Deactivate scrolling |
assert(len == 1); |
// m_scrolling = false; |
break; |
case 0x2f: // Activate scrolling |
assert(len == 1); |
// m_scrolling = true; |
break; |
default: |
printf("OLED: UNKNOWN COMMAND, data[0] = %02x\n", data[0] & 0x0ff); |
assert(0); |
break; |
} |
} |
} |
|
/* |
* set_gddram() |
* |
* Set graphics display DRAM. |
* |
* Here is the heart of drawing on the device, or at least pixel level drawing. |
* The device allows other types of drawing, such as filling rectangles and |
* such. Here, we just handle the setting of pixels. |
* |
* You'll note that updates to the drawing area are only queued if the device |
* is in powered mode. |
* |
* At some point, I may wish to implement scrolling. If/when that happens, |
* the GDDRAM will not be affected, but the area that needs to be redrawn will |
* be. Hence this routine will need to be adjusted at that time. |
*/ |
void OLEDSIM::set_gddram(const int col, const int row, |
const double dr, const double dg, const double db) { |
// Set our color to that given by the rgb (double) parameters. |
m_gc->set_source_rgb(dr, dg, db); |
|
printf("OLED: Setting pixel[%2d,%2d]\n", col, row); |
int drow; // dcol; |
drow = row + m_display_start_row; |
if (drow >= OLED_HEIGHT) |
drow -= OLED_HEIGHT; |
m_gc->rectangle(col, row, 1, 1); |
m_gc->fill(); |
|
if (m_state == OLED_POWERED) { |
// Need to adjust the invalidated area if scrolling is taking |
// place. |
double kw, kh; |
kw = get_width()/(double)OLED_WIDTH; |
kh = get_height()/(double)OLED_HEIGHT; |
queue_draw_area(col*kw, row*kh, (int)(kw+0.5), (int)(kh+0.5)); |
} |
} |
|
/* |
* clear_to() |
* |
* Clears the simulated device to a known grayscale value. Examples are |
* 0.0 for black, or 0.1 for a gray that is nearly black. Note that this |
* call does *not* invalidate our window. Perhaps it should, but for now that |
* is the responsibility of whatever function calls this function. |
*/ |
void OLEDSIM::clear_to(double v) { |
// How do we apply this to our pixmap? |
m_gc->set_source_rgb(v, v, v); |
m_gc->rectangle(0, 0, OLED_WIDTH, OLED_HEIGHT); |
m_gc->fill(); |
} |
|
bool OLEDSIM::on_draw(CONTEXT &gc) { |
gc->save(); |
if (m_state == OLED_POWERED) { |
// Scrolling will be implemented here |
gc->set_source(m_pix, 0, 0); |
gc->scale(get_width()/(double)OLED_WIDTH, |
get_height()/(double)OLED_HEIGHT); |
gc->paint(); |
} else { |
if ((m_state == OLED_VIO)||(m_state == OLED_RESET)) |
gc->set_source_rgb(0.1,0.1,0.1); // DARK gray |
else |
gc->set_source_rgb(0.0,0.0,0.0); // Black |
// gc->rectangle(0, 0, OLED_WIDTH, OLED_HEIGHT); |
gc->rectangle(0, 0, get_width(), get_height()); |
gc->fill(); |
} gc->restore(); |
|
return true; |
} |
|
OLEDWIN::OLEDWIN(void) { |
m_sim = new OLEDSIM(); |
m_sim->set_size_request(OLEDSIM::OLED_WIDTH, OLEDSIM::OLED_HEIGHT); |
set_border_width(0); |
add(*m_sim); |
show_all(); |
Gtk::Window::set_title(Glib::ustring("OLED Simulator")); |
} |
|
/cpp/oledsim.h
0,0 → 1,128
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: oledsim.h |
// |
// Project: OpenArty, an entirely open SoC based upon the Arty platform |
// |
// Purpose: To simulate the interaction between the OLED board and my |
// logic. This simulator tries to read from the SPI generated |
// by the logic, verify that the SPI interaction is valid, and then |
// draws the OLED memory to the screen so you can see how the OLED |
// would work ... even without having an OLED connected. |
// |
// 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 OLEDSIM_H |
#define OLEDSIM_H |
|
#include <gtkmm.h> |
#include <assert.h> |
|
#define OLED_OFF 1 |
#define OLED_RESET 2 |
#define OLED_VIO 3 |
#define OLED_POWERED 4 |
#define OLED_65kCLR 0 |
#define OLED_256CLR 1 |
|
class OLEDSIM : public Gtk::DrawingArea { |
public: |
typedef Cairo::RefPtr<Cairo::Context> CAIROGC; |
typedef const Cairo::RefPtr<Cairo::Context> CONTEXT; |
typedef Cairo::RefPtr<Cairo::ImageSurface> CAIROIMG; |
|
private: |
CAIROIMG m_pix; |
CAIROGC m_gc; |
|
int m_state, m_reset_clocks; // , m_address_counts; |
|
int m_last_csn, m_last_sck, m_last_dcn; |
|
int m_idx, m_bitpos; |
char m_data[16]; |
|
bool m_vaddr_inc, m_locked; |
int m_format; |
int m_col_start, m_col_end, m_col; |
int m_row_start, m_row_end, m_row, m_display_start_row; |
|
|
void do_command(const int dcn, const int len, char *data); |
void handle_io(const int, const int, const int, const int); |
void clear_to(const double v); |
void set_gddram(const int, const int, const double, const double, const double); |
public: |
static const int OLED_HEIGHT, OLED_WIDTH; |
|
OLEDSIM(void) : Gtk::DrawingArea() { |
|
set_has_window(true); |
Widget::set_can_focus(false); |
set_size_request(OLED_WIDTH, OLED_HEIGHT); |
|
m_state = OLED_OFF; |
m_locked = true; |
m_last_csn = 1; |
m_last_sck = 1; |
m_last_dcn = 1; |
m_format = OLED_65kCLR; |
m_display_start_row = 0; |
m_vaddr_inc = false; |
m_col = 0; m_row = 0; |
m_col_start = 0; m_row_start = 0; |
m_col_end = 95; m_row_end = 63; |
} |
|
void get_preferred_width_vfunc(int &min, int &nw) const; |
void get_preferred_height_vfunc(int &min, int &nw) const; |
void get_preferred_height_for_width_vfunc(int w, int &min, int &nw) const; |
void get_preferred_width_for_height_vfunc(int h, int &min, int &nw) const; |
|
virtual void on_realize(); |
virtual bool on_draw(CONTEXT &gc); |
void operator()(const int iopwr, const int rstn, const int dpwr, |
const int csn, const int sck, const int dcn, const int mosi); |
}; |
|
class OLEDWIN : public Gtk::Window { |
private: |
OLEDSIM *m_sim; |
|
public: |
OLEDWIN(void); |
~OLEDWIN(void) { delete m_sim; } |
void operator()(int iopwr, int rstn, int dpwr, |
int sck, int csn, int dcn, int mosi) { |
(*m_sim)(iopwr, rstn, dpwr, sck, csn, dcn, mosi); |
} |
}; |
|
#endif |
/cpp/sdspisim.cpp
378,9 → 378,10
} m_block_buf[0] = 0x0fe; |
m_blklen = 512; // (1<<m_csd[5]); |
if (m_dev) |
fread(&m_block_buf[1], m_blklen, 1, m_dev); |
m_blklen = fread(&m_block_buf[1], m_blklen, 1, m_dev); |
else |
memset(&m_block_buf[1], 0, m_blklen); |
m_blklen = (m_blklen != 512) ? 512 : m_blklen; |
add_block_crc(m_blklen, m_block_buf); |
|
m_blkdly = 60; |
/cpp/sdspisim.h
42,6 → 42,8
#ifndef SDSPISIM_H |
#define SDSPISIM_H |
|
#include <stdio.h> |
|
typedef enum eRESET_STATES { |
SDSPI_POWERUP_RESET, |
SDSPI_CMD0_IDLE, |