OpenCores
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 10 to Rev 11
    Reverse comparison

Rev 10 → Rev 11

/cpp/fastmaster_tb.cpp
0,0 → 1,274
////////////////////////////////////////////////////////////////////////////////
//
// Filename: fastmaster_tb.cpp
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: This is a piped version of the testbench for the fastmaster
// verilog module. The fastmaster code is designed to be a
// complete code set implementing all of the functionality of the Digilent
// Arty board. If done well, the programs talking to this one should be
// able to talk to the board and apply the same tests to the board itself.
//
// 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 <signal.h>
#include <time.h>
#include <ctype.h>
 
#include "verilated.h"
#include "Vfastmaster.h"
 
#include "testb.h"
// #include "twoc.h"
#include "pipecmdr.h"
#include "eqspiflashsim.h"
#ifdef SDRAM_ACCESS
#include "ddrsdramsim.h"
#endif
#include "sdspisim.h"
#include "uartsim.h"
#include "enetctrlsim.h"
 
#include "port.h"
 
const int LGMEMSIZE = 28;
 
// No particular "parameters" need definition or redefinition here.
class FASTMASTER_TB : public PIPECMDR<Vfastmaster> {
public:
unsigned long m_tx_busy_count;
EQSPIFLASHSIM m_flash;
SDSPISIM m_sdcard;
#ifdef SDRAM_ACCESS
DDRSDRAMSIM m_sdram;
#endif
ENETCTRLSIM *m_mid;
UARTSIM m_uart;
 
unsigned m_last_led, m_last_pic, m_last_tx_state;
time_t m_start_time;
bool m_last_writeout;
int m_last_bus_owner, m_busy;
 
FASTMASTER_TB(void) : PIPECMDR(FPGAPORT),
#ifdef SDRAM_ACCESS
m_sdram(LGMEMSIZE),
#endif
m_uart(FPGAPORT+1)
{
m_start_time = time(NULL);
m_mid = new ENETCTRLSIM;
}
 
void setsdcard(const char *fn) {
m_sdcard.load(fn);
printf("LOADING SDCARD FROM: \'%s\'\n", fn);
}
 
void tick(void) {
if ((m_tickcount & ((1<<28)-1))==0) {
double ticks_per_second = m_tickcount;
time_t seconds_passed = time(NULL)-m_start_time;
if (seconds_passed != 0) {
ticks_per_second /= (double)(time(NULL) - m_start_time);
printf(" ******** %.6f TICKS PER SECOND\n",
ticks_per_second);
}
}
 
// Set up the bus before any clock tick
m_core->i_clk = 1;
 
m_core->i_qspi_dat = m_flash(m_core->o_qspi_cs_n,
m_core->o_qspi_sck, m_core->o_qspi_dat);
 
m_core->i_mdio = (*m_mid)(m_core->o_mdclk,
((m_core->o_mdwe)&(m_core->o_mdio))
|((m_core->o_mdwe)?0:1));
 
#ifdef SDRAM_ACCESS
m_core->i_ddr_data = m_sdram(
m_core->o_ddr_reset_n,
m_core->o_ddr_cke,
m_core->o_ddr_cs_n,
m_core->o_ddr_ras_n,
m_core->o_ddr_cas_n,
m_core->o_ddr_we_n,
m_core->o_ddr_dqs,
m_core->o_ddr_dm,
m_core->o_ddr_odt,
m_core->o_ddr_bus_oe,
m_core->o_ddr_addr,
m_core->o_ddr_ba,
m_core->o_ddr_data);
#else
m_core->i_ddr_data = 0;
#endif
 
m_core->i_aux_rx = m_uart(m_core->o_aux_tx,
m_core->v__DOT__runio__DOT__aux_setup);
 
m_core->i_sd_data = m_sdcard((m_core->o_sd_data&8)?1:0,
m_core->o_sd_sck, m_core->o_sd_cmd);
m_core->i_sd_data &= 1;
m_core->i_sd_data |= (m_core->o_sd_data&0x0e);
 
PIPECMDR::tick();
 
// #define DEBUGGING_OUTPUT
bool writeout = false;
/*
*/
if ((writeout)||(m_last_writeout)) {
printf("%08lx:", m_tickcount);
 
/*
printf("%d/%02x %d/%02x%s ",
m_core->i_rx_stb, m_core->i_rx_data,
m_core->o_tx_stb, m_core->o_tx_data,
m_core->i_tx_busy?"/BSY":" ");
*/
 
/*
printf("(%d,%d->%d),(%c:%d,%d->%d)|%c[%08x/%08x]@%08x %c%c%c",
m_core->v__DOT__wbu_cyc,
m_core->v__DOT__dwb_cyc, // was zip_cyc
0,
m_core->v__DOT__wb_cyc,
//
m_core->v__DOT__wbu_zip_arbiter__DOT__r_a_owner?'Z':'j',
m_core->v__DOT__wbu_stb,
// 0, // m_core->v__DOT__dwb_stb, // was zip_stb
m_core->v__DOT__zippy__DOT__thecpu__DOT__mem_stb_gbl,
m_core->v__DOT__wb_stb,
//
(m_core->v__DOT__wb_we)?'W':'R',
m_core->v__DOT__wb_data,
m_core->v__DOT__dwb_idata,
m_core->v__DOT__wb_addr,
(m_core->v__DOT__dwb_ack)?'A':
(m_core->v__DOT____Vcellinp__genbus____pinNumber9)?'a':' ',
(m_core->v__DOT__dwb_stall)?'S':
(m_core->v__DOT____Vcellinp__genbus____pinNumber10)?'s':' ',
(m_core->v__DOT__wb_err)?'E':'.');
*/
 
/*
*/
 
/*
// CPU Pipeline debugging
*/
 
/*
printf(" SDSPI[%d,%d(%d),(%d)]",
m_core->v__DOT__sdcard_controller__DOT__r_cmd_busy,
m_core->v__DOT__sdcard_controller__DOT__r_sdspi_clk,
m_core->v__DOT__sdcard_controller__DOT__r_cmd_state,
m_core->v__DOT__sdcard_controller__DOT__r_rsp_state);
printf(" LL[%d,%2x->CK=%d/%2x,%s,ST=%2d,TX=%2x,RX=%2x->%d,%2x] ",
m_core->v__DOT__sdcard_controller__DOT__ll_cmd_stb,
m_core->v__DOT__sdcard_controller__DOT__ll_cmd_dat,
m_core->v__DOT__sdcard_controller__DOT__lowlevel__DOT__r_z_counter,
// (m_core->v__DOT__sdcard_controller__DOT__lowlevel__DOT__r_clk_counter==0)?1:0,
m_core->v__DOT__sdcard_controller__DOT__lowlevel__DOT__r_clk_counter,
(m_core->v__DOT__sdcard_controller__DOT__lowlevel__DOT__r_idle)?"IDLE":" ",
m_core->v__DOT__sdcard_controller__DOT__lowlevel__DOT__r_state,
m_core->v__DOT__sdcard_controller__DOT__lowlevel__DOT__r_byte,
m_core->v__DOT__sdcard_controller__DOT__lowlevel__DOT__r_ireg,
m_core->v__DOT__sdcard_controller__DOT__ll_out_stb,
m_core->v__DOT__sdcard_controller__DOT__ll_out_dat
);
printf(" CRC=%02x/%2d",
m_core->v__DOT__sdcard_controller__DOT__r_cmd_crc,
m_core->v__DOT__sdcard_controller__DOT__r_cmd_crc_cnt);
printf(" SPI(%d,%d,%d/%d,%d)->?",
m_core->o_sf_cs_n,
m_core->o_sd_cs_n,
m_core->o_spi_sck, m_core->v__DOT__sdcard_sck,
m_core->o_spi_mosi);
 
printf(" CK=%d,LN=%d",
m_core->v__DOT__sdcard_controller__DOT__r_sdspi_clk,
m_core->v__DOT__sdcard_controller__DOT__r_lgblklen);
 
 
if (m_core->v__DOT__sdcard_controller__DOT__r_use_fifo){
printf(" FIFO");
if (m_core->v__DOT__sdcard_controller__DOT__r_fifo_wr)
printf("-WR(%04x,%d,%d,%d)",
m_core->v__DOT__sdcard_controller__DOT__fifo_rd_crc_reg,
m_core->v__DOT__sdcard_controller__DOT__fifo_rd_crc_stb,
m_core->v__DOT__sdcard_controller__DOT__ll_fifo_pkt_state,
m_core->v__DOT__sdcard_controller__DOT__r_have_data_response_token);
else
printf("-RD(%04x,%d,%d,%d)",
m_core->v__DOT__sdcard_controller__DOT__fifo_wr_crc_reg,
m_core->v__DOT__sdcard_controller__DOT__fifo_wr_crc_stb,
m_core->v__DOT__sdcard_controller__DOT__ll_fifo_wr_state,
m_core->v__DOT__sdcard_controller__DOT__ll_fifo_wr_complete
);
}
*/
 
 
printf("\n"); fflush(stdout);
} m_last_writeout = writeout;
}
};
 
