Added entire system incl. terminal and MCP3008 ADC connected via SPI

This commit is contained in:
Eyck Jentzsch 2018-07-23 22:15:38 +02:00
parent a899d30556
commit 100822810f
18 changed files with 423 additions and 50 deletions

View File

@ -0,0 +1,47 @@
/*
* mcp3008.h
*
* Created on: 17.07.2018
* Author: eyck
*/
#ifndef RISCV_SC_INCL_SYSC_GENERAL_MCP3008_H_
#define RISCV_SC_INCL_SYSC_GENERAL_MCP3008_H_
#include "scc/signal_target_mixin.h"
#include "scc/signal_initiator_mixin.h"
#include "sysc/tlm_extensions.h"
#include <tlm/tlm_signal.h>
#include "cci_configuration"
#include <sysc/utils/sc_vector.h>
#include <sysc/kernel/sc_module.h>
namespace sysc {
class mcp3008: public sc_core::sc_module {
public:
SC_HAS_PROCESS(mcp3008);
scc::tlm_signal_logic_in sck_i;
scc::tlm_signal_logic_out miso_o;
scc::tlm_signal_logic_in mosi_i;
scc::tlm_signal_logic_in cs_i;
sc_core::sc_in<double> vref_i;
sc_core::sc_vector<sc_core::sc_in<double>> ch_i;
mcp3008(sc_core::sc_module_name nm);
virtual ~mcp3008();
private:
tlm::tlm_sync_enum receive(tlm::tlm_signal_gp<sc_dt::sc_logic> &, tlm::tlm_phase &, sc_core::sc_time &);
void do_conversion();
unsigned idx, rx_bits;
std::array<uint8_t, 3> rx_bytes, tx_bytes;
sc_dt::sc_logic mosi_v, miso_v, cs_v;
sysc::tlm_signal_spi_extension* ext, tx_ext;
sc_core::sc_time last_tx_start;
};
} /* namespace sysc */
#endif /* RISCV_SC_INCL_SYSC_GENERAL_MCP3008_H_ */

View File

@ -10,6 +10,7 @@
#include "sysc/SiFive/platform.h" #include "sysc/SiFive/platform.h"
#include "sysc/General/terminal.h" #include "sysc/General/terminal.h"
#include "sysc/General/mcp3008.h"
#include <systemc> #include <systemc>
namespace sysc { namespace sysc {
@ -24,8 +25,11 @@ public:
private: private:
sc_core::sc_vector<tlm::tlm_signal<sc_dt::sc_logic>> s_gpio; sc_core::sc_vector<tlm::tlm_signal<sc_dt::sc_logic>> s_gpio;
sc_core::sc_signal<bool> s_rst_n; sc_core::sc_signal<bool> s_rst_n;
sc_core::sc_signal<double> s_vref;
sc_core::sc_vector<sc_core::sc_signal<double>> s_ana;
sysc::platform i_platform; sysc::platform i_platform;
sysc::terminal i_terminal; sysc::terminal i_terminal;
sysc::mcp3008 i_adc;
void gen_por(); void gen_por();
}; };

View File

@ -32,8 +32,10 @@ public:
cci::cci_param<bool> write_to_ws; cci::cci_param<bool> write_to_ws;
protected: protected:
std::vector<uint8_t> queue; void before_end_of_elaboration();
void receive(tlm::tlm_signal_gp<sc_dt::sc_logic>& gp, sc_core::sc_time& delay); void receive(tlm::tlm_signal_gp<sc_dt::sc_logic>& gp, sc_core::sc_time& delay);
std::vector<uint8_t> queue;
std::shared_ptr<sysc::WsHandler> handler; std::shared_ptr<sysc::WsHandler> handler;
sc_core::sc_time last_tx_start=sc_core::SC_ZERO_TIME; sc_core::sc_time last_tx_start=sc_core::SC_ZERO_TIME;
}; };

View File

@ -83,7 +83,7 @@ protected:
private: private:
tlm::tlm_phase write_output(tlm::tlm_signal_gp<sc_dt::sc_logic>& gp, size_t i, sc_dt::sc_logic val); tlm::tlm_phase write_output(tlm::tlm_signal_gp<sc_dt::sc_logic>& gp, size_t i, sc_dt::sc_logic val);
void enable_outputs(uint32_t new_data); void enable_outputs(uint32_t new_iof_en, uint32_t new_iof_sel);
}; };
} /* namespace sysc */ } /* namespace sysc */

View File

