Added entire system incl. terminal and MCP3008 ADC connected via SPI
This commit is contained in:
parent
a899d30556
commit
100822810f
47
riscv.sc/incl/sysc/General/mcp3008.h
Normal file
47
riscv.sc/incl/sysc/General/mcp3008.h
Normal 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_ */
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "sysc/SiFive/platform.h"
|
||||
#include "sysc/General/terminal.h"
|
||||
#include "sysc/General/mcp3008.h"
|
||||
#include <systemc>
|
||||
|
||||
namespace sysc {
|
||||
@ -24,8 +25,11 @@ public:
|
||||
private:
|
||||
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<double> s_vref;
|
||||
sc_core::sc_vector<sc_core::sc_signal<double>> s_ana;
|
||||
sysc::platform i_platform;
|
||||
sysc::terminal i_terminal;
|
||||
sysc::mcp3008 i_adc;
|
||||
void gen_por();
|
||||
};
|
||||
|
||||
|
@ -32,8 +32,10 @@ public:
|
||||
cci::cci_param<bool> write_to_ws;
|
||||
|
||||
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);
|
||||
|
||||
std::vector<uint8_t> queue;
|
||||
std::shared_ptr<sysc::WsHandler> handler;
|
||||
sc_core::sc_time last_tx_start=sc_core::SC_ZERO_TIME;
|
||||
};
|
||||
|
@ -83,7 +83,7 @@ protected:
|
||||
|
||||
private:
|
||||
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 */
|
||||
|
@ -38,6 +38,11 @@
|
||||
#define _SPI_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 {
|
||||
|
||||
@ -47,15 +52,28 @@ class spi : public sc_core::sc_module, public scc::tlm_target<> {
|
||||
public:
|
||||
SC_HAS_PROCESS(spi);
|
||||
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);
|
||||
virtual ~spi() override;
|
||||
|
||||
protected:
|
||||
void clock_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;
|
||||
std::unique_ptr<spi_regs> regs;
|
||||
sc_core::sc_fifo<uint8_t> rx_fifo, tx_fifo;
|
||||
};
|
||||
|
||||
} /* namespace sysc */
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
|
||||
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);
|
||||
virtual ~uart() override;
|
||||
@ -69,13 +69,9 @@ protected:
|
||||
void transmit_data();
|
||||
void receive_data(tlm::tlm_signal_gp<>& gp, sc_core::sc_time& delay);
|
||||
void update_irq();
|
||||
void before_end_of_elaboration();
|
||||
sc_core::sc_time clk;
|
||||
sc_core::sc_time clk{SC_ZERO_TIME},rx_last_start{SC_ZERO_TIME};
|
||||
std::unique_ptr<uart_regs> regs;
|
||||
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 */
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -122,11 +122,6 @@ int sc_main(int argc, char *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
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
scc::configurer cfg(vm["config-file"].as<std::string>());
|
||||
@ -134,16 +129,24 @@ int sc_main(int argc, char *argv[]) {
|
||||
// instantiate top level
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
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){
|
||||
std::ofstream of{vm["dump-config"].as<std::string>()};
|
||||
if(of.is_open())
|
||||
cfg.dump_configuration(of);
|
||||
}
|
||||
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>());
|
||||
if (vm.count("dump-ir"))
|
||||
cfg.set_value("i_system.i_platform.i_core_complex.dump_ir", vm.count("dump-ir") != 0);
|
||||
|
@ -218,7 +218,7 @@ core_complex::core_complex(sc_core::sc_module_name name)
|
||||
, NAMED(timer_irq_i)
|
||||
, NAMED(local_irq_i, 16)
|
||||
, NAMED(elf_file, "")
|
||||
, NAMED(enable_disass, true)
|
||||
, NAMED(enable_disass, false)
|
||||
, NAMED(reset_address, 0ULL)
|
||||
, NAMED(gdb_server_port, 0)
|
||||
, 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() {
|
||||
cpu = make_unique<core_wrapper>(this);
|
||||
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());
|
||||
#endif
|
||||
auto* srv = debugger::server<debugger::gdb_session>::get();
|
||||
if(srv) tgt_adapter = srv->get_target();
|
||||
if(tgt_adapter)
|
||||
|
@ -103,7 +103,14 @@ gpio::gpio(sc_core::sc_module_name nm)
|
||||
});
|
||||
regs->iof_en.set_write_cb([this](scc::sc_register<uint32_t> ®, uint32_t data) -> bool {
|
||||
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> ®, uint32_t data) -> bool {
|
||||
if (!this->regs->in_reset()) {
|
||||
enable_outputs(regs->r_iof_en, data);
|
||||
reg.put(data);
|
||||
}
|
||||
return true;
|
||||
@ -157,12 +164,12 @@ void gpio::update_pins() {
|
||||
}
|
||||
}
|
||||
|
||||
void gpio::enable_outputs(uint32_t new_data) {
|
||||
auto changed_bits = regs->r_iof_en^new_data;
|
||||
void gpio::enable_outputs(uint32_t new_iof_en, uint32_t new_iof_sel) {
|
||||
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;
|
||||
for(size_t i=0, mask=1; i<32; ++i, mask<<=1){
|
||||
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){
|
||||
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)
|
||||
@ -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.copy_extensions_from(gp);
|
||||
socket->nb_transport_fw(new_gp, phase, delay); // we don't care about phase and sync enum
|
||||
gp.update_extensions_from(new_gp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
85
riscv.sc/src/sysc/mcp3008.cpp
Normal file
85
riscv.sc/src/sysc/mcp3008.cpp
Normal 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 */
|
@ -124,9 +124,20 @@ platform::platform(sc_core::sc_module_name nm)
|
||||
i_uart0.rx_i(i_gpio0.iof0_o[16]);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ void plic::handle_pending_int() {
|
||||
void plic::reset_pending_int(uint32_t irq) {
|
||||
// todo: evaluate enable register (see 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
|
||||
auto reg_idx = irq>>5;
|
||||
auto bit_ofs = irq & 0x1F;
|
||||
|
@ -36,8 +36,10 @@
|
||||
|
||||
#include "sysc/SiFive/spi.h"
|
||||
|
||||
#include "sysc/tlm_extensions.h"
|
||||
#include "scc/utilities.h"
|
||||
#include "sysc/SiFive/gen/spi_regs.h"
|
||||
#include <util/ities.h>
|
||||
|
||||
namespace sysc {
|
||||
|
||||
@ -46,6 +48,12 @@ spi::spi(sc_core::sc_module_name nm)
|
||||
, tlm_target<>(clk)
|
||||
, NAMED(clk_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) {
|
||||
regs->registerResources(*this);
|
||||
SC_METHOD(clock_cb);
|
||||
@ -53,6 +61,80 @@ spi::spi(sc_core::sc_module_name nm)
|
||||
SC_METHOD(reset_cb);
|
||||
sensitive << rst_i;
|
||||
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> ®, 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> ®, 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()®.rdmask;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
regs->csmode.set_write_cb([this](const scc::sc_register<uint32_t> ®, 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> ®, 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> ®, 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> ®, uint32_t data) -> bool {
|
||||
update_irq();
|
||||
});
|
||||
regs->ip.set_write_cb([this](scc::sc_register<uint32_t> ®, uint32_t data) -> bool {
|
||||
update_irq();
|
||||
});
|
||||
}
|
||||
|
||||
spi::~spi() {}
|
||||
@ -68,4 +150,70 @@ void spi::reset_cb() {
|
||||
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 */
|
||||
|
||||
|
@ -13,8 +13,11 @@ system::system(sc_core::sc_module_name nm)
|
||||
: sc_module(nm)
|
||||
, NAMED(s_gpio, 32)
|
||||
, NAMED(s_rst_n)
|
||||
, NAMED(s_vref)
|
||||
, NAMED(s_ana, 8)
|
||||
, NAMED(i_platform)
|
||||
, NAMED(i_terminal)
|
||||
, NAMED(i_adc)
|
||||
{
|
||||
// connect platform
|
||||
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);
|
||||
}
|
||||
// connect other units
|
||||
s_gpio[17].out(i_terminal.rx_i);
|
||||
// terminal
|
||||
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);
|
||||
}
|
||||
|
||||
@ -37,4 +50,10 @@ void sysc::system::gen_por() {
|
||||
s_rst_n = false;
|
||||
wait(10_ns);
|
||||
s_rst_n = true;
|
||||
s_vref=1.024;
|
||||
double val=0.1;
|
||||
for(auto& sig:s_ana){
|
||||
sig=val;
|
||||
val+=0.12;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,9 @@
|
||||
|
||||
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)
|
||||
@ -33,6 +35,15 @@ terminal::terminal(const sc_core::sc_module_name& nm)
|
||||
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) {
|
||||
sysc::tlm_signal_uart_extension* ext;
|
||||
gp.get_extension(ext);
|
||||
|
@ -36,7 +36,6 @@
|
||||
|
||||
#include "sysc/SiFive/uart.h"
|
||||
|
||||
#include "sysc/sc_comm_singleton.h"
|
||||
#include "sysc/tlm_extensions.h"
|
||||
#include "scc/report.h"
|
||||
#include "scc/utilities.h"
|
||||
@ -46,12 +45,7 @@ using namespace std;
|
||||
|
||||
|
||||
namespace sysc {
|
||||
namespace {
|
||||
|
||||
using namespace seasocks;
|
||||
|
||||
|
||||
}
|
||||
uart::uart(sc_core::sc_module_name nm)
|
||||
: sc_core::sc_module(nm)
|
||||
, tlm_target<>(clk)
|
||||
@ -60,8 +54,10 @@ uart::uart(sc_core::sc_module_name nm)
|
||||
, NAMED(tx_o)
|
||||
, NAMED(rx_i)
|
||||
, NAMED(irq_o)
|
||||
, NAMED(write_to_ws, false)
|
||||
, NAMED(bit_true_transfer, false)
|
||||
, NAMEDD(uart_regs, regs)
|
||||
, NAMED(rx_fifo, 8)
|
||||
, NAMED(tx_fifo, 8)
|
||||
{
|
||||
regs->registerResources(*this);
|
||||
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);
|
||||
}
|
||||
|
||||
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() {
|
||||
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.data=txdata;
|
||||
set_bit(false); // start bit
|
||||
for(int i = 8; i>0; --i)
|
||||
set_bit(txdata&(1<<(i-1))); // 8 data bits, MSB first
|
||||
set_bit(true); // stop bit 1
|
||||
if(regs->r_txctrl.nstop) set_bit(true); // stop bit 2
|
||||
if(bit_true_transfer.get_value()){
|
||||
for(int i = 8; i>0; --i)
|
||||
set_bit(txdata&(1<<(i-1))); // 8 data bits, MSB first
|
||||
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) {
|
||||
sysc::tlm_signal_uart_extension* ext{nullptr};
|
||||
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);
|
||||
if(ext->tx.parity || ext->tx.data_bits!=8) data = rand(); // random value if wrong config
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
@ -2,10 +2,19 @@
|
||||
"i_simple_system":{
|
||||
"i_platform": {
|
||||
"i_uart0":{
|
||||
"write_to_ws": false
|
||||
"bit_true_transfer": false
|
||||
},
|
||||
"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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user