FASTMASTER_TB *tb;
 
void fastmaster_kill(int v) {
tb->kill();
fprintf(stderr, "KILLED!!\n");
exit(0);
}
 
int main(int argc, char **argv) {
Verilated::commandArgs(argc, argv);
tb = new FASTMASTER_TB;
 
// signal(SIGINT, fastmaster_kill);
 
tb->reset();
if (argc > 1)
tb->setsdcard(argv[1]);
else
tb->setsdcard("/dev/zero");
 
while(1)
tb->tick();
 
exit(0);
}
 
/cpp/sdspisim.h
0,0 → 1,89
////////////////////////////////////////////////////////////////////////////////
//
// Filename: sdspisim.h
//
// Project: Wishbone Controlled SD-Card Controller over SPI port
//
// Purpose: This library simulates the operation of a SPI commanded SD-Card,
// such as might be found on a XuLA2-LX25 board made by xess.com.
//
// This simulator is for testing use in a Verilator/C++ environment, where
// it would be used in place of the actual hardware.
//
// 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 SDSPISIM_H
#define SDSPISIM_H
 
typedef enum eRESET_STATES {
SDSPI_POWERUP_RESET,
SDSPI_CMD0_IDLE,
SDSPI_RCVD_CMD8,
SDSPI_RCVD_ACMD41,
SDSPI_RESET_COMPLETE,
SDSPI_IN_OPERATION
} RESET_STATES;
 
#define SDSPI_RSPLEN 8
#define SDSPI_MAXBLKLEN (1+2048+2)
#define SDSPI_CSDLEN (16)
#define SDSPI_CIDLEN (16)
class SDSPISIM {
FILE *m_dev;
unsigned long m_devblocks;
 
int m_last_sck, m_delay, m_mosi;
bool m_busy, m_debug, m_block_address, m_altcmd_flag,
m_syncd, m_host_supports_high_capacity, m_reading_data,
m_have_token;
 
RESET_STATES m_reset_state;
 
int m_cmdidx, m_bitpos, m_rspidx, m_rspdly, m_blkdly,
m_blklen, m_blkidx, m_last_miso, m_powerup_busy,
m_rxloc;
char m_cmdbuf[8], m_dat_out, m_dat_in;
char m_rspbuf[SDSPI_RSPLEN];
char m_block_buf[SDSPI_MAXBLKLEN];
char m_csd[SDSPI_CSDLEN], m_cid[SDSPI_CIDLEN];
 
public:
SDSPISIM(void);
void load(const char *fname);
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);
unsigned cmdcrc(int ln, char *buf) const;
bool check_cmdcrc(char *buf) const;
unsigned blockcrc(int ln, char *buf) const;
void add_block_crc(int ln, char *buf) const;
};
 
#endif
/cpp/pipecmdr.h
0,0 → 1,274
////////////////////////////////////////////////////////////////////////////////
//
// Filename: pipecmdr.h
//
// Project: XuLA2-LX25 SoC based upon the ZipCPU
//
// Purpose: This program attaches to a Verilated Verilog IP core.
// It will not work apart from such a core. Once attached,
// it connects the simulated core to a controller via a pipe interface
// designed to act like a UART. Indeed, it is hoped that the final
// interface would be via UART. Until that point, however, this is just
// a simple test facility designed to verify that the IP core works
// prior to such actual hardware implementation.
//
// 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 PIPECMDR_H
#define PIPECMDR_H
 
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <unistd.h>
#include <arpa/inet.h>
 
#include "testb.h"
 
#define PIPEBUFLEN 256
 
// At 115200 Baud, 8 bits of data, no parity and one stop bit, there will
// bit ten bits per character and therefore 8681 clocks per transfer
// 8681 ~= 100 MHz / 115200 (bauds / second) * 10 bauds / character
//
// #define UARTLEN 8681 // Minimum ticks per character, 115200 Baud
//
// At 4MBaud, each bit takes 25 clocks. 10 bits would thus take 250 clocks
//
// #define UARTLEN 250 // Minimum ticks per character, 4M Baud
// #define UARTLEN 1000 // Minimum ticks per character, 1M Hz
// #define UARTLEN 8 // Minimum ticks per character
#define UARTLEN 4096 //
 
template <class VA> class PIPECMDR : public TESTB<VA> {
void setup_listener(const int port) {
struct sockaddr_in my_addr;
 
signal(SIGPIPE, SIG_IGN);
 
printf("Listening on port %d\n", port);
 
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;
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);
}
}
 
public:
int m_skt, m_con;
char m_txbuf[PIPEBUFLEN], m_rxbuf[PIPEBUFLEN];
int m_ilen, m_rxpos, m_txpos, m_uart_wait, m_tx_busy;
bool m_started_flag;
 
PIPECMDR(const int port) : TESTB<VA>() {
m_con = m_skt = -1;
setup_listener(port);
m_rxpos = m_txpos = m_ilen = 0;
m_started_flag = false;
m_uart_wait = 0; // Flow control into the FPGA
m_tx_busy = 0; // Flow control out of the FPGA
}
 
virtual void kill(void) {
// Close any active connection
if (m_con >= 0) close(m_con);
if (m_skt >= 0) close(m_skt);
}
 
virtual void tick(void) {
if (m_con < 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_con = accept(m_skt, 0, 0);
 
if (m_con < 0)
perror("Accept failed:");
}
}
 
TESTB<VA>::m_core->i_rx_stb = 0;
 