@ -38,6 +38,11 @@
#define _SPI_H_ #define _SPI_H_
#include "scc/tlm_target.h" #include "scc/tlm_target.h"
#include "scc/signal_target_mixin.h"
#include "scc/signal_initiator_mixin.h"
#include <tlm/tlm_signal.h>
#include "cci_configuration"
#include <sysc/utils/sc_vector.h>
namespace sysc { namespace sysc {
@ -47,15 +52,28 @@ class spi : public sc_core::sc_module, public scc::tlm_target<> {
public: public:
SC_HAS_PROCESS(spi); SC_HAS_PROCESS(spi);
sc_core::sc_in<sc_core::sc_time> clk_i; sc_core::sc_in<sc_core::sc_time> clk_i;
sc_core::sc_in<bool> rst_i; sc_core::sc_in<bool> rst_i;
scc::tlm_signal_bool_opt_out sck_o;
scc::tlm_signal_bool_opt_out mosi_o;
scc::tlm_signal_bool_opt_in miso_i;
sc_core::sc_vector<scc::tlm_signal_bool_opt_out> scs_o;
sc_core::sc_out<bool> irq_o;
cci::cci_param<bool> bit_true_transfer;
spi(sc_core::sc_module_name nm); spi(sc_core::sc_module_name nm);
virtual ~spi() override; virtual ~spi() override;
protected: protected:
void clock_cb(); void clock_cb();
void reset_cb(); void reset_cb();
void transmit_data();
void receive_data(tlm::tlm_signal_gp<>& gp, sc_core::sc_time& delay);
void update_irq();
sc_core::sc_time clk; sc_core::sc_time clk;
std::unique_ptr<spi_regs> regs; std::unique_ptr<spi_regs> regs;
sc_core::sc_fifo<uint8_t> rx_fifo, tx_fifo;
}; };
} /* namespace sysc */ } /* namespace sysc */

View File

@ -58,7 +58,7 @@ public:
sc_core::sc_out<bool> irq_o; sc_core::sc_out<bool> irq_o;
cci::cci_param<bool> write_to_ws; cci::cci_param<bool> bit_true_transfer;
uart(sc_core::sc_module_name nm); uart(sc_core::sc_module_name nm);
virtual ~uart() override; virtual ~uart() override;
@ -69,13 +69,9 @@ protected:
void transmit_data(); void transmit_data();
void receive_data(tlm::tlm_signal_gp<>& gp, sc_core::sc_time& delay); void receive_data(tlm::tlm_signal_gp<>& gp, sc_core::sc_time& delay);
void update_irq(); void update_irq();
void before_end_of_elaboration(); sc_core::sc_time clk{SC_ZERO_TIME},rx_last_start{SC_ZERO_TIME};
sc_core::sc_time clk;
std::unique_ptr<uart_regs> regs; std::unique_ptr<uart_regs> regs;
sc_core::sc_fifo<uint8_t> rx_fifo, tx_fifo; sc_core::sc_fifo<uint8_t> rx_fifo, tx_fifo;
std::vector<uint8_t> queue;
sysc::tlm_signal_uart_extension *rx_ext, *tx_ext;
std::shared_ptr<sysc::WsHandler> handler;
}; };
} /* namespace sysc */ } /* namespace sysc */

View File

@ -24,6 +24,23 @@ struct tlm_signal_uart_extension : public tlm::tlm_unmanaged_extension<tlm_signa
}; };
struct tlm_signal_spi_extension : public tlm::tlm_unmanaged_extension<tlm_signal_spi_extension> {
struct spi_tx {
unsigned data_bits:5;
bool msb_first:1;
bool s2m_data_valid:1;
unsigned m2s_data, s2m_data;
} tx;
sc_core::sc_time start_time;
void copy_from(tlm_extension_base const & other) override {
auto& o = static_cast<const type&>(other);
this->tx=o.tx;
this->start_time=o.start_time;
}
};
} }

View File

