Changed SystemC model to model a platform in a system. Added dedicated

UART Terminal connected via tlm_signals
This commit is contained in:
Eyck Jentzsch 2018-07-12 15:27:36 +02:00
parent a3baa45b00
commit fede5b2af1
19 changed files with 529 additions and 130 deletions

View File

@ -0,0 +1,30 @@
/*
* system.h
*
* Created on: 11.07.2018
* Author: eyck
*/
#ifndef __SYSC_GENERAL_SYSTEM_H_
#define __SYSC_GENERAL_SYSTEM_H_
#include "sysc/SiFive/platform.h"
#include "sysc/General/terminal.h"
#include <systemc>
namespace sysc {
class system: sc_core::sc_module {
public:
system(sc_core::sc_module_name nm);
virtual ~system();
sc_core::sc_vector<tlm::tlm_signal<sc_dt::sc_logic>> s_gpio;
private:
sysc::platform i_platform;
sysc::terminal i_terminal;
};
}
#endif /* __SYSC_GENERAL_SYSTEM_H_ */

View File

@ -0,0 +1,42 @@
/*
* terminal.h
*
* Created on: 07.07.2018
* Author: eyck
*/
#ifndef RISCV_SC_INCL_SYSC_GENERAL_TERMINAL_H_
#define RISCV_SC_INCL_SYSC_GENERAL_TERMINAL_H_
#include "scc/signal_target_mixin.h"
#include "scc/signal_initiator_mixin.h"
#include "tlm/tlm_signal.h"
#include "cci_configuration"
#include <sysc/kernel/sc_module.h>
#include <memory>
namespace sysc {
class WsHandler;
class terminal: public sc_core::sc_module {
public:
scc::tlm_signal_logic_out tx_o;
scc::tlm_signal_logic_in rx_i;
terminal();
terminal(const sc_core::sc_module_name& nm);
virtual ~terminal();
cci::cci_param<bool> write_to_ws;
protected:
std::vector<uint8_t> queue;
void receive(tlm::tlm_signal_gp<sc_dt::sc_logic>& gp, sc_core::sc_time& delay);
std::shared_ptr<sysc::WsHandler> handler;
sc_core::sc_time last_tx_start=sc_core::SC_ZERO_TIME;
};
}
#endif /* RISCV_SC_INCL_SYSC_GENERAL_TERMINAL_H_ */

View File