if (m_uart_wait == 0) {
if (m_ilen > 0) {
// Is there a byte in our buffer somewhere?
TESTB<VA>::m_core->i_rx_stb = 1;
TESTB<VA>::m_core->i_rx_data = m_rxbuf[m_rxpos++];
m_ilen--;
} else if (m_con > 0) {
// Is there a byte to be read here?
struct pollfd pb;
pb.fd = m_con;
pb.events = POLLIN;
if (poll(&pb, 1, 0) < 0)
perror("Polling error:");
if (pb.revents & POLLIN) {
if ((m_ilen =recv(m_con, m_rxbuf, sizeof(m_rxbuf), MSG_DONTWAIT)) > 0) {
m_rxbuf[m_ilen] = '\0';
if (m_rxbuf[m_ilen-1] == '\n') {
m_rxbuf[m_ilen-1] = '\0';
printf("< \'%s\'\n", m_rxbuf);
m_rxbuf[m_ilen-1] = '\n';
} else printf("< \'%s\'\n", m_rxbuf);
TESTB<VA>::m_core->i_rx_stb = 1;
TESTB<VA>::m_core->i_rx_data = m_rxbuf[0];
m_rxpos = 1; m_ilen--;
m_started_flag = true;
} else if (m_ilen < 0) {
// An error occurred, close the connection
// This could also be the
// indication of a simple
// connection close, so we deal
// with this quietly.
// perror("Read error: ");
// fprintf(stderr, "Closing connection\n");
close(m_con);
m_con = -1;
} else { // the connection closed on us
close(m_con);
m_con = -1;
}
}
} m_uart_wait = (TESTB<VA>::m_core->i_rx_stb)?UARTLEN:0;
} else {
// Still working on transmitting a character
m_uart_wait = m_uart_wait - 1;
}
 
/*
if (TESTB<VA>::m_core->i_rx_stb) {
putchar(TESTB<VA>::m_core->i_rx_data);
fflush(stdout);
}
*/
TESTB<VA>::tick();
 
bool tx_accepted = false;
if (m_tx_busy == 0) {
if ((TESTB<VA>::m_core->o_tx_stb)&&(m_con > 0)) {
m_txbuf[m_txpos++] = TESTB<VA>::m_core->o_tx_data;
tx_accepted = true;
if ((TESTB<VA>::m_core->o_tx_data == '\n')||(m_txpos >= (int)sizeof(m_txbuf))) {
int snt = 0;
snt = send(m_con, m_txbuf, m_txpos, 0);
if (snt < 0) {
close(m_con);
m_con = -1;
snt = 0;
}
m_txbuf[m_txpos] = '\0';
printf("> %s", m_txbuf);
if (snt < m_txpos) {
fprintf(stderr, "Only sent %d bytes of %d!\n",
snt, m_txpos);
}
m_txpos = 0;
}
}
} else
m_tx_busy--;
 
if ((TESTB<VA>::m_core->o_tx_stb)&&(TESTB<VA>::m_core->i_tx_busy==0))
m_tx_busy = UARTLEN;
TESTB<VA>::m_core->i_tx_busy = (m_tx_busy != 0);
 
if (0) {
if ((m_tx_busy!=0)||(TESTB<VA>::m_core->i_tx_busy)
||(TESTB<VA>::m_core->o_tx_stb)
||(tx_accepted))
printf("%4d %d %d %02x %s\n",
m_tx_busy,
TESTB<VA>::m_core->i_tx_busy,
TESTB<VA>::m_core->o_tx_stb,
TESTB<VA>::m_core->o_tx_data,
(tx_accepted)?"READ!":"");
}
 
 
/*
if((TESTB<VA>::m_core->o_wb_cyc)||(TESTB<VA>::m_core->o_wb_stb)){
printf("BUS: %d,%d,%d %8x %8x\n",
TESTB<VA>::m_core->o_wb_cyc,
TESTB<VA>::m_core->o_wb_stb,
TESTB<VA>::m_core->o_wb_we,
TESTB<VA>::m_core->o_wb_addr,
TESTB<VA>::m_core->o_wb_data);
} else if (m_started_flag) {
printf("%02x,%c,%d,%d,%02x -> %d,%d,%d, %2x,%2x,%2x\n",
TESTB<VA>::m_core->i_rx_data,
(TESTB<VA>::m_core->i_rx_stb)?(TESTB<VA>::m_core->i_rx_data):' ',
TESTB<VA>::m_core->v__DOT__decodewb__DOT__r_valid,
TESTB<VA>::m_core->v__DOT__decodewb__DOT__rx_eol,
TESTB<VA>::m_core->v__DOT__decodewb__DOT__rx_six_bits,
//
TESTB<VA>::m_core->v__DOT__decodewb__DOT__o_rq_strobe,
TESTB<VA>::m_core->v__DOT__decodewb__DOT__o_rq_hold,
TESTB<VA>::m_core->v__DOT__decodewb__DOT__o_rq_we,
//
TESTB<VA>::m_core->v__DOT__decodewb__DOT__state,
TESTB<VA>::m_core->v__DOT__decodewb__DOT__nreg,
TESTB<VA>::m_core->v__DOT__decodewb__DOT__szreg);
}
*/
}
};
 
#endif
/cpp/ddrsdramsim.cpp
0,0 → 1,496
////////////////////////////////////////////////////////////////////////////////
//
// Filename: ddrsdramsim.cpp
//
// Project: A wishbone controlled DDR3 SDRAM memory controller.
//
// 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 <stdio.h>
#include <assert.h>
 
#define PREFIX "DDR3-SDRAM"
const unsigned ckCL = 11,
ckRP = 11,
ckRC = 10,
ckRAS = 7,
ckRFC = 320, // Clocks from refresh to activate
ckREFI = 1560, // 7.8us @ 200MHz = 7.8e-6 * 200e6 = 1560
DDR_MR2 = 0x040 | (((ckCL-5)&7)<<3),
DDR_MR1 = 0x0844,
DDR_MR0 = 0x0200 | (((ckCL-4)&0x07)<<4) | ((ckCL>11)?0x4:0);
/*
const unsigned nREF = 4,
ckREFIn = nREF*ckREFI - (nREF-1) * ckRFC;
*/
const unsigned nREF = 1,
ckREFIn = ckREFI;
 
#include "ddrsdramsim.h"
 
BANKINFO::BANKINFO(void) {
m_state = 0; m_row = 0; m_wcounter = 0; m_min_time_before_precharge=0;
}
 