@ -122,11 +122,6 @@ int sc_main(int argc, char *argv[]) {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
iss::init_jit(argc, argv); iss::init_jit(argc, argv);
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// set up tracing & transaction recording
///////////////////////////////////////////////////////////////////////////
auto trace_val = vm["trace"].as<unsigned>();
scc::tracer trace("simple_system", static_cast<scc::tracer::file_type>(trace_val >> 1), trace_val != 0);
///////////////////////////////////////////////////////////////////////////
// set up configuration // set up configuration
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
scc::configurer cfg(vm["config-file"].as<std::string>()); scc::configurer cfg(vm["config-file"].as<std::string>());
@ -134,16 +129,24 @@ int sc_main(int argc, char *argv[]) {
// instantiate top level // instantiate top level
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
sysc::system i_system("i_system"); sysc::system i_system("i_system");
// sr_report_handler::add_sc_object_to_filter(&i_simple_system.i_master, ///////////////////////////////////////////////////////////////////////////
// sc_core::SC_WARNING, sc_core::SC_MEDIUM); // set up tracing & transaction recording
///////////////////////////////////////////////////////////////////////////
auto trace_val = vm["trace"].as<unsigned>();
scc::tracer trace("simple_system", static_cast<scc::tracer::file_type>(trace_val >> 1), trace_val != 0);
///////////////////////////////////////////////////////////////////////////
// dump configuration if requested
///////////////////////////////////////////////////////////////////////////
if(vm["dump-config"].as<std::string>().size()>0){ if(vm["dump-config"].as<std::string>().size()>0){
std::ofstream of{vm["dump-config"].as<std::string>()}; std::ofstream of{vm["dump-config"].as<std::string>()};
if(of.is_open()) if(of.is_open())
cfg.dump_configuration(of); cfg.dump_configuration(of);
} }
cfg.configure(); cfg.configure();
// overwrite with command line settings ///////////////////////////////////////////////////////////////////////////
if (vm["gdb-port"].as<unsigned short>()) // overwrite config with command line settings
///////////////////////////////////////////////////////////////////////////
if (vm["gdb-port"].as<unsigned short>())
cfg.set_value("i_system.i_platform.i_core_complex.gdb_server_port", vm["gdb-port"].as<unsigned short>()); cfg.set_value("i_system.i_platform.i_core_complex.gdb_server_port", vm["gdb-port"].as<unsigned short>());
if (vm.count("dump-ir")) if (vm.count("dump-ir"))
cfg.set_value("i_system.i_platform.i_core_complex.dump_ir", vm.count("dump-ir") != 0); cfg.set_value("i_system.i_platform.i_core_complex.dump_ir", vm.count("dump-ir") != 0);

View File

@ -218,7 +218,7 @@ core_complex::core_complex(sc_core::sc_module_name name)
, NAMED(timer_irq_i) , NAMED(timer_irq_i)
, NAMED(local_irq_i, 16) , NAMED(local_irq_i, 16)
, NAMED(elf_file, "") , NAMED(elf_file, "")
, NAMED(enable_disass, true) , NAMED(enable_disass, false)
, NAMED(reset_address, 0ULL) , NAMED(reset_address, 0ULL)
, NAMED(gdb_server_port, 0) , NAMED(gdb_server_port, 0)
, NAMED(dump_ir, false) , NAMED(dump_ir, false)
@ -264,7 +264,11 @@ void core_complex::trace(sc_core::sc_trace_file *trf) {}
void core_complex::before_end_of_elaboration() { void core_complex::before_end_of_elaboration() {
cpu = make_unique<core_wrapper>(this); cpu = make_unique<core_wrapper>(this);
vm = create<arch::rv32imac>(cpu.get(), gdb_server_port.get_value(), dump_ir.get_value()); vm = create<arch::rv32imac>(cpu.get(), gdb_server_port.get_value(), dump_ir.get_value());
#ifdef WITH_SCV
vm->setDisassEnabled(enable_disass.get_value() || m_db!=nullptr);
#else
vm->setDisassEnabled(enable_disass.get_value()); vm->setDisassEnabled(enable_disass.get_value());
#endif
auto* srv = debugger::server<debugger::gdb_session>::get(); auto* srv = debugger::server<debugger::gdb_session>::get();
if(srv) tgt_adapter = srv->get_target(); if(srv) tgt_adapter = srv->get_target();
if(tgt_adapter) if(tgt_adapter)

View File

@ -103,7 +103,14 @@ gpio::gpio(sc_core::sc_module_name nm)
}); });
regs->iof_en.set_write_cb([this](scc::sc_register<uint32_t> &reg, uint32_t data) -> bool { regs->iof_en.set_write_cb([this](scc::sc_register<uint32_t> &reg, uint32_t data) -> bool {
if (!this->regs->in_reset()) { if (!this->regs->in_reset()) {
enable_outputs(data); enable_outputs(data, regs->r_iof_sel);
reg.put(data);
}
return true;
});
regs->iof_sel.set_write_cb([this](scc::sc_register<uint32_t> &reg, uint32_t data) -> bool {
if (!this->regs->in_reset()) {
enable_outputs(regs->r_iof_en, data);
reg.put(data); reg.put(data);
} }
return true; return true;
@ -157,12 +164,12 @@ void gpio::update_pins() {
} }
} }
void gpio::enable_outputs(uint32_t new_data) { void gpio::enable_outputs(uint32_t new_iof_en, uint32_t new_iof_sel) {
auto changed_bits = regs->r_iof_en^new_data; auto changed_bits = (regs->r_iof_en^new_iof_en) | (regs->r_iof_sel^new_iof_sel);
tlm::tlm_signal_gp<sc_dt::sc_logic> gp; tlm::tlm_signal_gp<sc_dt::sc_logic> gp;
for(size_t i=0, mask=1; i<32; ++i, mask<<=1){ for(size_t i=0, mask=1; i<32; ++i, mask<<=1){
if(changed_bits&mask){ if(changed_bits&mask){
if(new_data&mask){ if(new_iof_en&mask){
if((regs->r_iof_sel&mask)==0 && iof0_i[i].size()>0){ if((regs->r_iof_sel&mask)==0 && iof0_i[i].size()>0){
tlm::tlm_phase phase = write_output(gp, i, last_iof0[i]?sc_dt::Log_1:sc_dt::Log_0); tlm::tlm_phase phase = write_output(gp, i, last_iof0[i]?sc_dt::Log_1:sc_dt::Log_0);
} else if((regs->r_iof_sel&mask)==1 && iof1_i[i].size()>0) } else if((regs->r_iof_sel&mask)==1 && iof1_i[i].size()>0)
@ -230,6 +237,7 @@ void gpio::iof_input(unsigned int tag, unsigned iof_idx, tlm::tlm_signal_gp<>& g
new_gp.set_value(val?sc_dt::Log_1:sc_dt::Log_0); new_gp.set_value(val?sc_dt::Log_1:sc_dt::Log_0);
new_gp.copy_extensions_from(gp); new_gp.copy_extensions_from(gp);
socket->nb_transport_fw(new_gp, phase, delay); // we don't care about phase and sync enum socket->nb_transport_fw(new_gp, phase, delay); // we don't care about phase and sync enum
gp.update_extensions_from(new_gp);
} }
} }
} }

View File

@ -0,0 +1,85 @@
/*
* mcp3008.cpp
*
* Created on: 17.07.2018
* Author: eyck
*/
#include "sysc/General/mcp3008.h"
#include <scc/report.h>
#include <util/ities.h>
namespace sysc {
mcp3008::mcp3008(sc_core::sc_module_name nm)
: sc_core::sc_module(nm)
, NAMED(sck_i)
, NAMED(miso_o)
, NAMED(mosi_i)
, NAMED(cs_i)
, NAMED(vref_i)
, NAMED(ch_i, 8)
, last_tx_start(sc_core::SC_ZERO_TIME)
{
sck_i.register_nb_transport([this](tlm::tlm_signal_gp<sc_dt::sc_logic>& gp, tlm::tlm_phase& phase, sc_core::sc_time& delay)
-> tlm::tlm_sync_enum{
return tlm::TLM_COMPLETED;
});
mosi_i.register_nb_transport([this](tlm::tlm_signal_gp<sc_dt::sc_logic>& gp, tlm::tlm_phase& phase, sc_core::sc_time& delay)
-> tlm::tlm_sync_enum{
if(cs_v==sc_dt::Log_0)
return receive(gp, phase, delay);
});
cs_i.register_nb_transport([this](tlm::tlm_signal_gp<sc_dt::sc_logic>& gp, tlm::tlm_phase& phase, sc_core::sc_time& delay)
-> tlm::tlm_sync_enum{
if(cs_v!=sc_dt::Log_0 && gp.get_value()==sc_dt::Log_0){
idx=0; // falling edge
rx_bits=0;
}
cs_v=gp.get_value();
return tlm::TLM_COMPLETED;
});
}
mcp3008::~mcp3008() {
}
tlm::tlm_sync_enum mcp3008::receive(tlm::tlm_signal_gp<sc_dt::sc_logic>& gp, tlm::tlm_phase& phase, sc_core::sc_time& delay) {
gp.get_extension(ext);
if(ext){
if( ext->start_time!=last_tx_start){
assert(ext->tx.data_bits==8);
rx_bytes[idx]=bit_sub<0,8>(ext->tx.m2s_data);
if(idx==1)
do_conversion();
ext->tx.s2m_data=tx_bytes[idx];
ext->tx.s2m_data_valid=true;
idx++;
last_tx_start=ext->start_time;
}
}
return tlm::TLM_COMPLETED;
}
void mcp3008::do_conversion() {
if(rx_bytes[0]==0x1){
auto mode = bit_sub<7,1>(rx_bytes[1]);
auto channel = bit_sub<4,3>(rx_bytes[1]);
auto vref=vref_i.read();
if(mode){ // single ended
auto inp = ch_i[channel].read();
auto norm = inp/vref*1024.0;
auto res = static_cast<int>(norm);
CLOG(DEBUG, SystemC)<<"Converting "<<inp<<" to "<<norm<<" as int "<<res;
tx_bytes[1]=bit_sub<8,2>(res);
tx_bytes[2]=bit_sub<0,8>(res);
} else {
tx_bytes[1]=0;
tx_bytes[2]=0;
}
}
}
} /* namespace sysc */

View File

@ -124,9 +124,20 @@ platform::platform(sc_core::sc_module_name nm)
i_uart0.rx_i(i_gpio0.iof0_o[16]); i_uart0.rx_i(i_gpio0.iof0_o[16]);
i_uart0.irq_o(s_global_int[3]); i_uart0.irq_o(s_global_int[3]);
i_gpio0.iof0_i[2](i_qspi1.scs_o[0]);
i_gpio0.iof0_i[3](i_qspi1.mosi_o);
i_qspi1.miso_i(i_gpio0.iof0_o[4]);
i_gpio0.iof0_i[5](i_qspi1.sck_o);
i_gpio0.iof0_i[9](i_qspi1.scs_o[2]);
i_gpio0.iof0_i[10](i_qspi1.scs_o[3]);
i_qspi0.irq_o(s_global_int[5]);
i_qspi1.irq_o(s_global_int[6]);
i_qspi2.irq_o(s_global_int[7]);
s_dummy_sck_i[0](i_uart1.tx_o); s_dummy_sck_i[0](i_uart1.tx_o);
i_uart1.rx_i(s_dummy_sck_o[0]); i_uart1.rx_i(s_dummy_sck_o[0]);
i_uart1.irq_o(s_dummy[0]); i_uart1.irq_o(s_global_int[4]);
for(auto& sock:s_dummy_sck_i) sock.error_if_no_callback=false; for(auto& sock:s_dummy_sck_i) sock.error_if_no_callback=false;
} }

View File

@ -167,7 +167,7 @@ void plic::handle_pending_int() {
void plic::reset_pending_int(uint32_t irq) { void plic::reset_pending_int(uint32_t irq) {
// todo: evaluate enable register (see spec) // todo: evaluate enable register (see spec)
// todo: make sure that pending is set, otherwise don't reset irq ... read spec. // todo: make sure that pending is set, otherwise don't reset irq ... read spec.
LOG(INFO) << "reset pending interrupt: " << irq; LOG(TRACE) << "reset pending interrupt: " << irq;
// reset related pending bit // reset related pending bit
auto reg_idx = irq>>5; auto reg_idx = irq>>5;
auto bit_ofs = irq & 0x1F; auto bit_ofs = irq & 0x1F;

View File

@ -36,8 +36,10 @@
#include "sysc/SiFive/spi.h" #include "sysc/SiFive/spi.h"
#include "sysc/tlm_extensions.h"
#include "scc/utilities.h" #include "scc/utilities.h"
#include "sysc/SiFive/gen/spi_regs.h" #include "sysc/SiFive/gen/spi_regs.h"
#include <util/ities.h>
namespace sysc { namespace sysc {
@ -46,6 +48,12 @@ spi::spi(sc_core::sc_module_name nm)
, tlm_target<>(clk) , tlm_target<>(clk)
, NAMED(clk_i) , NAMED(clk_i)
, NAMED(rst_i) , NAMED(rst_i)
, NAMED(sck_o)
, NAMED(mosi_o)
, NAMED(miso_i)
, NAMED(scs_o, 4)
, NAMED(irq_o)
, NAMED(bit_true_transfer, false)
, NAMEDD(spi_regs, regs) { , NAMEDD(spi_regs, regs) {
regs->registerResources(*this); regs->registerResources(*this);
SC_METHOD(clock_cb); SC_METHOD(clock_cb);
@ -53,6 +61,80 @@ spi::spi(sc_core::sc_module_name nm)
SC_METHOD(reset_cb); SC_METHOD(reset_cb);
sensitive << rst_i; sensitive << rst_i;
dont_initialize(); dont_initialize();
SC_THREAD(transmit_data);
miso_i.register_nb_transport([this](tlm::tlm_signal_gp<bool>& gp,
tlm::tlm_phase& phase, sc_core::sc_time& delay)->tlm::tlm_sync_enum{
this->receive_data(gp, delay);
return tlm::TLM_COMPLETED;
});
regs->txdata.set_write_cb([this](scc::sc_register<uint32_t> &reg, uint32_t data) -> bool {
if (!this->regs->in_reset()) {
reg.put(data);
tx_fifo.nb_write(static_cast<uint8_t>(regs->r_txdata.data));
regs->r_txdata.full=tx_fifo.num_free()==0;
update_irq();
}
return true;
});
regs->rxdata.set_read_cb([this](const scc::sc_register<uint32_t> &reg, uint32_t& data) -> bool {
if (!this->regs->in_reset()) {
uint8_t val;
if(rx_fifo.nb_read(val)){
regs->r_rxdata.empty=0;
regs->r_rxdata.data=val;
if(regs->r_rxmark.rxmark<=rx_fifo.num_available()){
regs->r_ip.rxwm=1;
update_irq();
}
} else
regs->r_rxdata.empty=1;
data = reg.get()&reg.rdmask;
}
return true;
});
regs->csmode.set_write_cb([this](const scc::sc_register<uint32_t> &reg, uint32_t& data) -> bool {
if(regs->r_csmode.mode==2 && regs->r_csmode.mode != bit_sub<0, 2>(data) && regs->r_csid<4){
tlm::tlm_phase phase(tlm::BEGIN_REQ);
sc_core::sc_time delay(SC_ZERO_TIME);
tlm::tlm_signal_gp<> gp;
gp.set_command(tlm::TLM_WRITE_COMMAND);
gp.set_value(true);
scs_o[regs->r_csid]->nb_transport_fw(gp, phase, delay);
}
reg.put(data);
return true;
});
regs->csid.set_write_cb([this](const scc::sc_register<uint32_t> &reg, uint32_t& data) -> bool {
if(regs->r_csmode.mode==2 && regs->csid != data && regs->r_csid<4){
tlm::tlm_phase phase(tlm::BEGIN_REQ);
sc_core::sc_time delay(SC_ZERO_TIME);
tlm::tlm_signal_gp<> gp;
gp.set_command(tlm::TLM_WRITE_COMMAND);
gp.set_value(true);
scs_o[regs->r_csid]->nb_transport_fw(gp, phase, delay);
}
reg.put(data);
return true;
});
regs->csdef.set_write_cb([this](const scc::sc_register<uint32_t> &reg, uint32_t& data) -> bool {
auto diff = regs->csdef ^ data;
if(regs->r_csmode.mode==2 && diff!=0 && (regs->r_csid<4) && (diff & (1<<regs->r_csid))!=0){
tlm::tlm_phase phase(tlm::BEGIN_REQ);
sc_core::sc_time delay(SC_ZERO_TIME);
tlm::tlm_signal_gp<> gp;
gp.set_command(tlm::TLM_WRITE_COMMAND);
gp.set_value(true);
scs_o[regs->r_csid]->nb_transport_fw(gp, phase, delay);
}
reg.put(data);
return true;
});
regs->ie.set_write_cb([this](scc::sc_register<uint32_t> &reg, uint32_t data) -> bool {
update_irq();
});
regs->ip.set_write_cb([this](scc::sc_register<uint32_t> &reg, uint32_t data) -> bool {
update_irq();
});
} }
spi::~spi() {} spi::~spi() {}
@ -68,4 +150,70 @@ void spi::reset_cb() {
regs->reset_stop(); regs->reset_stop();
} }
void spi::transmit_data() {
uint8_t txdata;
sysc::tlm_signal_spi_extension ext;
tlm::tlm_phase phase(tlm::BEGIN_REQ);
tlm::tlm_signal_gp<> gp;
sc_core::sc_time delay(SC_ZERO_TIME);
sc_core::sc_time bit_duration(SC_ZERO_TIME);
gp.set_extension(&ext);
ext.tx.data_bits=8;
auto set_bit = [&](bool val, scc::tlm_signal_bool_opt_out& socket){
if(socket.get_interface()==nullptr) return;
gp.set_command(tlm::TLM_WRITE_COMMAND);
gp.set_value(val);
tlm::tlm_phase phase(tlm::BEGIN_REQ);
socket->nb_transport_fw(gp, phase, delay);
};
wait(delay); //intentionally 0ns;
while(true){
wait(tx_fifo.data_written_event());
if(regs->r_csmode.mode != 3 && regs->r_csid<4) // not in OFF mode
set_bit(false, scs_o[regs->r_csid]);
set_bit(regs->r_sckmode.pol, sck_o);
while(tx_fifo.nb_read(txdata)){
regs->r_txdata.full=tx_fifo.num_free()==0;
regs->r_ip.txwm=regs->r_txmark.txmark<=(7-tx_fifo.num_free())?1:0;
bit_duration = 2*(regs->r_sckdiv.div+1)*clk;
ext.start_time = sc_core::sc_time_stamp();
ext.tx.m2s_data=txdata;
ext.tx.s2m_data_valid=false;
set_bit(txdata&0x80, mosi_o); // 8 data bits, MSB first
set_bit(1-regs->r_sckmode.pol, sck_o);
wait(bit_duration/2);
set_bit(regs->r_sckmode.pol, sck_o);
wait(bit_duration/2);
if(bit_true_transfer.get_value()){
for(size_t i = 0, mask=0x40; i<7; ++i, mask>=1){
set_bit(txdata&mask, mosi_o); // 8 data bits, MSB first
set_bit(1-regs->r_sckmode.pol, sck_o);
wait(bit_duration/2);
set_bit(regs->r_sckmode.pol, sck_o);
wait(bit_duration/2);
}
} else
wait(7*bit_duration);
rx_fifo.nb_write(ext.tx.s2m_data&0xff);
if(regs->r_rxmark.rxmark<=rx_fifo.num_available()){
regs->r_ip.rxwm=1;
update_irq();
}
}
if(regs->r_csmode.mode == 0 && regs->r_csid<4) // in AUTO mode
set_bit(false, scs_o[regs->r_csid]);
}
}
void spi::receive_data(tlm::tlm_signal_gp<>& gp, sc_core::sc_time& delay) {
}
void spi::update_irq() {
}
} /* namespace sysc */ } /* namespace sysc */

View File

@ -13,8 +13,11 @@ system::system(sc_core::sc_module_name nm)
: sc_module(nm) : sc_module(nm)
, NAMED(s_gpio, 32) , NAMED(s_gpio, 32)
, NAMED(s_rst_n) , NAMED(s_rst_n)
, NAMED(s_vref)
, NAMED(s_ana, 8)
, NAMED(i_platform) , NAMED(i_platform)
, NAMED(i_terminal) , NAMED(i_terminal)
, NAMED(i_adc)
{ {
// connect platform // connect platform
i_platform.erst_n(s_rst_n); i_platform.erst_n(s_rst_n);
@ -24,8 +27,18 @@ system::system(sc_core::sc_module_name nm)
i_platform.pins_i[i](s_gpio[i].out); i_platform.pins_i[i](s_gpio[i].out);
} }
// connect other units // connect other units
s_gpio[17].out(i_terminal.rx_i); // terminal
i_terminal.tx_o(s_gpio[16].in); i_terminal.tx_o(s_gpio[16].in);
s_gpio[17].out(i_terminal.rx_i);
// adc digital io
s_gpio[2].out(i_adc.cs_i);
s_gpio[3].out(i_adc.mosi_i);
i_adc.miso_o(s_gpio[4].in);
s_gpio[5].out(i_adc.sck_i);
// adc analog inputs
i_adc.ch_i(s_ana);
i_adc.vref_i(s_vref);
SC_THREAD(gen_por); SC_THREAD(gen_por);
} }
@ -37,4 +50,10 @@ void sysc::system::gen_por() {
s_rst_n = false; s_rst_n = false;
wait(10_ns); wait(10_ns);
s_rst_n = true; s_rst_n = true;
s_vref=1.024;
double val=0.1;
for(auto& sig:s_ana){
sig=val;
val+=0.12;
}
} }

View File

@ -12,7 +12,9 @@
using namespace sysc; using namespace sysc;
terminal::terminal() :terminal(sc_core::sc_gen_unique_name("terminal")){ terminal::terminal()
: terminal(sc_core::sc_gen_unique_name("terminal"))
{
} }
terminal::terminal(const sc_core::sc_module_name& nm) terminal::terminal(const sc_core::sc_module_name& nm)
@ -33,6 +35,15 @@ terminal::terminal(const sc_core::sc_module_name& nm)
terminal::~terminal() { terminal::~terminal() {
} }
void terminal::before_end_of_elaboration() {
if(write_to_ws.get_value()) {
LOG(TRACE)<<"Adding WS handler for "<<(std::string{"/ws/"}+name());
handler=std::make_shared<WsHandler>();
sc_comm_singleton::inst().registerWebSocketHandler((std::string{"/ws/"}+name()).c_str(), handler);
}
}
void terminal::receive(tlm::tlm_signal_gp<sc_dt::sc_logic>& gp, sc_core::sc_time& delay) { void terminal::receive(tlm::tlm_signal_gp<sc_dt::sc_logic>& gp, sc_core::sc_time& delay) {
sysc::tlm_signal_uart_extension* ext; sysc::tlm_signal_uart_extension* ext;
gp.get_extension(ext); gp.get_extension(ext);

View File

@ -36,7 +36,6 @@
#include "sysc/SiFive/uart.h" #include "sysc/SiFive/uart.h"
#include "sysc/sc_comm_singleton.h"
#include "sysc/tlm_extensions.h" #include "sysc/tlm_extensions.h"
#include "scc/report.h" #include "scc/report.h"
#include "scc/utilities.h" #include "scc/utilities.h"
@ -46,12 +45,7 @@ using namespace std;
namespace sysc { namespace sysc {
namespace {
using namespace seasocks;
}
uart::uart(sc_core::sc_module_name nm) uart::uart(sc_core::sc_module_name nm)
: sc_core::sc_module(nm) : sc_core::sc_module(nm)
, tlm_target<>(clk) , tlm_target<>(clk)
@ -60,8 +54,10 @@ uart::uart(sc_core::sc_module_name nm)
, NAMED(tx_o) , NAMED(tx_o)
, NAMED(rx_i) , NAMED(rx_i)
, NAMED(irq_o) , NAMED(irq_o)
, NAMED(write_to_ws, false) , NAMED(bit_true_transfer, false)
, NAMEDD(uart_regs, regs) , NAMEDD(uart_regs, regs)
, NAMED(rx_fifo, 8)
, NAMED(tx_fifo, 8)
{ {
regs->registerResources(*this); regs->registerResources(*this);
SC_METHOD(clock_cb); SC_METHOD(clock_cb);
@ -113,14 +109,6 @@ void uart::update_irq() {
irq_o=(regs->r_ip.rxwm==1 && regs->r_ie.rxwm==1) || (regs->r_ip.txwm==1 && regs->r_ie.txwm==1); irq_o=(regs->r_ip.rxwm==1 && regs->r_ie.rxwm==1) || (regs->r_ip.txwm==1 && regs->r_ie.txwm==1);
} }
void uart::before_end_of_elaboration() {
if(write_to_ws.get_value()) {
LOG(TRACE)<<"Adding WS handler for "<<(std::string{"/ws/"}+name());
handler=std::make_shared<WsHandler>();
sc_comm_singleton::inst().registerWebSocketHandler((std::string{"/ws/"}+name()).c_str(), handler);
}
}
void uart::clock_cb() { void uart::clock_cb() {
this->clk = clk_i.read(); this->clk = clk_i.read();
} }
@ -164,10 +152,13 @@ void uart::transmit_data() {
ext.tx.baud_rate=static_cast<unsigned>(1/bit_duration.to_seconds()); ext.tx.baud_rate=static_cast<unsigned>(1/bit_duration.to_seconds());
ext.tx.data=txdata; ext.tx.data=txdata;
set_bit(false); // start bit set_bit(false); // start bit
for(int i = 8; i>0; --i) if(bit_true_transfer.get_value()){
set_bit(txdata&(1<<(i-1))); // 8 data bits, MSB first for(int i = 8; i>0; --i)
set_bit(true); // stop bit 1 set_bit(txdata&(1<<(i-1))); // 8 data bits, MSB first
if(regs->r_txctrl.nstop) set_bit(true); // stop bit 2 if(regs->r_txctrl.nstop) set_bit(true); // stop bit 1
} else
wait(8*bit_duration);
set_bit(true); // stop bit 1/2
} }
} }
} }
@ -175,7 +166,7 @@ void uart::transmit_data() {
void uart::receive_data(tlm::tlm_signal_gp<>& gp, sc_core::sc_time& delay) { void uart::receive_data(tlm::tlm_signal_gp<>& gp, sc_core::sc_time& delay) {
sysc::tlm_signal_uart_extension* ext{nullptr}; sysc::tlm_signal_uart_extension* ext{nullptr};
gp.get_extension(ext); gp.get_extension(ext);
if(ext && ext != rx_ext){ if(ext && ext->start_time != rx_last_start){
auto data = static_cast<uint8_t>(ext->tx.data); auto data = static_cast<uint8_t>(ext->tx.data);
if(ext->tx.parity || ext->tx.data_bits!=8) data = rand(); // random value if wrong config if(ext->tx.parity || ext->tx.data_bits!=8) data = rand(); // random value if wrong config
rx_fifo.write(data); rx_fifo.write(data);
@ -183,7 +174,7 @@ void uart::receive_data(tlm::tlm_signal_gp<>& gp, sc_core::sc_time& delay) {
regs->r_ip.rxwm=1; regs->r_ip.rxwm=1;
update_irq(); update_irq();
} }
rx_ext=ext; // omit repeated handling of signale changes rx_last_start=ext->start_time; // omit repeated handling of signal changes
} }
gp.set_response_status(tlm::TLM_OK_RESPONSE); gp.set_response_status(tlm::TLM_OK_RESPONSE);
} }

View File

@ -2,10 +2,19 @@
"i_simple_system":{ "i_simple_system":{
"i_platform": { "i_platform": {
"i_uart0":{ "i_uart0":{
"write_to_ws": false "bit_true_transfer": false
}, },
"i_uart1":{ "i_uart1":{
"write_to_ws": false "bit_true_transfer": false
},
"i_qspi0":{
"bit_true_transfer": false
},
"i_qspi1":{
"bit_true_transfer": false
},
"i_qspi2":{
"bit_true_transfer": false
}, },
"i_gpio0.write_to_ws": false "i_gpio0.write_to_ws": false
} }