litex/build/sim: add module for simulating SPD EEPROM
This commit is contained in:
parent
02072deab1
commit
a0ce4ce56b
|
@ -1,5 +1,5 @@
|
||||||
include ../variables.mak
|
include ../variables.mak
|
||||||
MODULES = xgmii_ethernet ethernet serial2console serial2tcp clocker
|
MODULES = xgmii_ethernet ethernet serial2console serial2tcp clocker spdeeprom
|
||||||
|
|
||||||
.PHONY: $(MODULES)
|
.PHONY: $(MODULES)
|
||||||
all: $(MODULES)
|
all: $(MODULES)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
include ../../variables.mak
|
||||||
|
include $(SRC_DIR)/modules/rules.mak
|
|
@ -0,0 +1,428 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "error.h"
|
||||||
|
#include "modules.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a simulation of SPD EEPROM I2C slave.
|
||||||
|
* It only supports basic read/write commands.
|
||||||
|
* Although it has been written with SPD EEPROM chips in mind, it should be
|
||||||
|
* compatible with some other EEPROM chips that use single byte addressing.
|
||||||
|
*
|
||||||
|
* Some details can be controlled using defines/environmental variables:
|
||||||
|
* #define SPD_EEPROM_ADDR 7bit address of I2C slave
|
||||||
|
* #define DEBUG_SPD_EEPROM print debug messages
|
||||||
|
* env SPD_EEPROM_FILE load memory contents from file
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SPD_EEPROM_ADDR 0b000
|
||||||
|
|
||||||
|
#ifdef DEBUG_SPD_EEPROM
|
||||||
|
#define DBG(...) do{ fprintf(stderr, __VA_ARGS__); } while(0)
|
||||||
|
#else
|
||||||
|
#define DBG(...) do{ } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// state of the serial-to-parallel FSM
|
||||||
|
enum SerialState {
|
||||||
|
IDLE,
|
||||||
|
WRITE, // slave writing a byte to master
|
||||||
|
READ, // slave reading a byte from master
|
||||||
|
RACK_0, // slave starts sending ACK
|
||||||
|
RACK_1, // slave finishes sending ACK
|
||||||
|
WACK, // slave reads ACK
|
||||||
|
};
|
||||||
|
|
||||||
|
// state of the transaction FSM
|
||||||
|
enum TransactionState {
|
||||||
|
DEV_ADDR, // reading slave device address
|
||||||
|
WRITE_ADDR, // master writes address
|
||||||
|
WRITE_DATA, // master writes data
|
||||||
|
READ_DATA, // master reads data
|
||||||
|
};
|
||||||
|
|
||||||
|
// module state
|
||||||
|
struct session_s {
|
||||||
|
// DUT pads (need separate SDA io/out as Verilator does not support tristate pins)
|
||||||
|
char *sys_clk;
|
||||||
|
char *sda_in;
|
||||||
|
char *sda_out;
|
||||||
|
char *scl;
|
||||||
|
// SPD EEPROM memory contents
|
||||||
|
unsigned char mem[256];
|
||||||
|
// state machine
|
||||||
|
enum TransactionState state_transaction;
|
||||||
|
enum SerialState state_serial;
|
||||||
|
unsigned int byte_in;
|
||||||
|
unsigned int byte_out;
|
||||||
|
unsigned int bit_counter;
|
||||||
|
unsigned int devaddr;
|
||||||
|
unsigned int addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Module interface
|
||||||
|
static int spdeeprom_start();
|
||||||
|
static int spdeeprom_new(void **sess, char *args);
|
||||||
|
static int spdeeprom_add_pads(void *sess, struct pad_list_s *plist);
|
||||||
|
static int spdeeprom_tick(void *sess);
|
||||||
|
// EEPROM simulation
|
||||||
|
static void fsm_tick(struct session_s *s);
|
||||||
|
static enum SerialState state_serial_next(struct session_s *s);
|
||||||
|
// Helper functions
|
||||||
|
static void spdeeprom_from_file(struct session_s *s, FILE *file);
|
||||||
|
static int litex_sim_module_pads_get(struct pad_s *pads, char *name, void **signal);
|
||||||
|
|
||||||
|
/*** Module interface *****************************************************************************/
|
||||||
|
|
||||||
|
static struct ext_module_s ext_mod = {
|
||||||
|
"spdeeprom",
|
||||||
|
spdeeprom_start,
|
||||||
|
spdeeprom_new,
|
||||||
|
spdeeprom_add_pads,
|
||||||
|
NULL,
|
||||||
|
spdeeprom_tick
|
||||||
|
};
|
||||||
|
|
||||||
|
int litex_sim_ext_module_init(int (*register_module)(struct ext_module_s *))
|
||||||
|
{
|
||||||
|
int ret = RC_OK;
|
||||||
|
ret = register_module(&ext_mod);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spdeeprom_start()
|
||||||
|
{
|
||||||
|
printf("[spdeeprom] loaded (addr = 0x%01x)\n", SPD_EEPROM_ADDR);
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spdeeprom_new(void **sess, char *args)
|
||||||
|
{
|
||||||
|
int ret=RC_OK;
|
||||||
|
int i;
|
||||||
|
char *spd_filename;
|
||||||
|
FILE *spd_file;
|
||||||
|
|
||||||
|
struct session_s *s=NULL;
|
||||||
|
|
||||||
|
if(!sess) {
|
||||||
|
ret = RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = (struct session_s*) malloc(sizeof(struct session_s));
|
||||||
|
if(!s) {
|
||||||
|
ret=RC_NOENMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memset(s, 0, sizeof(struct session_s));
|
||||||
|
|
||||||
|
spd_filename = getenv("SPD_EEPROM_FILE");
|
||||||
|
if (spd_filename != NULL) {
|
||||||
|
spd_file = fopen(spd_filename, "r");
|
||||||
|
}
|
||||||
|
if (spd_filename != NULL && spd_file != NULL) {
|
||||||
|
DBG("[spdeeprom] loading EEPROM contents from file: %s\n", spd_filename);
|
||||||
|
spdeeprom_from_file(s, spd_file);
|
||||||
|
fclose(spd_file);
|
||||||
|
} else { // fill in the memory with some data
|
||||||
|
for (i = 0; i < sizeof(s->mem) / sizeof(s->mem[0]); ++i) {
|
||||||
|
s->mem[i] = i & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
*sess = (void*) s;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spdeeprom_add_pads(void *sess, struct pad_list_s *plist)
|
||||||
|
{
|
||||||
|
int ret = RC_OK;
|
||||||
|
struct session_s *s = (struct session_s*) sess;
|
||||||
|
struct pad_s *pads;
|
||||||
|
|
||||||
|
if(!sess || !plist) {
|
||||||
|
ret = RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pads = plist->pads;
|
||||||
|
|
||||||
|
if(!strcmp(plist->name, "i2c")) {
|
||||||
|
litex_sim_module_pads_get(pads, "sda_in", (void**) &s->sda_in);
|
||||||
|
litex_sim_module_pads_get(pads, "sda_out", (void**) &s->sda_out);
|
||||||
|
litex_sim_module_pads_get(pads, "scl", (void**) &s->scl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strcmp(plist->name, "sys_clk"))
|
||||||
|
litex_sim_module_pads_get(pads, "sys_clk", (void**) &s->sys_clk);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spdeeprom_tick(void *sess)
|
||||||
|
{
|
||||||
|
struct session_s *s = (struct session_s*) sess;
|
||||||
|
|
||||||
|
if (s->sda_in == 0 || s->sda_out == 0 || s->scl == 0) {
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*s->sys_clk == 0) {
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
fsm_tick(s);
|
||||||
|
|
||||||
|
return RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** Simulation ***********************************************************************************/
|
||||||
|
|
||||||
|
#ifdef DEBUG_SPD_EEPROM
|
||||||
|
static inline const char *state_serial_str(enum SerialState s)
|
||||||
|
{
|
||||||
|
switch (s) {
|
||||||
|
case IDLE: return "IDLE";
|
||||||
|
case WRITE: return "WRITE";
|
||||||
|
case READ: return "READ";
|
||||||
|
case RACK_0: return "RACK_0";
|
||||||
|
case RACK_1: return "RACK_1";
|
||||||
|
case WACK: return "WACK";
|
||||||
|
default: return "_";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *state_transaction_str(enum TransactionState s)
|
||||||
|
{
|
||||||
|
switch (s) {
|
||||||
|
case DEV_ADDR: return "DEV_ADDR";
|
||||||
|
case WRITE_ADDR: return "WRITE_ADDR";
|
||||||
|
case WRITE_DATA: return "WRITE_DATA";
|
||||||
|
case READ_DATA: return "READ_DATA";
|
||||||
|
default: return "_";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void fsm_tick(struct session_s *s)
|
||||||
|
{
|
||||||
|
static int sda_last = 1;
|
||||||
|
static int scl_last = 1;
|
||||||
|
|
||||||
|
enum SerialState last_state_serial;
|
||||||
|
int sda_rising_edge;
|
||||||
|
int sda_falling_edge;
|
||||||
|
int start_cond;
|
||||||
|
int stop_cond;
|
||||||
|
int scl_rising;
|
||||||
|
int scl_falling;
|
||||||
|
|
||||||
|
sda_rising_edge = !sda_last && *s->sda_out;
|
||||||
|
sda_falling_edge = sda_last && !*s->sda_out;
|
||||||
|
start_cond = sda_falling_edge && *s->scl;
|
||||||
|
stop_cond = sda_rising_edge && *s->scl;
|
||||||
|
scl_rising = !scl_last && *s->scl;
|
||||||
|
scl_falling = scl_last && !*s->scl;
|
||||||
|
|
||||||
|
sda_last = *s->sda_out;
|
||||||
|
scl_last = *s->scl;
|
||||||
|
|
||||||
|
if (start_cond) {
|
||||||
|
DBG("[spdeeprom] START condition\n");
|
||||||
|
s->state_serial = READ;
|
||||||
|
s->state_transaction = DEV_ADDR;
|
||||||
|
s->bit_counter = 0;
|
||||||
|
}
|
||||||
|
if (stop_cond) {
|
||||||
|
DBG("[spdeeprom] STOP condition\n");
|
||||||
|
s->state_serial = IDLE;
|
||||||
|
s->state_transaction = DEV_ADDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_state_serial = s->state_serial;
|
||||||
|
|
||||||
|
switch (s->state_serial) {
|
||||||
|
case IDLE:
|
||||||
|
*s->sda_in = 1;
|
||||||
|
break;
|
||||||
|
case READ:
|
||||||
|
if (s->bit_counter == 0) {
|
||||||
|
s->byte_in = 0;
|
||||||
|
}
|
||||||
|
if (scl_rising) {
|
||||||
|
s->byte_in <<= 1;
|
||||||
|
s->byte_in |= *s->sda_out & 1;
|
||||||
|
s->bit_counter++;
|
||||||
|
}
|
||||||
|
if (s->bit_counter >= 8) {
|
||||||
|
s->bit_counter = 0;
|
||||||
|
s->state_serial = RACK_0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WRITE:
|
||||||
|
if (scl_rising) {
|
||||||
|
*s->sda_in = (s->byte_out & (1 << 7)) != 0;
|
||||||
|
s->byte_out <<= 1;
|
||||||
|
s->bit_counter++;
|
||||||
|
}
|
||||||
|
if (s->bit_counter >= 8) {
|
||||||
|
s->bit_counter = 0;
|
||||||
|
s->state_serial = WACK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RACK_0: // first falling edge
|
||||||
|
if (scl_falling) {
|
||||||
|
*s->sda_in = 0;
|
||||||
|
s->state_serial = RACK_1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RACK_1: // second falling edge
|
||||||
|
if (scl_falling) {
|
||||||
|
*s->sda_in = 1;
|
||||||
|
s->state_serial = state_serial_next(s);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WACK:
|
||||||
|
if (scl_rising) {
|
||||||
|
if ((*s->sda_out) != 0) {
|
||||||
|
DBG("[spdeeprom] No ACK from master!\n");
|
||||||
|
}
|
||||||
|
s->state_serial = state_serial_next(s);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: DBG("[spdeeprom] unknown state_serial\n"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->state_serial != last_state_serial) {
|
||||||
|
DBG("[spdeeprom] state_serial: %s -> %s\n",
|
||||||
|
state_serial_str(last_state_serial), state_serial_str(s->state_serial));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum SerialState state_serial_next(struct session_s *s)
|
||||||
|
{
|
||||||
|
enum TransactionState state_transaction_last = s->state_transaction;
|
||||||
|
enum SerialState state_serial = IDLE;
|
||||||
|
|
||||||
|
switch (s->state_transaction) {
|
||||||
|
case DEV_ADDR:
|
||||||
|
if (s->state_serial != RACK_1) {
|
||||||
|
DBG("[spdeeprom] ERROR: DEV_ADDR during WACK\n");
|
||||||
|
}
|
||||||
|
s->devaddr = s->byte_in;
|
||||||
|
if (((s->devaddr & 0b1110) >> 1) != SPD_EEPROM_ADDR) {
|
||||||
|
DBG("[spdeeprom] ERROR: read wrong address\n");
|
||||||
|
state_serial = IDLE;
|
||||||
|
} else {
|
||||||
|
DBG("[spdeeprom] devaddr = 0x%02x\n", s->devaddr);
|
||||||
|
if ((s->devaddr & 1) != 0) { // read command
|
||||||
|
DBG("[spdeeprom] registered READ cmd\n");
|
||||||
|
s->state_transaction = READ_DATA;
|
||||||
|
s->byte_out = s->mem[s->addr++];
|
||||||
|
s->addr %= sizeof(s->mem);
|
||||||
|
state_serial = WRITE;
|
||||||
|
} else { // write command
|
||||||
|
DBG("[spdeeprom] registered WRITE cmd\n");
|
||||||
|
s->state_transaction = WRITE_ADDR;
|
||||||
|
state_serial = READ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WRITE_ADDR:
|
||||||
|
if (s->state_serial != RACK_1) {
|
||||||
|
DBG("[spdeeprom] ERROR: WRITE_ADDR during WACK\n");
|
||||||
|
}
|
||||||
|
s->addr = s->byte_in;
|
||||||
|
s->state_transaction = WRITE_DATA;
|
||||||
|
DBG("[spdeeprom] addr = 0x%02x\n", s->addr);
|
||||||
|
state_serial = READ;
|
||||||
|
break;
|
||||||
|
case WRITE_DATA:
|
||||||
|
if (s->state_serial != RACK_1) {
|
||||||
|
DBG("[spdeeprom] ERROR: WRITE_DATA during WACK\n");
|
||||||
|
}
|
||||||
|
s->mem[s->addr++] = s->byte_in;
|
||||||
|
s->addr %= sizeof(s->mem);
|
||||||
|
s->state_transaction = WRITE_DATA;
|
||||||
|
DBG("[spdeeprom] wdata = 0x%02x\n", s->byte_in);
|
||||||
|
state_serial = READ;
|
||||||
|
break;
|
||||||
|
case READ_DATA:
|
||||||
|
if (s->state_serial != WACK) {
|
||||||
|
DBG("[spdeeprom] ERROR: READ_DATA during RACK\n");
|
||||||
|
}
|
||||||
|
s->state_transaction = READ_DATA;
|
||||||
|
s->byte_out = s->mem[s->addr++];
|
||||||
|
DBG("[spdeeprom] rdata = 0x%02x\n", s->byte_out);
|
||||||
|
state_serial = WRITE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG("[spdeeprom] ERROR: wrong state_transaction!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_serial == IDLE) {
|
||||||
|
DBG("[spdeeprom] ERROR: unhandled state_serial_next\n");
|
||||||
|
}
|
||||||
|
if (state_transaction_last != s->state_transaction) {
|
||||||
|
DBG("[spdeeprom] state_transaction: %s -> %s\n", state_transaction_str(state_transaction_last), state_transaction_str(s->state_transaction));
|
||||||
|
}
|
||||||
|
return state_serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** Helper functions *****************************************************************************/
|
||||||
|
|
||||||
|
static void spdeeprom_from_file(struct session_s *s, FILE *file)
|
||||||
|
{
|
||||||
|
size_t bufsize = 0;
|
||||||
|
ssize_t n_read;
|
||||||
|
char *line = NULL;
|
||||||
|
char *c;
|
||||||
|
unsigned int byte;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(s->mem) / sizeof(s->mem[0]); ++i) {
|
||||||
|
if ((n_read = getline(&line, &bufsize, file)) < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
byte = strtoul(line, &c, 0);
|
||||||
|
if (c == line) {
|
||||||
|
DBG("[spdeeprom] Incorrect value at line %d\n", i);
|
||||||
|
} else {
|
||||||
|
s->mem[i] = byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line != NULL)
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int litex_sim_module_pads_get(struct pad_s *pads, char *name, void **signal)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
void *sig=NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(!pads || !name || !signal) {
|
||||||
|
ret = RC_INVARG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while(pads[i].name) {
|
||||||
|
if(!strcmp(pads[i].name, name))
|
||||||
|
{
|
||||||
|
sig = (void*) pads[i].signal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
*signal = sig;
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -30,8 +30,9 @@ class I2CMaster(Module, AutoCSR):
|
||||||
CSRField("sda", size=1, offset=0)],
|
CSRField("sda", size=1, offset=0)],
|
||||||
name="r")
|
name="r")
|
||||||
|
|
||||||
# # #
|
self.connect(pads)
|
||||||
|
|
||||||
|
def connect(self, pads):
|
||||||
_sda_w = Signal()
|
_sda_w = Signal()
|
||||||
_sda_oe = Signal()
|
_sda_oe = Signal()
|
||||||
_sda_r = Signal()
|
_sda_r = Signal()
|
||||||
|
@ -44,6 +45,32 @@ class I2CMaster(Module, AutoCSR):
|
||||||
self.specials += Tristate(pads.sda, _sda_w, _sda_oe, _sda_r)
|
self.specials += Tristate(pads.sda, _sda_w, _sda_oe, _sda_r)
|
||||||
|
|
||||||
|
|
||||||
|
class I2CMasterSim(I2CMaster):
|
||||||
|
"""I2C Master Bit-Banging for Verilator simulation
|
||||||
|
|
||||||
|
Uses separate pads for SDA IN/OUT as Verilator does not support tristate pins well.
|
||||||
|
"""
|
||||||
|
pads_layout = [("scl", 1), ("sda_in", 1), ("sda_out", 1)]
|
||||||
|
|
||||||
|
def connect(self, pads):
|
||||||
|
_sda_w = Signal()
|
||||||
|
_sda_oe = Signal()
|
||||||
|
_sda_r = Signal()
|
||||||
|
_sda_in = Signal()
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
pads.scl.eq(self._w.fields.scl),
|
||||||
|
_sda_oe.eq( self._w.fields.oe),
|
||||||
|
_sda_w.eq( self._w.fields.sda),
|
||||||
|
If(_sda_oe,
|
||||||
|
pads.sda_out.eq(_sda_w),
|
||||||
|
self._r.fields.sda.eq(_sda_w),
|
||||||
|
).Else(
|
||||||
|
pads.sda_out.eq(1),
|
||||||
|
self._r.fields.sda.eq(pads.sda_in),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
# SPI Master Bit-Banging ---------------------------------------------------------------------------
|
# SPI Master Bit-Banging ---------------------------------------------------------------------------
|
||||||
|
|
||||||
class SPIMaster(Module, AutoCSR):
|
class SPIMaster(Module, AutoCSR):
|
||||||
|
|
|
@ -18,6 +18,7 @@ from litex.soc.integration.soc_core import *
|
||||||
from litex.soc.integration.soc_sdram import *
|
from litex.soc.integration.soc_sdram import *
|
||||||
from litex.soc.integration.builder import *
|
from litex.soc.integration.builder import *
|
||||||
from litex.soc.integration.soc import *
|
from litex.soc.integration.soc import *
|
||||||
|
from litex.soc.cores.bitbang import *
|
||||||
|
|
||||||
from litedram import modules as litedram_modules
|
from litedram import modules as litedram_modules
|
||||||
from litedram.modules import parse_spd_hexdump
|
from litedram.modules import parse_spd_hexdump
|
||||||
|
@ -63,6 +64,11 @@ _io = [
|
||||||
Subsignal("sink_ready", Pins(1)),
|
Subsignal("sink_ready", Pins(1)),
|
||||||
Subsignal("sink_data", Pins(8)),
|
Subsignal("sink_data", Pins(8)),
|
||||||
),
|
),
|
||||||
|
("i2c", 0,
|
||||||
|
Subsignal("scl", Pins(1)),
|
||||||
|
Subsignal("sda_out", Pins(1)),
|
||||||
|
Subsignal("sda_in", Pins(1)),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Platform -----------------------------------------------------------------------------------------
|
# Platform -----------------------------------------------------------------------------------------
|
||||||
|
@ -170,6 +176,7 @@ class SimSoC(SoCCore):
|
||||||
sdram_data_width = 32,
|
sdram_data_width = 32,
|
||||||
sdram_spd_data = None,
|
sdram_spd_data = None,
|
||||||
sdram_verbosity = 0,
|
sdram_verbosity = 0,
|
||||||
|
with_i2c = False,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
platform = Platform()
|
platform = Platform()
|
||||||
sys_clk_freq = int(1e6)
|
sys_clk_freq = int(1e6)
|
||||||
|
@ -293,6 +300,12 @@ class SimSoC(SoCCore):
|
||||||
csr_csv = "analyzer.csv")
|
csr_csv = "analyzer.csv")
|
||||||
self.add_csr("analyzer")
|
self.add_csr("analyzer")
|
||||||
|
|
||||||
|
# I2C --------------------------------------------------------------------------------------
|
||||||
|
if with_i2c:
|
||||||
|
pads = platform.request("i2c", 0)
|
||||||
|
self.submodules.i2c = I2CMasterSim(pads)
|
||||||
|
self.add_csr("i2c")
|
||||||
|
|
||||||
# Build --------------------------------------------------------------------------------------------
|
# Build --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -313,6 +326,7 @@ def main():
|
||||||
parser.add_argument("--local-ip", default="192.168.1.50", help="Local IP address of SoC (default=192.168.1.50)")
|
parser.add_argument("--local-ip", default="192.168.1.50", help="Local IP address of SoC (default=192.168.1.50)")
|
||||||
parser.add_argument("--remote-ip", default="192.168.1.100", help="Remote IP address of TFTP server (default=192.168.1.100)")
|
parser.add_argument("--remote-ip", default="192.168.1.100", help="Remote IP address of TFTP server (default=192.168.1.100)")
|
||||||
parser.add_argument("--with-analyzer", action="store_true", help="Enable Analyzer support")
|
parser.add_argument("--with-analyzer", action="store_true", help="Enable Analyzer support")
|
||||||
|
parser.add_argument("--with-i2c", action="store_true", help="Enable I2C support")
|
||||||
parser.add_argument("--trace", action="store_true", help="Enable Tracing")
|
parser.add_argument("--trace", action="store_true", help="Enable Tracing")
|
||||||
parser.add_argument("--trace-fst", action="store_true", help="Enable FST tracing (default=VCD)")
|
parser.add_argument("--trace-fst", action="store_true", help="Enable FST tracing (default=VCD)")
|
||||||
parser.add_argument("--trace-start", default=0, help="Cycle to start tracing")
|
parser.add_argument("--trace-start", default=0, help="Cycle to start tracing")
|
||||||
|
@ -352,12 +366,16 @@ def main():
|
||||||
if args.with_ethernet or args.with_etherbone:
|
if args.with_ethernet or args.with_etherbone:
|
||||||
sim_config.add_module("ethernet", "eth", args={"interface": "tap0", "ip": args.remote_ip})
|
sim_config.add_module("ethernet", "eth", args={"interface": "tap0", "ip": args.remote_ip})
|
||||||
|
|
||||||
|
if args.with_i2c:
|
||||||
|
sim_config.add_module("spdeeprom", "i2c")
|
||||||
|
|
||||||
# SoC ------------------------------------------------------------------------------------------
|
# SoC ------------------------------------------------------------------------------------------
|
||||||
soc = SimSoC(
|
soc = SimSoC(
|
||||||
with_sdram = args.with_sdram,
|
with_sdram = args.with_sdram,
|
||||||
with_ethernet = args.with_ethernet,
|
with_ethernet = args.with_ethernet,
|
||||||
with_etherbone = args.with_etherbone,
|
with_etherbone = args.with_etherbone,
|
||||||
with_analyzer = args.with_analyzer,
|
with_analyzer = args.with_analyzer,
|
||||||
|
with_i2c = args.with_i2c,
|
||||||
sdram_init = [] if args.sdram_init is None else get_mem_data(args.sdram_init, cpu_endianness),
|
sdram_init = [] if args.sdram_init is None else get_mem_data(args.sdram_init, cpu_endianness),
|
||||||
**soc_kwargs)
|
**soc_kwargs)
|
||||||
if args.ram_init is not None:
|
if args.ram_init is not None:
|
||||||
|
|
Loading…
Reference in New Issue