void BANKINFO::tick(int cmd, unsigned addr) {
if (m_wcounter)
m_wcounter--;
switch(cmd) {
case DDR_REFRESH:
assert(m_state == 0);
break;
case DDR_PRECHARGE:
// assert((m_state&((1<<ckRP)-1)) == ((1<<ckRP)-1));
m_state &= -2;
// While the specification allows precharging an already
// precharged bank, we can keep that from happening
// here:
// assert(m_state&7);
// Only problem is, this will currently break our
// refresh logic.
/*
if (m_min_time_before_precharge != 0) {
printf("BANK-FAIL: TIME-BEFORE-PRECHARGE = %d (should be zero)\n", m_min_time_before_precharge);
assert(m_min_time_before_precharge == 0);
} if (m_min_time_before_activate != 0) {
printf("BANK-FAIL: TIME-BEFORE-ACTIVATE = %d (should be zero)\n", m_min_time_before_activate);
assert(m_min_time_before_activate==0);
}
*/
break;
case DDR_ACTIVATE:
assert((m_state&((1<<ckRP)-1)) == 0);
if (((m_state&7)!=0)&&((addr&0x7fff) != m_row)) {
printf("BANK-FAIL: Attempt to Activate an already active bank without closing it first (m_state = %x)\n", m_state);
assert((m_state&7)==0);
}
 
/*
if (m_wcounter != 0) {
printf("BANK-FAIL: ACTIVATE too soon after write (wcounter = %d)\n", m_wcounter);
assert(m_wcounter == 0);
} if (m_min_time_before_activate!=0) {
printf("BANK-FAIL: ACTIVATE too soon after last activate, (ctr=%d)\n", m_min_time_before_activate);
assert(m_min_time_before_activate==0);
}
*/
m_state = 1;
m_row = addr & 0x7fff;
m_min_time_before_precharge = ckRAS;
m_min_time_before_activate = ckRC;
break;
case DDR_READ: case DDR_WRITE:
if (DDR_READ)
assert(m_wcounter == 0);
else
m_wcounter = 3+4+4;
if ((m_state&((1<<ckRP)-1)) != ((1<<ckRP)-1)) {
printf(PREFIX "::R/W Error: m_state = %08x, ckRP = %d (%08x)\n",
m_state, ckRP, ((1<<ckRP)-1));
assert((m_state&((1<<ckRP)-1)) == ((1<<ckRP)-1));
}
if (m_min_time_before_precharge)
m_min_time_before_precharge--;
if (m_min_time_before_activate)
m_min_time_before_activate--;
break;
case DDR_ZQS:
assert((m_state&((1<<ckRP)-1)) == 0);
if (m_min_time_before_precharge)
m_min_time_before_precharge--;
if (m_min_time_before_activate)
m_min_time_before_activate--;
break;
case DDR_NOOP:
m_state <<= 1;
m_state |= (m_state&2)>>1;
m_state &= ((1<<ckRP)-1);
if (m_min_time_before_precharge)
m_min_time_before_precharge--;
if (m_min_time_before_activate)
m_min_time_before_activate--;
break;
default:
break;
}
}
int gbl_state, gbl_counts;
 
DDRSDRAMSIM::DDRSDRAMSIM(int lglen) {
m_memlen = (1<<(lglen-2));
m_mem = new unsigned[m_memlen];
m_reset_state = 0;
m_reset_counts= 0;
assert(NTIMESLOTS > ckCL+3);
m_bus = new BUSTIMESLOT[NTIMESLOTS];
for(int i=0; i<NTIMESLOTS; i++)
m_bus[i].m_used = 0;
for(int i=0; i<NTIMESLOTS; i++)
m_bus[i].m_rtt = 0;
m_busloc = 0;
}
 