@ -55,7 +55,8 @@ class core_complex;
class clint : public sc_core::sc_module, public scc::tlm_target<> { class clint : public sc_core::sc_module, public scc::tlm_target<> {
public: public:
SC_HAS_PROCESS(clint); SC_HAS_PROCESS(clint);
sc_core::sc_in<sc_core::sc_time> clk_i; sc_core::sc_in<sc_core::sc_time> tlclk_i;
sc_core::sc_in<sc_core::sc_time> lfclk_i;
sc_core::sc_in<bool> rst_i; sc_core::sc_in<bool> rst_i;
sc_core::sc_out<bool> mtime_int_o; sc_core::sc_out<bool> mtime_int_o;
sc_core::sc_out<bool> msip_int_o; sc_core::sc_out<bool> msip_int_o;

View File

@ -109,7 +109,8 @@ public:
~core_complex(); ~core_complex();
inline void sync(uint64_t cycle) { inline void sync(uint64_t cycle) {
quantum_keeper.inc(curr_clk*(cycle-last_sync_cycle)); auto time = curr_clk*(cycle-last_sync_cycle);
quantum_keeper.inc(time);
if (quantum_keeper.need_sync()) { if (quantum_keeper.need_sync()) {
wait(quantum_keeper.get_local_time()); wait(quantum_keeper.get_local_time());
quantum_keeper.reset(); quantum_keeper.reset();

View File

@ -38,8 +38,10 @@
#define _GPIO_H_ #define _GPIO_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 "cci_configuration"
#include <sysc/communication/sc_signal_rv_ports.h>
namespace sysc { namespace sysc {
@ -51,7 +53,15 @@ public:
SC_HAS_PROCESS(gpio); SC_HAS_PROCESS(gpio);
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;
sc_core::sc_inout_rv<32> pins_io; // sc_core::sc_inout_rv<32> pins_io;
sc_core::sc_vector<scc::tlm_signal_logic_out> pins_o;
sc_core::sc_vector<scc::tlm_signal_logic_in> pins_i;
sc_core::sc_vector<scc::tlm_signal_bool_opt_out> iof0_o;
sc_core::sc_vector<scc::tlm_signal_bool_opt_out> iof1_o;
sc_core::sc_vector<scc::tlm_signal_bool_opt_in> iof0_i;
sc_core::sc_vector<scc::tlm_signal_bool_opt_in> iof1_i;
gpio(sc_core::sc_module_name nm); gpio(sc_core::sc_module_name nm);
virtual ~gpio() override; // need to keep it in source file because of fwd declaration of gpio_regs virtual ~gpio() override; // need to keep it in source file because of fwd declaration of gpio_regs
@ -62,14 +72,13 @@ protected:
void clock_cb(); void clock_cb();
void reset_cb(); void reset_cb();
void update_pins(); void update_pins();
void pins_cb();
void before_end_of_elaboration(); void before_end_of_elaboration();
void pin_input(unsigned int tag, tlm::tlm_signal_gp<sc_logic>& gp, sc_core::sc_time& delay);
void forward_pin_input(unsigned int tag, tlm::tlm_signal_gp<sc_logic>& gp);
void iof_input(unsigned int tag, unsigned iof_idx, tlm::tlm_signal_gp<>& gp, sc_core::sc_time& delay);
sc_core::sc_time clk; sc_core::sc_time clk;
std::unique_ptr<gpio_regs> regs; std::unique_ptr<gpio_regs> regs;
std::shared_ptr<sysc::WsHandler> handler; std::shared_ptr<sysc::WsHandler> handler;
private:
void update_value_reg();
}; };
} /* namespace sysc */ } /* namespace sysc */

View File

@ -34,8 +34,8 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef SIMPLESYSTEM_H_ #ifndef _PLATFORM_H_
#define SIMPLESYSTEM_H_ #define _PLATFORM_H_
#include "aon.h" #include "aon.h"
#include "clint.h" #include "clint.h"
@ -44,14 +44,15 @@
#include "prci.h" #include "prci.h"
#include "spi.h" #include "spi.h"
#include "uart.h" #include "uart.h"
#include "core_complex.h"
#include <array>
#include <sysc/kernel/sc_module.h>
#include "scc/memory.h" #include "scc/memory.h"
#include "scc/router.h" #include "scc/router.h"
#include "scc/utilities.h" #include "scc/utilities.h"
#include "core_complex.h" #include "tlm/tlm_signal_sockets.h"
#include <sysc/kernel/sc_module.h>
#include <array>
namespace sysc { namespace sysc {
@ -59,6 +60,12 @@ class platform : public sc_core::sc_module {
public: public:
SC_HAS_PROCESS(platform); SC_HAS_PROCESS(platform);
sc_core::sc_vector<tlm::tlm_signal_initiator_socket<sc_dt::sc_logic>> pins_o;
sc_core::sc_vector<tlm::tlm_signal_target_socket<sc_dt::sc_logic>> pins_i;
platform(sc_core::sc_module_name nm);
private:
SiFive::core_complex i_core_complex; SiFive::core_complex i_core_complex;
scc::router<> i_router; scc::router<> i_router;
uart i_uart0, i_uart1; uart i_uart0, i_uart1;
@ -71,13 +78,15 @@ public:
scc::memory<512_MB, 32> i_mem_qspi; scc::memory<512_MB, 32> i_mem_qspi;
scc::memory<128_kB, 32> i_mem_ram; scc::memory<128_kB, 32> i_mem_ram;
sc_core::sc_signal<sc_core::sc_time> s_clk; sc_core::sc_signal<sc_core::sc_time> s_tlclk;
sc_core::sc_signal<sc_core::sc_time> s_lfclk;
sc_core::sc_signal<bool> s_rst, s_mtime_int, s_msie_int; sc_core::sc_signal<bool> s_rst, s_mtime_int, s_msie_int;
sc_core::sc_vector<sc_core::sc_signal<bool>> s_global_int, s_local_int; sc_core::sc_vector<sc_core::sc_signal<bool, SC_MANY_WRITERS>> s_global_int, s_local_int;
sc_core::sc_signal<bool> s_core_int; sc_core::sc_signal<bool> s_core_int;
sc_core::sc_signal_rv<32> s_gpio_pins; sc_core::sc_vector<sc_core::sc_signal<bool>> s_dummy;
sc_core::sc_vector<scc::tlm_signal_bool_opt_in> s_dummy_sck_i;
sc_core::sc_vector<scc::tlm_signal_bool_opt_out> s_dummy_sck_o;
platform(sc_core::sc_module_name nm);
protected: protected:
void gen_reset(); void gen_reset();
@ -87,4 +96,4 @@ protected:
} /* namespace sysc */ } /* namespace sysc */
#endif /* SIMPLESYSTEM_H_ */ #endif /* _PLATFORM_H_ */

View File

@ -37,11 +37,14 @@
#ifndef _UART_H_ #ifndef _UART_H_
#define _UART_H_ #define _UART_H_
#include "cci_configuration"
#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"
namespace sysc { namespace sysc {
class tlm_signal_uart_extension;
class uart_regs; class uart_regs;
class WsHandler; class WsHandler;
@ -50,18 +53,28 @@ public:
SC_HAS_PROCESS(uart); SC_HAS_PROCESS(uart);
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_out tx_o;
scc::tlm_signal_bool_in rx_i;
sc_core::sc_out<bool> irq_o;
cci::cci_param<bool> write_to_ws;
uart(sc_core::sc_module_name nm); uart(sc_core::sc_module_name nm);
virtual ~uart() override; virtual ~uart() override;
cci::cci_param<bool> write_to_ws;
protected: protected:
void clock_cb(); void clock_cb();
void reset_cb(); void reset_cb();
void transmit_data(); void transmit_data();
void receive_data(tlm::tlm_signal_gp<>& gp, sc_core::sc_time& delay);
void update_irq();
void before_end_of_elaboration(); void before_end_of_elaboration();
sc_core::sc_time clk; 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;
std::vector<uint8_t> queue; std::vector<uint8_t> queue;
sysc::tlm_signal_uart_extension *rx_ext, *tx_ext;
std::shared_ptr<sysc::WsHandler> handler; std::shared_ptr<sysc::WsHandler> handler;
}; };

View File

@ -0,0 +1,31 @@
/*
* tlm_extensions.h
*
* Created on: 12.07.2018
* Author: eyck
*/
#ifndef RISCV_SC_INCL_SYSC_TLM_EXTENSIONS_H_
#define RISCV_SC_INCL_SYSC_TLM_EXTENSIONS_H_
#include "tlm/tlm_extensions.h"
namespace sysc {
struct tlm_signal_uart_extension : public tlm::tlm_unmanaged_extension<tlm_signal_uart_extension> {
struct uart_tx {
unsigned data_bits:4;
unsigned stop_bits:2;
bool parity:1;
unsigned baud_rate:24;
unsigned data;
} tx;
sc_core::sc_time start_time;
};
}
#endif /* RISCV_SC_INCL_SYSC_TLM_EXTENSIONS_H_ */

View File

@ -1,5 +1,5 @@
# library files # library files
FILE(GLOB RiscVSCHeaders *.h) FILE(GLOB RiscVSCHeaders *.h */*.h)
FILE(GLOB RiscvSCSources sysc/*.cpp) FILE(GLOB RiscvSCSources sysc/*.cpp)
set(LIB_HEADERS ${RiscVSCHeaders} ) set(LIB_HEADERS ${RiscVSCHeaders} )

View File

@ -37,7 +37,7 @@
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <iss/log_categories.h> #include <iss/log_categories.h>
#include <sstream> #include <sstream>
#include <sysc/SiFive/platform.h> #include <sysc/General/system.h>
#include "scc/configurer.h" #include "scc/configurer.h"
#include "scc/report.h" #include "scc/report.h"
#include "scc/scv_tr_db.h" #include "scc/scv_tr_db.h"
@ -123,7 +123,7 @@ int sc_main(int argc, char *argv[]) {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// instantiate top level // instantiate top level
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
platform i_simple_system("i_simple_system"); sysc::system i_system("i_system");
// sr_report_handler::add_sc_object_to_filter(&i_simple_system.i_master, // sr_report_handler::add_sc_object_to_filter(&i_simple_system.i_master,
// sc_core::SC_WARNING, sc_core::SC_MEDIUM); // sc_core::SC_WARNING, sc_core::SC_MEDIUM);
if(vm["dump-config"].as<std::string>().size()>0){ if(vm["dump-config"].as<std::string>().size()>0){
@ -134,20 +134,20 @@ int sc_main(int argc, char *argv[]) {
cfg.configure(); cfg.configure();
// overwrite with command line settings // overwrite with command line settings
if (vm["gdb-port"].as<unsigned short>()) if (vm["gdb-port"].as<unsigned short>())
cfg.set_value("i_simple_system.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_simple_system.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);
if (vm.count("elf")) if (vm.count("elf"))
cfg.set_value("i_simple_system.i_core_complex.elf_file", vm["elf"].as<std::string>()); cfg.set_value("i_system.i_platform.i_core_complex.elf_file", vm["elf"].as<std::string>());
if (vm.count("quantum")) if (vm.count("quantum"))
tlm::tlm_global_quantum::instance().set(sc_core::sc_time(vm["quantum"].as<unsigned>(), sc_core::SC_NS)); tlm::tlm_global_quantum::instance().set(sc_core::sc_time(vm["quantum"].as<unsigned>(), sc_core::SC_NS));
if (vm.count("reset")) { if (vm.count("reset")) {
auto str = vm["reset"].as<std::string>(); auto str = vm["reset"].as<std::string>();
uint64_t start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), 0, 16) : std::stoull(str, 0, 10); uint64_t start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), 0, 16) : std::stoull(str, 0, 10);
cfg.set_value("i_simple_system.i_core_complex.reset_address", start_address); cfg.set_value("i_system.i_platform.i_core_complex.reset_address", start_address);
} }
if (vm.count("disass")) { if (vm.count("disass")) {
cfg.set_value("i_simple_system.i_core_complex.enable_disass", true); cfg.set_value("i_system.i_platform.i_core_complex.enable_disass", true);
LOGGER(disass)::reporting_level() = logging::INFO; LOGGER(disass)::reporting_level() = logging::INFO;
auto file_name = vm["disass"].as<std::string>(); auto file_name = vm["disass"].as<std::string>();
if (file_name.length() > 0) { if (file_name.length() > 0) {

View File

@ -47,7 +47,8 @@ const int lfclk_mutiplier = 1 << 12;
clint::clint(sc_core::sc_module_name nm) clint::clint(sc_core::sc_module_name nm)
: sc_core::sc_module(nm) : sc_core::sc_module(nm)
, tlm_target<>(clk) , tlm_target<>(clk)
, NAMED(clk_i) , NAMED(tlclk_i)
, NAMED(lfclk_i)
, NAMED(rst_i) , NAMED(rst_i)
, NAMED(mtime_int_o) , NAMED(mtime_int_o)
, NAMED(msip_int_o) , NAMED(msip_int_o)
@ -55,7 +56,7 @@ clint::clint(sc_core::sc_module_name nm)
, cnt_fraction(0) { , cnt_fraction(0) {
regs->registerResources(*this); regs->registerResources(*this);
SC_METHOD(clock_cb); SC_METHOD(clock_cb);
sensitive << clk_i; sensitive << tlclk_i<<lfclk_i;
SC_METHOD(reset_cb); SC_METHOD(reset_cb);
sensitive << rst_i; sensitive << rst_i;
dont_initialize(); dont_initialize();
@ -84,7 +85,7 @@ clint::clint(sc_core::sc_module_name nm)
void clint::clock_cb() { void clint::clock_cb() {
update_mtime(); update_mtime();
this->clk = clk_i.read(); clk = lfclk_i.read();
update_mtime(); update_mtime();
} }
@ -101,10 +102,11 @@ void clint::reset_cb() {
} }
void clint::update_mtime() { void clint::update_mtime() {
auto diff = (sc_core::sc_time_stamp() - last_updt) / clk; if(clk>SC_ZERO_TIME){
auto diffi = (int)diff; uint64_t elapsed_clks = (sc_time_stamp()-last_updt)/clk; // get the number of clock periods since last invocation
regs->r_mtime += (diffi + cnt_fraction) / lfclk_mutiplier; last_updt += elapsed_clks*clk; // increment the last_updt timestamp by the number of clocks
cnt_fraction = (cnt_fraction + diffi) % lfclk_mutiplier; if(elapsed_clks){ // update mtime reg if we have more than 0 elapsed clk periods
regs->r_mtime+=elapsed_clks;
mtime_evt.cancel(); mtime_evt.cancel();
if (regs->r_mtimecmp > 0) if (regs->r_mtimecmp > 0)
if(regs->r_mtimecmp > regs->r_mtime && clk > sc_core::SC_ZERO_TIME) { if(regs->r_mtimecmp > regs->r_mtime && clk > sc_core::SC_ZERO_TIME) {
@ -114,7 +116,9 @@ void clint::update_mtime() {
mtime_int_o.write(false); mtime_int_o.write(false);
} else } else
mtime_int_o.write(true); mtime_int_o.write(true);
last_updt = sc_core::sc_time_stamp(); }
} else
last_updt = sc_time_stamp();
} }
} /* namespace sysc */ } /* namespace sysc */

View File

@ -35,7 +35,6 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "sysc/SiFive/gpio.h" #include "sysc/SiFive/gpio.h"
#include "sysc/sc_comm_singleton.h" #include "sysc/sc_comm_singleton.h"
#include "scc/report.h" #include "scc/report.h"
#include "scc/utilities.h" #include "scc/utilities.h"
@ -48,7 +47,12 @@ gpio::gpio(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(pins_io) , NAMED(pins_o, 32)
, NAMED(pins_i, 32)
, NAMED(iof0_o, 32)
, NAMED(iof1_o, 32)
, NAMED(iof0_i, 32)
, NAMED(iof1_i, 32)
, NAMEDD(gpio_regs, regs) , NAMEDD(gpio_regs, regs)
, NAMED(write_to_ws, false){ , NAMED(write_to_ws, false){
regs->registerResources(*this); regs->registerResources(*this);
@ -57,9 +61,36 @@ gpio::gpio(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_METHOD(pins_cb); auto pins_i_cb =[this](unsigned int tag, tlm::tlm_signal_gp<sc_logic>& gp,
sensitive << pins_io; tlm::tlm_phase& phase, sc_core::sc_time& delay)->tlm::tlm_sync_enum{
this->pin_input(tag, gp, delay);
return tlm::TLM_COMPLETED;
};
auto i=0U;
for(auto& s:pins_i){
s.register_nb_transport(pins_i_cb, i);
++i;
}
auto iof0_i_cb =[this](unsigned int tag, tlm::tlm_signal_gp<bool>& gp,
tlm::tlm_phase& phase, sc_core::sc_time& delay)->tlm::tlm_sync_enum{
this->iof_input(tag, 0, gp, delay);
return tlm::TLM_COMPLETED;
};
i=0;
for(auto& s:iof0_i){
s.register_nb_transport(iof0_i_cb, i);
++i;
}
auto iof1_i_cb =[this](unsigned int tag, tlm::tlm_signal_gp<bool>& gp,
tlm::tlm_phase& phase, sc_core::sc_time& delay)->tlm::tlm_sync_enum{
this->iof_input(tag, 1, gp, delay);
return tlm::TLM_COMPLETED;
};
i=0;
for(auto& s:iof1_i){
s.register_nb_transport(iof1_i_cb, i);
++i;
}
regs->port.set_write_cb([this](scc::sc_register<uint32_t> &reg, uint32_t data) -> bool { regs->port.set_write_cb([this](scc::sc_register<uint32_t> &reg, uint32_t data) -> bool {
if (!this->regs->in_reset()) { if (!this->regs->in_reset()) {
reg.put(data); reg.put(data);
@ -69,14 +100,6 @@ gpio::gpio(sc_core::sc_module_name nm)
return true; return true;
}); });
regs->value.set_read_cb([this](const scc::sc_register<uint32_t> &reg, uint32_t& data) -> bool {
if (!this->regs->in_reset()) {
// read pins_io and update r_value
update_value_reg();
data=reg.get();
}
return true;
});
} }
gpio::~gpio() {} gpio::~gpio() {}
@ -100,40 +123,76 @@ void gpio::clock_cb() {
this->clk = clk_i.read(); this->clk = clk_i.read();
} }
void gpio::pins_cb(){
auto inval=pins_io.read();
std::string msg(inval.to_string());
sc_core::sc_time now = sc_core::sc_time_stamp();
if(handler) sc_comm_singleton::inst().execute([this, msg, now](){
std::stringstream os;
os << "{\"time\":\"" << now << "\",\"data\":\""<<msg<<"\"}";
this->handler->send(os.str());
});
}
void gpio::update_value_reg() {
// read pins_io and update r_value reg
auto inval = pins_io.read();
uint32_t res = 0;
for (size_t i = 0, msk = 1; i < 32; ++i, msk = msk << 1) {
bool bit_set = false;
if ((regs->r_input_en & msk) != 0) {
if (inval.get_bit(1) == sc_dt::Log_1)
bit_set = true;
else if (inval.get_bit(1) == sc_dt::Log_Z
&& (regs->r_pue & msk) != 0)
bit_set = true;
}
if (bit_set) res |= msk;
}
regs->r_value = res;
}
void gpio::update_pins() { void gpio::update_pins() {
sc_core::sc_inout_rv<32>::data_type out_val; sc_core::sc_inout_rv<32>::data_type out_val;
for(size_t i=0, msk = 1; i<32; ++i, msk=msk<<1) tlm::tlm_signal_gp<sc_dt::sc_logic> gp;
out_val.set_bit(i, regs->r_output_en&msk?regs->r_port&msk?sc_dt::Log_1:sc_dt::Log_0:sc_dt::Log_Z); for(size_t i=0, mask = 1; i<32; ++i, mask<<=1){
pins_io.write(out_val); if((regs->iof_en&mask == 0) || (iof0_i[i].size()==0 && iof1_i[i].size()==0)){
sc_core::sc_time delay{SC_ZERO_TIME};
tlm::tlm_phase phase{tlm::BEGIN_REQ};
gp.set_command(tlm::TLM_WRITE_COMMAND);
gp.set_response_status(tlm::TLM_OK_RESPONSE);
gp.set_value(regs->r_output_en&mask?regs->r_port&mask?sc_dt::Log_1:sc_dt::Log_0:sc_dt::Log_Z);
pins_o.at(i)->nb_transport_fw(gp, phase, delay);
}
}
}
void gpio::pin_input(unsigned int tag, tlm::tlm_signal_gp<sc_logic>& gp, sc_core::sc_time& delay) {
if(delay>SC_ZERO_TIME){
wait(delay);
delay=SC_ZERO_TIME;
}
switch(gp.get_value().value()){
case sc_dt::Log_1:
regs->r_value|=1<<tag;
forward_pin_input(tag, gp);
break;
case sc_dt::Log_0:
regs->r_value&=~(1<<tag);
forward_pin_input(tag, gp);
break;
}
}
void gpio::forward_pin_input(unsigned int tag, tlm::tlm_signal_gp<sc_logic>& gp) {
const auto mask = 1U<<tag;
if(regs->iof_en&mask){
auto& socket = regs->iof_sel&mask?iof1_o[tag]:iof0_o[tag];
tlm::tlm_signal_gp<> new_gp;
for(size_t i=0; i<socket.size(); ++i){
sc_core::sc_time delay{SC_ZERO_TIME};
tlm::tlm_phase phase{tlm::BEGIN_REQ};
new_gp.set_command(tlm::TLM_WRITE_COMMAND);
new_gp.set_response_status(tlm::TLM_OK_RESPONSE);
new_gp.set_value(gp.get_value().value()==sc_dt::Log_1);
new_gp.update_extensions_from(gp);
socket->nb_transport_fw(new_gp, phase, delay); // we don't care about phase and sync enum
}
}
}
void gpio::iof_input(unsigned int tag, unsigned iof_idx, tlm::tlm_signal_gp<>& gp, sc_core::sc_time& delay) {
if(delay>SC_ZERO_TIME){
wait(delay);
delay=SC_ZERO_TIME;
}
const auto mask = 1U<<tag;
if(regs->r_iof_en&mask){
const auto idx = regs->r_iof_sel&mask?1:0;
if(iof_idx == idx){
auto& socket = pins_o[tag];
for(size_t i=0; i<socket.size(); ++i){
sc_core::sc_time delay{SC_ZERO_TIME};
tlm::tlm_phase phase{tlm::BEGIN_REQ};
tlm::tlm_signal_gp<sc_logic> new_gp;
new_gp.set_command(tlm::TLM_WRITE_COMMAND);
new_gp.set_value(gp.get_value()?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
}
}
}
} }
} /* namespace sysc */ } /* namespace sysc */

View File

@ -40,6 +40,8 @@ namespace sysc {
platform::platform(sc_core::sc_module_name nm) platform::platform(sc_core::sc_module_name nm)
: sc_core::sc_module(nm) : sc_core::sc_module(nm)
, NAMED(pins_o, 32)
, NAMED(pins_i, 32)
, NAMED(i_core_complex) , NAMED(i_core_complex)
, NAMED(i_router, 12, 1) , NAMED(i_router, 12, 1)
, NAMED(i_uart0) , NAMED(i_uart0)
@ -54,12 +56,15 @@ platform::platform(sc_core::sc_module_name nm)
, NAMED(i_clint) , NAMED(i_clint)
, NAMED(i_mem_qspi) , NAMED(i_mem_qspi)
, NAMED(i_mem_ram) , NAMED(i_mem_ram)
, NAMED(s_clk) , NAMED(s_tlclk)
, NAMED(s_rst) , NAMED(s_rst)
, NAMED(s_global_int, 256) , NAMED(s_global_int, 256)
, NAMED(s_local_int, 16) , NAMED(s_local_int, 16)
, NAMED(s_core_int) , NAMED(s_core_int)
, NAMED(s_gpio_pins) { , NAMED(s_dummy, 16)
, NAMED(s_dummy_sck_i, 16)
, NAMED(s_dummy_sck_o, 16)
{
i_core_complex.initiator(i_router.target[0]); i_core_complex.initiator(i_router.target[0]);
size_t i = 0; size_t i = 0;
for (const auto &e : e300_plat_map) { for (const auto &e : e300_plat_map) {
@ -72,17 +77,18 @@ platform::platform(sc_core::sc_module_name nm)
i_router.initiator.at(++i)(i_mem_ram.target); i_router.initiator.at(++i)(i_mem_ram.target);
i_router.add_target_range(i, 0x80000000, 128_kB); i_router.add_target_range(i, 0x80000000, 128_kB);
i_uart0.clk_i(s_clk); i_uart0.clk_i(s_tlclk);
i_uart1.clk_i(s_clk); i_uart1.clk_i(s_tlclk);
i_qspi0.clk_i(s_clk); i_qspi0.clk_i(s_tlclk);
i_qspi1.clk_i(s_clk); i_qspi1.clk_i(s_tlclk);
i_qspi2.clk_i(s_clk); i_qspi2.clk_i(s_tlclk);
i_gpio0.clk_i(s_clk); i_gpio0.clk_i(s_tlclk);
i_plic.clk_i(s_clk); i_plic.clk_i(s_tlclk);
i_aon.clk_i(s_clk); i_aon.clk_i(s_tlclk);
i_prci.clk_i(s_clk); i_prci.clk_i(s_tlclk);
i_clint.clk_i(s_clk); i_clint.tlclk_i(s_tlclk);
i_core_complex.clk_i(s_clk); i_clint.lfclk_i(s_lfclk);
i_core_complex.clk_i(s_tlclk);
i_uart0.rst_i(s_rst); i_uart0.rst_i(s_rst);
i_uart1.rst_i(s_rst); i_uart1.rst_i(s_rst);
@ -107,13 +113,25 @@ platform::platform(sc_core::sc_module_name nm)
i_core_complex.global_irq_i(s_core_int); i_core_complex.global_irq_i(s_core_int);
i_core_complex.local_irq_i(s_local_int); i_core_complex.local_irq_i(s_local_int);
i_gpio0.pins_io(s_gpio_pins); pins_i(i_gpio0.pins_i);
i_gpio0.pins_o(pins_o);
i_gpio0.iof0_i[17](i_uart0.tx_o);
i_uart0.rx_i(i_gpio0.iof0_o[16]);
i_uart0.irq_o(s_global_int[3]);
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]);
SC_THREAD(gen_reset); SC_THREAD(gen_reset);
for(auto& sock:s_dummy_sck_i) sock.error_if_no_callback=false;
} }
void platform::gen_reset() { void platform::gen_reset() {
s_clk = 10_ns; s_tlclk = 10_ns;
s_lfclk = 30517_ns;
s_rst = true; s_rst = true;
wait(10_ns); wait(10_ns);
s_rst = false; s_rst = false;

View File

@ -0,0 +1,30 @@
/*
* system.cpp
*
* Created on: 11.07.2018
* Author: eyck
*/
#include "sysc/General/system.h"
using namespace sysc;
system::system(sc_core::sc_module_name nm)
: sc_module(nm)
, NAMED(s_gpio, 32)
, NAMED(i_platform)
, NAMED(i_terminal)
{
for(auto i=0U; i<s_gpio.size(); ++i){
s_gpio[i].in(i_platform.pins_o[i]);
i_platform.pins_i[i](s_gpio[i].out);
}
// i_platform.pins_i(i_platform.pins_o);
s_gpio[17].out(i_terminal.rx_i);
i_terminal.tx_o(s_gpio[16].in);
}
system::~system() {
}

View File

@ -0,0 +1,57 @@
/*
* terminal.cpp
*
* Created on: 07.07.2018
* Author: eyck
*/
#include "sysc/General/terminal.h"
#include "sysc/sc_comm_singleton.h"
#include "sysc/tlm_extensions.h"
#include "scc/report.h"
using namespace sysc;
terminal::terminal() :terminal(sc_core::sc_gen_unique_name("terminal")){
}
terminal::terminal(const sc_core::sc_module_name& nm)
: sc_core::sc_module(nm)
, NAMED(tx_o)
, NAMED(rx_i)
, NAMED(write_to_ws, false)
{
rx_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{
this->receive(gp, delay);
return tlm::TLM_COMPLETED;
});
}
terminal::~terminal() {
}
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);
if(ext && ext->start_time!=last_tx_start){
uint8_t txdata = static_cast<uint8_t>(ext->tx.data);
last_tx_start = ext->start_time;
if(txdata != '\r') queue.push_back(txdata);
if (queue.size() >> 0 && (txdata == '\n' || txdata == 0)) {
std::string msg(queue.begin(), queue.end()-1);
sc_core::sc_time now = sc_core::sc_time_stamp();
if(handler)
sysc::sc_comm_singleton::inst().execute([this, msg, now](){
std::stringstream os;
os << "{\"time\":\"" << now << "\",\"message\":\""<<msg<<"\"}";
this->handler->send(os.str());
});
else
LOG(INFO) << this->name() << " receive: '" << msg << "'";
queue.clear();
}
}
}

View File

@ -37,6 +37,7 @@
#include "sysc/SiFive/uart.h" #include "sysc/SiFive/uart.h"
#include "sysc/sc_comm_singleton.h" #include "sysc/sc_comm_singleton.h"
#include "sysc/tlm_extensions.h"
#include "scc/report.h" #include "scc/report.h"
#include "scc/utilities.h" #include "scc/utilities.h"
#include "sysc/SiFive/gen/uart_regs.h" #include "sysc/SiFive/gen/uart_regs.h"
@ -56,25 +57,62 @@ uart::uart(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(tx_o)
, NAMED(rx_i)
, NAMED(irq_o)
, NAMED(write_to_ws, false)
, NAMEDD(uart_regs, regs) , NAMEDD(uart_regs, regs)
, NAMED(write_to_ws, false) { {
regs->registerResources(*this); regs->registerResources(*this);
SC_METHOD(clock_cb); SC_METHOD(clock_cb);
sensitive << clk_i; sensitive << clk_i;
SC_METHOD(reset_cb); SC_METHOD(reset_cb);
sensitive << rst_i; sensitive << rst_i;
dont_initialize(); dont_initialize();
SC_THREAD(transmit_data);
rx_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 { regs->txdata.set_write_cb([this](scc::sc_register<uint32_t> &reg, uint32_t data) -> bool {
if (!this->regs->in_reset()) { if (!this->regs->in_reset()) {
reg.put(data); reg.put(data);
this->transmit_data(); tx_fifo.nb_write(static_cast<uint8_t>(regs->r_txdata.data));
regs->r_txdata.full=tx_fifo.num_free()==0;
regs->r_ip.txwm=regs->r_txctrl.txcnt<=(7-tx_fifo.num_free())?1:0;
update_irq();
} }
return true; 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.data=val;
if(regs->r_rxctrl.rxcnt<=rx_fifo.num_available()){
regs->r_ip.rxwm=1;
update_irq();
}
}
data = reg.get()&reg.rdmask;
}
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();
});
} }
uart::~uart() {} uart::~uart() {}
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() { void uart::before_end_of_elaboration() {
if(write_to_ws.get_value()) { if(write_to_ws.get_value()) {
LOG(TRACE)<<"Adding WS handler for "<<(std::string{"/ws/"}+name()); LOG(TRACE)<<"Adding WS handler for "<<(std::string{"/ws/"}+name());
@ -95,19 +133,74 @@ void uart::reset_cb() {
} }
void uart::transmit_data() { void uart::transmit_data() {
if(regs->r_txdata.data != '\r') queue.push_back(regs->r_txdata.data); uint8_t txdata;
if (queue.size() >> 0 && (regs->r_txdata.data == '\n' || regs->r_txdata.data == 0)) { sc_core::sc_time delay(SC_ZERO_TIME);
std::string msg(queue.begin(), queue.end()-1); tlm::tlm_phase phase(tlm::BEGIN_REQ);
LOG(INFO) << this->name() << " transmit: '" << msg << "'"; tlm::tlm_signal_gp<> gp;
sc_core::sc_time now = sc_core::sc_time_stamp(); gp.set_command(tlm::TLM_WRITE_COMMAND);
if(handler) gp.set_value(true);
sc_comm_singleton::inst().execute([this, msg, now](){ tx_o->nb_transport_fw(gp, phase, delay);
std::stringstream os; while(true){
os << "{\"time\":\"" << now << "\",\"message\":\""<<msg<<"\"}"; wait(tx_fifo.data_written_event());
this->handler->send(os.str()); while(tx_fifo.nb_read(txdata)){
}); regs->r_txdata.full=tx_fifo.num_free()==0;
queue.clear(); regs->r_ip.txwm=regs->r_txctrl.txcnt<=(7-tx_fifo.num_free())?1:0;
auto bit_duration = (regs->r_div.div+1)*clk;
sysc::tlm_signal_uart_extension ext;
ext.start_time = sc_core::sc_time_stamp();
ext.tx.data_bits=8;
ext.tx.parity=false;
ext.tx.stop_bits=1+regs->r_txctrl.nstop;
ext.tx.baud_rate=static_cast<unsigned>(1/bit_duration.to_seconds());
ext.tx.data=txdata;
delay=SC_ZERO_TIME;
auto start = sc_time_stamp();
gp.set_command(tlm::TLM_WRITE_COMMAND);
gp.set_value(false);
gp.set_extension(&ext);
phase=tlm::BEGIN_REQ;
tx_o->nb_transport_fw(gp, phase, delay);
auto duration = bit_duration*(1+8+1+ext.tx.stop_bits);//start+data+parity+stop
auto diff=start+duration-sc_time_stamp();
if(diff>SC_ZERO_TIME) wait(diff);
delay=SC_ZERO_TIME;
gp.set_command(tlm::TLM_WRITE_COMMAND);
gp.set_value(true);
phase=tlm::BEGIN_REQ;
tx_o->nb_transport_fw(gp, phase, delay);
// if(txdata != '\r') queue.push_back(txdata);
// if (queue.size() >> 0 && (txdata == '\n' || txdata == 0)) {
// std::string msg(queue.begin(), queue.end()-1);
// LOG(INFO) << this->name() << " transmit: '" << msg << "'";
// sc_core::sc_time now = sc_core::sc_time_stamp();
// if(handler)
// sc_comm_singleton::inst().execute([this, msg, now](){
// std::stringstream os;
// os << "{\"time\":\"" << now << "\",\"message\":\""<<msg<<"\"}";
// this->handler->send(os.str());
// });
// queue.clear();
// }
}
} }
} }
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){
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);
if(regs->r_rxctrl.rxcnt<=rx_fifo.num_available()){
regs->r_ip.rxwm=1;
update_irq();
}
rx_ext=ext; // omit repeated handling of signale changes
}
gp.set_response_status(tlm::TLM_OK_RESPONSE);
}
} /* namespace sysc */ } /* namespace sysc */

View File

@ -697,7 +697,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const iss::addr_t &addr, unsigned leng
} break; } break;
case traits<BASE>::RES: { case traits<BASE>::RES: {
auto it = atomic_reservation.find(addr.val); auto it = atomic_reservation.find(addr.val);
if (it != atomic_reservation.end() && (*it).second != 0) { if (it != atomic_reservation.end() && it->second != 0) {
memset(data, 0xff, length); memset(data, 0xff, length);
atomic_reservation.erase(addr.val); atomic_reservation.erase(addr.val);
} else } else

@ -1 +1 @@
Subproject commit b50df83ebfbf06299613a973552856954ed383c1 Subproject commit 019a04132a8beb7fcab24d504e3347ca0771ea5f

View File

@ -1,11 +1,13 @@
{ {
"i_simple_system":{ "i_simple_system":{
"i_platform": {
"i_uart0":{ "i_uart0":{
"write_to_ws": true "write_to_ws": false
}, },
"i_uart1":{ "i_uart1":{
"write_to_ws": false "write_to_ws": false
}, },
"i_gpio0.write_to_ws": true "i_gpio0.write_to_ws": false
}
} }
} }