unsigned DDRSDRAMSIM::operator()(int reset_n, int cke,
int csn, int rasn, int casn, int wen,
int dqs, int dm, int odt, int busoe,
int addr, int ba, int data) {
BUSTIMESLOT *ts, *nxtts;
int cmd = (reset_n?0:32)|(cke?0:16)|(csn?8:0)
|(rasn?4:0)|(casn?2:0)|(wen?1:0);
 
if ((m_reset_state!=0)&&(reset_n==0)) {
m_reset_state = 0;
m_reset_counts = 0;
} else if (m_reset_state < 16) {
switch(m_reset_state) {
case 0:
m_reset_counts++;
if (reset_n) {
assert(m_reset_counts > 40000);
m_reset_counts = 0;
m_reset_state = 1;
} break;
case 1:
m_reset_counts++;
if (cke) {
assert(m_reset_counts > 100000);
m_reset_counts = 0;
m_reset_state = 2;
} break;
case 2:
m_reset_counts++;
assert(cke);
if (cmd != DDR_NOOP) {
assert(m_reset_counts > 147);
m_reset_counts = 0;
m_reset_state = 3;
assert(cmd == DDR_MRSET);
// Set MR2
assert(ba == 2);
assert(addr == DDR_MR2);
} break;
case 3:
m_reset_counts++;
assert(cke);
if (cmd != DDR_NOOP) {
// assert(m_reset_counts > 3);
m_reset_counts = 0;
m_reset_state = 4;
assert(cmd == DDR_MRSET);
// Set MR1
assert(ba == 1);
assert(addr == DDR_MR1);
} break;
case 4:
m_reset_counts++;
assert(cke);
if (cmd != DDR_NOOP) {
printf(PREFIX "::RESET-CMD[4]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
assert(m_reset_counts > 3);
m_reset_counts = 0;
m_reset_state = 5;
assert(cmd == DDR_MRSET);
// Set MR0
assert(ba == 0);
assert(addr == DDR_MR0);
} break;
case 5:
m_reset_counts++;
assert(cke);
if (cmd != DDR_NOOP) {
printf(PREFIX "::RESET-CMD[5]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
assert(m_reset_counts > 11);
m_reset_counts = 0;
m_reset_state = 6;
assert(cmd == DDR_ZQS);
assert(addr == 0x400);
} break;
case 6:
m_reset_counts++;
assert(cke);
if (cmd != DDR_NOOP) {
printf(PREFIX "::RESET-CMD[6]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
assert(m_reset_counts > 512);
m_reset_counts = 0;
m_reset_state = 7;
assert(cmd == DDR_PRECHARGE);
assert(addr == 0x400);
} break;
case 7:
m_reset_counts++;
assert(cke);
if (cmd != DDR_NOOP) {
printf(PREFIX "::RESET-CMD[7]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
assert(m_reset_counts > 3);
m_reset_counts = 0;
m_reset_state = 8;
assert(cmd == DDR_REFRESH);
m_clocks_since_refresh = 0;
} break;
case 8:
m_reset_counts++;
assert(cke);
assert(cmd == DDR_NOOP);
if (m_reset_counts > 140) {
m_reset_state = 16;
printf(PREFIX ": Leaving reset state\n");
}
break;
default:
break;
}
 
gbl_state = m_reset_state;
gbl_counts= m_reset_counts;
m_nrefresh_issued = nREF;
m_clocks_since_refresh++;
for(int i=0; i<NBANKS; i++)
m_bank[i].tick(cmd, 0);
} else if (!cke) {
assert(0&&"Clock not enabled!");
} else if ((cmd == DDR_REFRESH)||(m_nrefresh_issued < (int)nREF)) {
if (DDR_REFRESH == cmd) {
m_clocks_since_refresh = 0;
if (m_nrefresh_issued >= (int)nREF)
m_nrefresh_issued = 1;
else
m_nrefresh_issued++;
} else {
m_clocks_since_refresh++;
assert(DDR_NOOP == cmd);
}
for(int i=0; i<NBANKS; i++)
m_bank[i].tick(cmd,0);
 
if (m_nrefresh_issued == nREF)
printf(PREFIX "::Refresh cycle complete\n");
} else {
// In operational mode!!
 
m_clocks_since_refresh++;
assert(m_clocks_since_refresh < (int)ckREFIn);
switch(cmd) {
case DDR_MRSET:
assert(0&&"Modes should only be set in reset startup");
for(int i=0; i<NBANKS; i++)
m_bank[i].tick(DDR_MRSET,0);
break;
case DDR_REFRESH:
for(int i=0; i<NBANKS; i++)
m_bank[i].tick(DDR_REFRESH,0);
m_clocks_since_refresh = 0;
assert(0 && "Internal err: Refresh should be handled above");
break;
case DDR_PRECHARGE:
if (addr & 0x400) {
// Precharge all
for(int i=0; i<NBANKS; i++)
m_bank[i].tick(DDR_PRECHARGE,0);
} else {
m_bank[ba].tick(DDR_PRECHARGE,0);
for(int i=0; i<NBANKS; i++)
if (ba != i)
m_bank[i].tick(DDR_NOOP,0);
}
break;
case DDR_ACTIVATE:
if (m_clocks_since_refresh < (int)ckRFC) {
printf(PREFIX "::ACTIVATE -- not enough clocks since refresh, %d < %d should be true\n", m_clocks_since_refresh, ckRFC);
assert(m_clocks_since_refresh >= (int)ckRFC);
}
printf(PREFIX "::Activating bank %d, address %08x\n", ba, addr);
m_bank[ba].tick(DDR_ACTIVATE,addr);
for(int i=0; i<NBANKS; i++)
if (i!=ba) m_bank[i].tick(DDR_NOOP,0);
break;
case DDR_WRITE:
{
// This SIM doesn't handle out of order writes
assert((addr&7)==0);
m_bank[ba].tick(DDR_WRITE, addr);
for(int i=0; i<NBANKS; i++)
if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
unsigned caddr = m_bank[ba].m_row;
caddr <<= 3;
caddr |= ba;
caddr <<= 10;
caddr |= addr;
caddr &= ~7;
caddr >>= 1;
 
BUSTIMESLOT *tp;
int offset = m_busloc+ckCL+1;
 
tp = &m_bus[(offset+0)&(NTIMESLOTS-1)];
// printf("Setting bus timeslots from (now=%d)+%d=%d to now+%d+3\n", m_busloc, ckCL,(m_busloc+ckCL)&(NTIMESLOTS-1), ckCL);
tp->m_addr = caddr ;
tp->m_used = 1;
tp->m_read = 0;
 
tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
tp->m_addr = caddr+1;
tp->m_used = 1;
tp->m_read = 0;
 
tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
tp->m_addr = caddr+2;
tp->m_used = 1;
tp->m_read = 0;
 
tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
tp->m_addr = caddr+3;
tp->m_used = 1;
tp->m_read = 0;
} break;
case DDR_READ:
{
// This SIM doesn't handle out of order reads
assert((addr&7)==0);
m_bank[ba].tick(DDR_READ, addr);
for(int i=0; i<NBANKS; i++)
if (i!=ba)m_bank[i].tick(DDR_NOOP,addr);
unsigned caddr = m_bank[ba].m_row;
caddr <<= 3;
caddr |= ba;
caddr <<= 10;
caddr |= addr;
caddr &= ~7;
caddr >>= 1;
 
BUSTIMESLOT *tp;
int offset = (m_busloc+ckCL+1)&(NTIMESLOTS-1);
tp = &m_bus[(offset)&(NTIMESLOTS-1)];
tp->m_data = m_mem[caddr];
tp->m_addr = caddr;
tp->m_used = 1;
tp->m_read = 1;
tp = &m_bus[(offset+1)&(NTIMESLOTS-1)];
tp->m_data = m_mem[caddr+1];
tp->m_addr = caddr+1;
tp->m_used = 1;
tp->m_read = 1;
 
tp = &m_bus[(offset+2)&(NTIMESLOTS-1)];
tp->m_data = m_mem[caddr+2];
tp->m_addr = caddr+2;
tp->m_used = 1;
tp->m_read = 1;
 
tp = &m_bus[(offset+3)&(NTIMESLOTS-1)];
tp->m_data = m_mem[caddr+3];
tp->m_addr = caddr+3;
tp->m_used = 1;
tp->m_read = 1;
} break;
case DDR_ZQS:
assert(0&&"Sim does not support ZQS outside of startup");
break;
case DDR_NOOP:
for(int i=0; i<NBANKS; i++)
m_bank[i].tick(DDR_NOOP,addr);
break;
default: // We are deselecteda
for(int i=0; i<NBANKS; i++)
m_bank[i].tick(DDR_NOOP,addr);
break;
}
 
if (false) {
bool flag = false;
for(int i=0; i<5; i++) {
int bl = (m_busloc+1+i)&(NTIMESLOTS-1);
nxtts = &m_bus[bl];
if (nxtts->m_used) {
flag = true;
break;
}
} if (flag) {
printf("DQS = %d BUSLOC = %d\n", dqs, (m_busloc+1)&(NTIMESLOTS-1));
for(int i=0; i<5; i++) {
int bl = (m_busloc+1+i)&(NTIMESLOTS-1);
nxtts = &m_bus[bl];
printf("BUS[%2d] ", bl);
if (nxtts->m_used)
printf(" USED");
if (nxtts->m_read)
printf(" READ");
if (nxtts->m_rtt)
printf(" RTT");
printf("\n");
}}
}
 
ts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
if (dqs)
assert((ts->m_rtt)&&(m_last_rtt));
else if (!m_last_dqs)
assert(!m_last_rtt);
}
 
m_busloc = (m_busloc+1)&(NTIMESLOTS-1);
 
ts = &m_bus[m_busloc];
nxtts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
unsigned vl = ts->m_data;
assert( ((!ts->m_used)||(busoe))
|| ((ts->m_used)&&(ts->m_read)&&(!busoe))
|| ((ts->m_used)&&(!ts->m_read)&&(busoe))
);
 
m_last_dqs = dqs;
m_last_rtt = ts->m_rtt;
 
if (ts->m_used) {
if (ts->m_read)
assert((!dqs)&&(!m_last_dqs));
else
assert((dqs) && (m_last_dqs));
} else if (!nxtts->m_used)
assert(!dqs);
 
assert((!ts->m_used)||(ts->m_addr < (unsigned)m_memlen));
if ((ts->m_used)&&(!ts->m_read)&&(!dm)) {
printf(PREFIX "::Setting MEM[%08x] = %08x\n", ts->m_addr, data);
m_mem[ts->m_addr] = data;
}
 
m_bus[(m_busloc+3)&(NTIMESLOTS-1)].m_rtt = (odt)&&(reset_n);
ts->m_used = 0;
ts->m_read = 0;
ts->m_addr = -1;
ts->m_rtt = 0;
return (!busoe)?vl:data;
}
 
/cpp/ddrsdramsim.h
0,0 → 1,83
////////////////////////////////////////////////////////////////////////////////
//
// Filename: ddrsdramsim.h
//
// Project: A wishbone controlled DDR3 SDRAM memory controller.
//
// 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 DDRSDRAMSIM_H
#define DDRSDRAMSIM_H
 
#define DDR_MRSET 0
#define DDR_REFRESH 1
#define DDR_PRECHARGE 2
#define DDR_ACTIVATE 3
#define DDR_WRITE 4
#define DDR_READ 5
#define DDR_ZQS 6
#define DDR_NOOP 7
 
#define NBANKS 8
#define NTIMESLOTS 32
 
class BANKINFO {
public:
int m_state;
unsigned m_row, m_wcounter;
void tick(int cmd, unsigned addr=0);
};
 
class BUSTIMESLOT {
public:
int m_used, m_read, m_data, m_rtt;
unsigned m_addr;
};
 
class DDRSDRAMSIM {
int m_reset_state, m_reset_counts, m_memlen, m_busloc,
m_clocks_since_refresh, m_nrefresh_issued,
m_last_dqs, m_last_rtt;
unsigned *m_mem;
BANKINFO m_bank[8];
BUSTIMESLOT *m_bus;
int cmd(int,int,int,int);
public:
DDRSDRAMSIM(int lglen);
unsigned operator()(int, int,
int, int, int, int,
int, int, int, int,
int, int, int);
unsigned &operator[](unsigned addr) { return m_mem[addr]; };
};
 
#endif
/cpp/uartsim.cpp
0,0 → 1,234
////////////////////////////////////////////////////////////////////////////////
//
// Filename: uartsim.cpp
//
// Project: XuLA2-LX25 SoC based upon the ZipCPU
//
// 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 <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>
 
#include "uartsim.h"
 
void UARTSIM::setup_listener(const int port) {
struct sockaddr_in my_addr;
 
signal(SIGPIPE, SIG_IGN);
 
printf("Listening on port %d\n", port);
 
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;
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);
}
}
 
UARTSIM::UARTSIM(const int port) {
m_con = m_skt = -1;
setup_listener(port);
setup(25);
m_rx_baudcounter = 0;
m_tx_baudcounter = 0;
m_rx_state = RXIDLE;
m_tx_state = TXIDLE;
}
 
void UARTSIM::kill(void) {
// Close any active connection
if (m_con >= 0) close(m_con);
if (m_skt >= 0) close(m_skt);
}
 
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::tick(int i_tx) {
int o_rx = 1;
 
if (m_con < 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_con = accept(m_skt, 0, 0);
 
if (m_con < 0)
perror("Accept failed:");
}
}
 
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;
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_con > 0) {
char buf[1];
buf[0] = (m_rx_data >> (32-m_nbits-m_nstop-m_nparity))&0x0ff;
if (1 != send(m_con, buf, 1, 0)) {
close(m_con);
m_con = -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;
} else
m_rx_baudcounter--;
 
if (m_tx_state == TXIDLE) {
struct pollfd pb;
pb.fd = m_con;
pb.events = POLLIN;
if (poll(&pb, 1, 0) < 0)
perror("Polling error:");
if (pb.revents & POLLIN) {
char buf[1];
if (1 == recv(m_con, 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_fixdp)
p = m_evenp;
else {
int 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;
}
}
} 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;
o_rx = m_tx_data&1;
} else {
m_tx_baudcounter--;
o_rx = m_tx_data&1;
}
 
return o_rx;
}
 
/*
0x00 -> c0 = 1100 0000???
0x01 -> c0 = 1100 0000??
0x02 -> c0 = 1100 0000?
0x04 -> c1 = 1100 0001
0x20 -> c5 = 1100 0101
0x40 -> ca = 1100 1010
0x80 -> d4 = 1101 0100
*/
/cpp/testb.h
0,0 → 1,70
////////////////////////////////////////////////////////////////////////////////
//
// Filename: testb.h
//
// Project: Zip CPU -- a small, lightweight, RISC CPU core
//
// Purpose: A wrapper for a common interface to a clocked FPGA core
// begin exercised in Verilator.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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 TESTB_H
#define TESTB_H
 
template <class VA> class TESTB {
public:
VA *m_core;
unsigned long m_tickcount;
 
TESTB(void) { m_core = new VA; }
~TESTB(void) { delete m_core; m_core = NULL; }
 
virtual void eval(void) {
m_core->eval();
}
 
virtual void tick(void) {
m_core->i_clk = 1;
eval();
m_core->i_clk = 0;
eval();
 
m_tickcount++;
}
 
virtual void reset(void) {
m_core->i_rst = 1;
tick();
m_core->i_rst = 0;
m_tickcount = 0l;
// printf("RESET\n");
}
};
 
#endif
/cpp/port.h
0,0 → 1,52
////////////////////////////////////////////////////////////////////////////////
//
// Filename: port.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 PORT_H
#define PORT_H
 
// #define FPGAHOST "lazarus"
#define FPGAHOST "localhost"
#define FPGATTY "/dev/ttyUSB1"
#define FPGAPORT 6510
 
#ifndef FORCE_UART
#define FPGAOPEN(V) V= new FPGA(new NETCOMMS(FPGAHOST, FPGAPORT))
#else
#define FPGAOPEN(V) V= new FPGA(new TTYCOMMS(FPGATTY))
#endif
 
#endif
/cpp/uartsim.h
0,0 → 1,78
////////////////////////////////////////////////////////////////////////////////
//
// Filename: uartsim.h
//
// Project: XuLA2-LX25 SoC based upon the ZipCPU
//
// 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 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>
 
#define TXIDLE 0
#define TXDATA 1
#define RXIDLE 0
#define RXDATA 1
 
class UARTSIM {
int m_skt, m_con;
unsigned m_setup;
int m_nparity, m_fixdp, m_evenp, m_nbits, m_nstop, m_baud_counts;
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;
 
void setup_listener(const int port);
int tick(const int i_tx);
 
public:
UARTSIM(const int port);
void kill(void);
void setup(unsigned isetup);
int operator()(int i_tx) {
return tick(i_tx); }
int operator()(int i_tx, unsigned isetup) {
setup(isetup); return tick(i_tx); }
};
 
#endif
/cpp/sdspisim.cpp
0,0 → 1,511
///////////////////////////////////////////////////////////////////////////
//
//
// Filename: sdspisim.cpp
//
// Project: Wishbone Controlled SD-Card Controller over SPI port
//
// Purpose: This library simulates the operation of a SPI commanded SD-Card,
// such as might be found on a XuLA2-LX25 board made by xess.com.
//
// This simulator is for testing use in a Verilator/C++ environment, where
// it would be used in place of the actual hardware.
//
// Creator: Dan Gisselquist
// 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 <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
 
#include "sdspisim.h"
 
static const unsigned
MICROSECONDS = 80, // Clocks in a microsecond
MILLISECONDS = MICROSECONDS * 1000,
tRESET = 4*MILLISECONDS; // Just a wild guess
/*
static const unsigned DEVID = 0x0115,
DEVESD = 0x014,
MICROSECONDS = 100,
MILLISECONDS = MICROSECONDS * 1000,
SECONDS = MILLISECONDS * 1000,
tW = 50 * MICROSECONDS, // write config cycle time
tBE = 32 * SECONDS,
tDP = 10 * SECONDS,
tRES = 30 * SECONDS,
// Shall we artificially speed up this process?
tPP = 12 * MICROSECONDS,
tSE = 15 * MILLISECONDS;
// or keep it at the original speed
// tPP = 1200 * MICROSECONDS,
// tSE = 1500 * MILLISECONDS;
*/
static const unsigned
CCS = 1; // 0: SDSC card, 1: SDHC or SDXC card
 
SDSPISIM::SDSPISIM(void) {
m_dev = NULL;
m_last_sck = 1;
m_block_address = (CCS==1);
m_host_supports_high_capacity = false;
m_powerup_busy = -1;
m_reset_state = SDSPI_POWERUP_RESET;
//
m_csd[ 0] = 0; // Normal SDcard, not high capacity
m_csd[ 1] = 0x0f;
m_csd[ 2] = 0x0f;
m_csd[ 3] = 0x32; // Can be either 0x32 (25MHz) or 0x5a (50MHz)
m_csd[ 4] = 0x5b; // Could also be 0x07b, if we supported more comands(?)
m_csd[ 5] = 0x59; // 9-> 2^9,or 512 bytes (10->1024, 11->2048, no othrs)
m_csd[ 6] = 0x00; // partial blocks allowed?
m_csd[ 7] = 0x00; // C_SIZE, 2'b00, then top 6 bits
m_csd[ 8] = 0; // C_SIZE, 22-bits, mid 8 bits
m_csd[ 9] = 0; // C_SIZE, 22-bits, bottom 8 bits
m_csd[10] = 0x7f;
m_csd[11] = 0x80;
m_csd[12] = 0x0a;
m_csd[13] = 0x40;
m_csd[14] = 0; // R/W: file format, copy, write protect, etc.
m_csd[15] = cmdcrc(15, m_csd);
 
// CID Register
m_cid[ 0] = 0xba;
m_cid[ 1] = 0xd0;
m_cid[ 2] = 0xda;
m_cid[ 3] = 0xdd;
m_cid[ 4] = 0;
m_cid[ 5] = 0xde;
m_cid[ 6] = 0xad;
m_cid[ 7] = 0xbe;
m_cid[ 8] = 0xef;
m_cid[ 9] = 0x20;
m_cid[10] = 0x16;
m_cid[11] = 0x05;
m_cid[12] = 0x26;
m_cid[13] = 0;
m_cid[14] = 0;
m_cid[15] = cmdcrc(15, m_cid);
 
// m_write_count = 0;
// m_ireg = m_oreg = 0;
// m_sreg = 0x01c;
// m_creg = 0x001; // Iinitial creg on delivery
 
//
m_reading_data = false;
m_have_token = false;
}
 
void SDSPISIM::load(const char *fname) {
m_dev = fopen(fname, "r+b");
 
if (m_dev) {
unsigned long devln;
fseek(m_dev, 0l, SEEK_END);
devln = ftell(m_dev);
fseek(m_dev, 0l, SEEK_SET);
 
m_devblocks = devln>>9;
 
printf("SDCARD: NBLOCKS = %ld\n", m_devblocks);
}
}
 
int SDSPISIM::operator()(const int csn, const int sck, const int mosi) {
// Keep track of a timer to determine when page program and erase
// cycles complete.
 
/*
if (m_write_count > 0) {
//
}
*/
 
m_delay++;
if (m_powerup_busy>0)
m_powerup_busy--;
 
if (csn) {
m_delay = 0;
m_cmdidx= 0;
m_rspidx= 0;
m_bitpos= 0;
m_delay = 0;
m_busy = false;
m_last_sck = sck;
m_syncd = false;
m_last_miso = 1;
m_dat_out = 0x0ff;
// Reset everything when not selected
return 0;
} else if (sck == m_last_sck) {
m_last_sck = sck;
return m_last_miso;
} else if (!m_last_sck) {
// Register our input on the rising edge
m_mosi = mosi;
m_syncd= true;
m_last_sck = sck;
return m_last_miso;
} if (!m_syncd) {
m_last_sck = sck;
return m_last_miso;
}
 
// Only change our output on the falling edge
 
m_last_sck = sck;
printf("SDSPI: (%3d) [%d,%d,%d] ", m_delay, csn, sck, m_mosi);
// assert(m_delay > 20);
 
m_bitpos++;
m_dat_in = (m_dat_in<<1)|m_mosi;
 
 
printf("(bitpos=%d,dat_in=%02x)\n", m_bitpos&7, m_dat_in&0x0ff);
 
if ((m_bitpos&7)==0) {
printf("SDSPI--RX BYTE %02x\n", m_dat_in&0x0ff);
m_dat_out = 0xff;
if (m_reading_data) {
if (m_have_token) {
m_block_buf[m_rxloc++] = m_dat_in;
printf("SDSPI: WR[%3d] = %02x\n", m_rxloc-1,
m_dat_in&0x0ff);
if (m_rxloc >= 512+2) {
unsigned crc, rxcrc;
crc = blockcrc(512, m_block_buf);
rxcrc = ((m_block_buf[512]&0x0ff)<<8)
|(m_block_buf[513]&0x0ff);
 
printf("LEN = %d\n", m_rxloc);
printf("CHECKING CRC: (rx) %04x =? %04x (calc)\n",
crc, rxcrc);
m_reading_data = false;
m_have_token = false;
if (rxcrc == crc)
m_dat_out = 5;
else {
m_dat_out = 0x0b;
assert(rxcrc == crc);
}
}
} else {
if ((m_dat_in&0x0ff) == 0x0fe) {
printf("SDSPI: TOKEN!!\n");
m_have_token = true;
m_rxloc = 0;
} else printf("SDSPI: waiting on token\n");
}
} else if (m_cmdidx < 6) {
printf("SDSPI: CMDIDX = %d\n", m_cmdidx);
// All commands *must* start with a 01... pair of bits.
if (m_cmdidx == 0)
assert((m_dat_in&0xc0)==0x40);
 
// Record the command for later processing
m_cmdbuf[m_cmdidx++] = m_dat_in;
} else if (m_cmdidx == 6) {
// We're going to start a response from here ...
m_rspidx = 0;
m_blkdly = 0;
m_blkidx = SDSPI_MAXBLKLEN;
printf("SDSPI: CMDIDX = %d -- WE HAVE A COMMAND! [ ", m_cmdidx);
for(int i=0; i<6; i++)
printf("%02x ", m_cmdbuf[i] & 0xff);
printf("]\n"); fflush(stdout);
 
unsigned arg;
arg = ((((((m_cmdbuf[1]<<8)|(m_cmdbuf[2]&0x0ff))<<8)
|(m_cmdbuf[3]&0x0ff))<<8)
|(m_cmdbuf[4]&0x0ff));
arg &= 0x0ffffffff;
 
// Check the CRC
if (!check_cmdcrc(m_cmdbuf)) {
assert(0 && "BAD CRC");
m_rspbuf[0] = 0x09;
m_rspdly = 1;
} else if (m_altcmd_flag) {
switch(m_cmdbuf[0]&0x03f) {
case 41: // ACMD41 -- SD_SEND_OP_COND
// and start initialization sequence
assert((m_reset_state == SDSPI_RCVD_CMD8)||(m_reset_state == SDSPI_RCVD_ACMD41)||(m_reset_state == SDSPI_RESET_COMPLETE));
if((unsigned)m_powerup_busy>tRESET)
m_powerup_busy = tRESET;
assert((arg&0x0bfffffff) == 0);
m_rspbuf[0] = (m_powerup_busy)?1:0;
m_rspdly = 2;
m_host_supports_high_capacity = (m_cmdbuf[1]&0x40)?1:0;
m_reset_state = (m_powerup_busy)?
SDSPI_RCVD_ACMD41
:SDSPI_RESET_COMPLETE;
break;
case 51: // ACMD51
m_block_buf[0] = 0x0fe;
for(int j=0; j<8; j++)
m_block_buf[j+1] = m_csd[j];
m_blklen = 8;
add_block_crc(m_blklen, m_block_buf);
 
m_blkdly = 0;
m_blkidx = 0;
m_dat_out = 0;
break;
case 13: // ACMD13
case 22: // ACMD22
case 23: // ACMD23
case 42: // ACMD42
default: // Unimplemented command!
m_rspbuf[0] = 0x04;
m_rspdly = 4;
fprintf(stderr, "SDSPI ERR: Alt command ACMD%d not implemented!\n", m_cmdbuf[0]&0x03f);
assert(0 && "Not Implemented");
} m_altcmd_flag = false;
} else {
m_altcmd_flag = false;
memset(m_rspbuf, 0x0ff, SDSPI_RSPLEN);
printf("SDSPI: Received a command 0x%02x (%d)\n",
m_cmdbuf[0], m_cmdbuf[0]&0x03f);
switch(m_cmdbuf[0]&0x3f) {
case 0: // CMD0 -- GO_IDLE_STATE
m_rspbuf[0] = 0x01;
m_rspdly = 4;
m_reset_state = SDSPI_CMD0_IDLE;
break;
case 1: // CMD1 -- SEND_OP_COND
assert((arg&0x0bfffffff) == 0);
m_rspbuf[0] = 0x02;
m_rspdly = 4;
m_host_supports_high_capacity = (m_cmdbuf[1]&0x40)?1:0;
break;
case 8: // CMD8 -- SEND_IF_COND
assert((arg&0x0fffff000) == 0);
m_rspbuf[0] = 0x00;
// See p82 for this format
m_rspbuf[1] = 0;
m_rspbuf[2] = 0;
// If we do not accept the voltage range
m_rspbuf[3] = 0;
// Now, check if we accept it
// We only accept 2.7-3.6V in this
// simulation.
if ((arg&0x0f00)==0x0100)
m_rspbuf[3] = 1;
m_rspbuf[4] = (char)(arg&0x0ff);
m_rspdly = 4;
assert((m_reset_state == SDSPI_CMD0_IDLE)||(m_reset_state == SDSPI_RCVD_CMD8));
m_reset_state = SDSPI_RCVD_CMD8;
break;
case 9: // CMD9 -- SEND_CSD
// Block read, returning start token,
// 16 bytes, then 2 crc bytes
assert(m_reset_state == SDSPI_IN_OPERATION);
m_rspbuf[0] = 0x00;
memset(m_block_buf, 0x0ff, SDSPI_MAXBLKLEN);
m_block_buf[0] = 0x0fe;
for(int j=0; j<16; j++)
m_block_buf[j+1] = m_csd[j];
m_blklen = 16;
add_block_crc(m_blklen, m_block_buf);
 
m_blkdly = 60;
m_blkidx = 0;
break;
case 10: // CMD10 -- SEND_CID
// Block read, returning start token,
// 16 bytes, then 2 crc bytes
assert(m_reset_state == SDSPI_IN_OPERATION);
m_rspbuf[0] = 0x00;
memset(m_block_buf, 0x0ff, SDSPI_MAXBLKLEN);
m_block_buf[0] = 0x0fe;
for(int j=0; j<16; j++)
m_block_buf[j+1] = m_cid[j];
m_blklen = 16;
add_block_crc(m_blklen, m_block_buf);
 
m_blkdly = 60;
m_blkidx = 0;
break;
case 13: // CMD13 -- SEND_STATUS
assert(m_reset_state == SDSPI_IN_OPERATION);
m_rspbuf[0] = 0x00;
m_rspbuf[1] = 0x00;
// if (m_wp_fault) m_rspbuf[1]|=0x20;
// if (m_err) m_rspbuf[1]|=0x04;
m_rspdly = 4;
break;
case 17: // CMD17 -- READ_SINGLE_BLOCK
assert(m_reset_state == SDSPI_IN_OPERATION);
m_rspbuf[0] = 0x00;
memset(m_block_buf, 0x0ff, SDSPI_MAXBLKLEN);
if (m_dev) {
printf("Reading from block %08x of %08lx\n", arg, m_devblocks);
if (m_block_address) {
assert(arg < m_devblocks);
fseek(m_dev, arg<<9, SEEK_SET);
} else {
assert(arg < m_devblocks<<9);
fseek(m_dev, arg, SEEK_SET);
}
} 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);
else
memset(&m_block_buf[1], 0, m_blklen);
add_block_crc(m_blklen, m_block_buf);
 
m_blkdly = 60;
m_blkidx = 0;
break;
case 24: // CMD24 -- WRITE_BLOCK
m_reading_data = true;
m_have_token = false;
m_dat_out = 0;
break;
case 55: // CMD55 -- APP_CMD
m_rspbuf[0] = 0x00;
m_rspdly = 2;
m_altcmd_flag = true;
break;
case 58: // CMD58 -- READ_OCR, respond R7
// argument is stuff bits/dont care
m_rspbuf[0] = 0x00;
// See p112, Tbl 5-1 for this format
m_rspbuf[1] = ((m_powerup_busy)?0x80:0)
|(CCS?0x40:0);
m_rspbuf[2] = 0xff;// 2.7-3.6V supported
m_rspbuf[3] = 0x80;
m_rspbuf[4] = 0; // No low-voltage supt
m_rspdly = 4;
 
if (m_reset_state == SDSPI_RESET_COMPLETE)
m_reset_state = SDSPI_IN_OPERATION;
break;
case 6: // CMD6 -- SWITCH_FUNC
case 12: // CMD12 -- STOP_TRANSMISSION (!impl)
case 16: // CMD16 -- SET_BLOCKLEN
case 18: // CMD18 -- READ_MULTIPLE_BLOCK
case 25: // CMD25 -- WRITE_MULTIPLE_BLOCK
case 27: // CMD27 -- PROGRAM_CSD
case 32: // CMD32 -- ERASE_WR_BLK_START_ADDR
case 33: // CMD33 -- ERASE_WR_BLK_END_ADDR
case 38: // CMD38 -- ERASE
case 56: // CMD56 -- GEN_CMD
default: // Unimplemented command
m_rspbuf[0] = 0x04;
m_rspdly = 4;
printf("SDSPI ERR: Command CMD%d not implemented!\n", m_cmdbuf[0]&0x03f);
fflush(stdout);
assert(0 && "Not Implemented");
}
} m_cmdidx++;
 
// If we are using blocks, add bytes for the start
// token and the two CRC bytes
m_blklen += 3;
} else if (m_rspdly > 0) {
assert((m_dat_in&0x0ff) == 0x0ff);
// A delay until a response is given
if (m_busy)
m_dat_out = 0;
m_rspdly--;
} else if (m_rspidx < SDSPI_RSPLEN) {
assert((m_dat_in&0x0ff) == 0x0ff);
m_dat_out = m_rspbuf[m_rspidx++];
} else if (m_blkdly > 0) {
assert((m_dat_in&0x0ff) == 0x0ff);
m_blkdly--;
} else if (m_blkidx < SDSPI_MAXBLKLEN) {
assert((m_dat_in&0x0ff) == 0x0ff);
m_dat_out = m_block_buf[m_blkidx++];
}
// else m_dat_out = 0x0ff; // So set already above
}
 
int result = (m_dat_out&0x80)?1:0;
m_dat_out <<= 1;
m_delay = 0;
m_last_miso = result;
fflush(stdout);
return result;
}
 
unsigned SDSPISIM::cmdcrc(int len, char *buf) const {
unsigned int fill = 0, taps = 0x12;
 
for(int i=0; i<len; i++) {
fill ^= buf[i];
for(int j=0; j<8; j++) {
if (fill&0x80)
fill = (fill<<1)^taps;
else
fill <<= 1;
}
}
 
fill &= 0x0fe; fill |= 1;
return fill;
}
 
bool SDSPISIM::check_cmdcrc(char *buf) const {
unsigned fill = cmdcrc(5, buf);
printf("SDSPI: CRC-CHECK, should have a CRC of %02x\n", fill);
return (fill == (buf[5]&0x0ff));
}
 
unsigned SDSPISIM::blockcrc(int len, char *buf) const {
unsigned int fill = 0, taps = 0x1021;
bool dbg = (len == 512);
 
for(int i=0; i<len; i++) {
if (dbg) { printf("BUF[%3d] = %02x\n", i, buf[i]&0x0ff); }
fill ^= ((buf[i]&0x0ff) << 8);
for(int j=0; j<8; j++) {
if (fill&0x8000)
fill = (fill<<1)^taps;
else
fill <<= 1;
}
}
 
fill &= 0x0ffff;
if (dbg) { printf("BLOCKCRC(%d,??) = %04x\n", len, fill); }
return fill;
}
 
void SDSPISIM::add_block_crc(int len, char *buf) const {
unsigned fill = blockcrc(len, &buf[1]);
 
buf[len+1] = (fill >> 8)&0x0ff;
buf[len+2] = (fill )&0x0ff;
}
 

powered by: WebSVN 2.1.0

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