Changed SystemC model to model a platform in a system. Added dedicated
UART Terminal connected via tlm_signals
This commit is contained in:
parent
a3baa45b00
commit
fede5b2af1
30
riscv.sc/incl/sysc/General/system.h
Normal file
30
riscv.sc/incl/sysc/General/system.h
Normal 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_ */
|
42
riscv.sc/incl/sysc/General/terminal.h
Normal file
42
riscv.sc/incl/sysc/General/terminal.h
Normal 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_ */
|
@ -55,7 +55,8 @@ class core_complex;
|
||||
class clint : public sc_core::sc_module, public scc::tlm_target<> {
|
||||
public:
|
||||
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_out<bool> mtime_int_o;
|
||||
sc_core::sc_out<bool> msip_int_o;
|
||||
|
@ -109,7 +109,8 @@ public:
|
||||
~core_complex();
|
||||
|
||||
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()) {
|
||||
wait(quantum_keeper.get_local_time());
|
||||
quantum_keeper.reset();
|
||||
|
@ -38,8 +38,10 @@
|
||||
#define _GPIO_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/communication/sc_signal_rv_ports.h>
|
||||
|
||||
namespace sysc {
|
||||
|
||||
@ -51,7 +53,15 @@ public:
|
||||
SC_HAS_PROCESS(gpio);
|
||||
sc_core::sc_in<sc_core::sc_time> clk_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);
|
||||
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 reset_cb();
|
||||
void update_pins();
|
||||
void pins_cb();
|
||||
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;
|
||||
std::unique_ptr<gpio_regs> regs;
|
||||
std::shared_ptr<sysc::WsHandler> handler;
|
||||
|
||||
private:
|
||||
void update_value_reg();
|
||||
};
|
||||
|
||||
} /* namespace sysc */
|
||||
|
@ -34,8 +34,8 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SIMPLESYSTEM_H_
|
||||
#define SIMPLESYSTEM_H_
|
||||
#ifndef _PLATFORM_H_
|
||||
#define _PLATFORM_H_
|
||||
|
||||
#include "aon.h"
|
||||
#include "clint.h"
|
||||
@ -44,14 +44,15 @@
|
||||
#include "prci.h"
|
||||
#include "spi.h"
|
||||
#include "uart.h"
|
||||
|
||||
#include <array>
|
||||
#include <sysc/kernel/sc_module.h>
|
||||
#include "core_complex.h"
|
||||
|
||||
#include "scc/memory.h"
|
||||
#include "scc/router.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 {
|
||||
|
||||
@ -59,6 +60,12 @@ class platform : public sc_core::sc_module {
|
||||
public:
|
||||
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;
|
||||
scc::router<> i_router;
|
||||
uart i_uart0, i_uart1;
|
||||
@ -71,13 +78,15 @@ public:
|
||||
|
||||
scc::memory<512_MB, 32> i_mem_qspi;
|
||||
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_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_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:
|
||||
void gen_reset();
|
||||
@ -87,4 +96,4 @@ protected:
|
||||
|
||||
} /* namespace sysc */
|
||||
|
||||
#endif /* SIMPLESYSTEM_H_ */
|
||||
#endif /* _PLATFORM_H_ */
|
||||
|
@ -37,11 +37,14 @@
|
||||
#ifndef _UART_H_
|
||||
#define _UART_H_
|
||||
|
||||
#include "cci_configuration"
|
||||
#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 {
|
||||
|
||||
class tlm_signal_uart_extension;
|
||||
class uart_regs;
|
||||
class WsHandler;
|
||||
|
||||
@ -50,18 +53,28 @@ public:
|
||||
SC_HAS_PROCESS(uart);
|
||||
sc_core::sc_in<sc_core::sc_time> clk_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);
|
||||
virtual ~uart() override;
|
||||
|
||||
cci::cci_param<bool> write_to_ws;
|
||||
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();
|
||||
void before_end_of_elaboration();
|
||||
sc_core::sc_time clk;
|
||||
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;
|
||||
};
|
||||
|
||||
|
31
riscv.sc/incl/sysc/tlm_extensions.h
Normal file
31
riscv.sc/incl/sysc/tlm_extensions.h
Normal 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_ */
|
@ -1,5 +1,5 @@
|
||||
# library files
|
||||
FILE(GLOB RiscVSCHeaders *.h)
|
||||
FILE(GLOB RiscVSCHeaders *.h */*.h)
|
||||
FILE(GLOB RiscvSCSources sysc/*.cpp)
|
||||
|
||||
set(LIB_HEADERS ${RiscVSCHeaders} )
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include <boost/program_options.hpp>
|
||||
#include <iss/log_categories.h>
|
||||
#include <sstream>
|
||||
#include <sysc/SiFive/platform.h>
|
||||
#include <sysc/General/system.h>
|
||||
#include "scc/configurer.h"
|
||||
#include "scc/report.h"
|
||||
#include "scc/scv_tr_db.h"
|
||||
@ -123,7 +123,7 @@ int sc_main(int argc, char *argv[]) {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 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,
|
||||
// sc_core::SC_WARNING, sc_core::SC_MEDIUM);
|
||||
if(vm["dump-config"].as<std::string>().size()>0){
|
||||
@ -134,20 +134,20 @@ int sc_main(int argc, char *argv[]) {
|
||||
cfg.configure();
|
||||
// overwrite with command line settings
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
tlm::tlm_global_quantum::instance().set(sc_core::sc_time(vm["quantum"].as<unsigned>(), sc_core::SC_NS));
|
||||
if (vm.count("reset")) {
|
||||
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);
|
||||
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")) {
|
||||
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;
|
||||
auto file_name = vm["disass"].as<std::string>();
|
||||
if (file_name.length() > 0) {
|
||||
|
@ -47,7 +47,8 @@ const int lfclk_mutiplier = 1 << 12;
|
||||
clint::clint(sc_core::sc_module_name nm)
|
||||
: sc_core::sc_module(nm)
|
||||
, tlm_target<>(clk)
|
||||
, NAMED(clk_i)
|
||||
, NAMED(tlclk_i)
|
||||
, NAMED(lfclk_i)
|
||||
, NAMED(rst_i)
|
||||
, NAMED(mtime_int_o)
|
||||
, NAMED(msip_int_o)
|
||||
@ -55,7 +56,7 @@ clint::clint(sc_core::sc_module_name nm)
|
||||
, cnt_fraction(0) {
|
||||
regs->registerResources(*this);
|
||||
SC_METHOD(clock_cb);
|
||||
sensitive << clk_i;
|
||||
sensitive << tlclk_i<<lfclk_i;
|
||||
SC_METHOD(reset_cb);
|
||||
sensitive << rst_i;
|
||||
dont_initialize();
|
||||
@ -84,7 +85,7 @@ clint::clint(sc_core::sc_module_name nm)
|
||||
|
||||
void clint::clock_cb() {
|
||||
update_mtime();
|
||||
this->clk = clk_i.read();
|
||||
clk = lfclk_i.read();
|
||||
update_mtime();
|
||||
}
|
||||
|
||||
@ -101,20 +102,23 @@ void clint::reset_cb() {
|
||||
}
|
||||
|
||||
void clint::update_mtime() {
|
||||
auto diff = (sc_core::sc_time_stamp() - last_updt) / clk;
|
||||
auto diffi = (int)diff;
|
||||
regs->r_mtime += (diffi + cnt_fraction) / lfclk_mutiplier;
|
||||
cnt_fraction = (cnt_fraction + diffi) % lfclk_mutiplier;
|
||||
mtime_evt.cancel();
|
||||
if (regs->r_mtimecmp > 0)
|
||||
if(regs->r_mtimecmp > regs->r_mtime && clk > sc_core::SC_ZERO_TIME) {
|
||||
sc_core::sc_time next_trigger = (clk * lfclk_mutiplier) * (regs->r_mtimecmp - regs->mtime) - cnt_fraction * clk;
|
||||
LOG(DEBUG)<<"Timer fires at "<< sc_time_stamp()+next_trigger;
|
||||
mtime_evt.notify(next_trigger);
|
||||
mtime_int_o.write(false);
|
||||
} else
|
||||
mtime_int_o.write(true);
|
||||
last_updt = sc_core::sc_time_stamp();
|
||||
if(clk>SC_ZERO_TIME){
|
||||
uint64_t elapsed_clks = (sc_time_stamp()-last_updt)/clk; // get the number of clock periods since last invocation
|
||||
last_updt += elapsed_clks*clk; // increment the last_updt timestamp by the number of clocks
|
||||
if(elapsed_clks){ // update mtime reg if we have more than 0 elapsed clk periods
|
||||
regs->r_mtime+=elapsed_clks;
|
||||
mtime_evt.cancel();
|
||||
if (regs->r_mtimecmp > 0)
|
||||
if(regs->r_mtimecmp > regs->r_mtime && clk > sc_core::SC_ZERO_TIME) {
|
||||
sc_core::sc_time next_trigger = (clk * lfclk_mutiplier) * (regs->r_mtimecmp - regs->mtime) - cnt_fraction * clk;
|
||||
LOG(DEBUG)<<"Timer fires at "<< sc_time_stamp()+next_trigger;
|
||||
mtime_evt.notify(next_trigger);
|
||||
mtime_int_o.write(false);
|
||||
} else
|
||||
mtime_int_o.write(true);
|
||||
}
|
||||
} else
|
||||
last_updt = sc_time_stamp();
|
||||
}
|
||||
|
||||
} /* namespace sysc */
|
||||
|
@ -35,7 +35,6 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "sysc/SiFive/gpio.h"
|
||||
|
||||
#include "sysc/sc_comm_singleton.h"
|
||||
#include "scc/report.h"
|
||||
#include "scc/utilities.h"
|
||||
@ -48,7 +47,12 @@ gpio::gpio(sc_core::sc_module_name nm)
|
||||
, tlm_target<>(clk)
|
||||
, NAMED(clk_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)
|
||||
, NAMED(write_to_ws, false){
|
||||
regs->registerResources(*this);
|
||||
@ -57,9 +61,36 @@ gpio::gpio(sc_core::sc_module_name nm)
|
||||
SC_METHOD(reset_cb);
|
||||
sensitive << rst_i;
|
||||
dont_initialize();
|
||||
SC_METHOD(pins_cb);
|
||||
sensitive << pins_io;
|
||||
|
||||
auto pins_i_cb =[this](unsigned int tag, tlm::tlm_signal_gp<sc_logic>& gp,
|
||||
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> ®, uint32_t data) -> bool {
|
||||
if (!this->regs->in_reset()) {
|
||||
reg.put(data);
|
||||
@ -69,14 +100,6 @@ gpio::gpio(sc_core::sc_module_name nm)
|
||||
return true;
|
||||
});
|
||||
|
||||
regs->value.set_read_cb([this](const scc::sc_register<uint32_t> ®, 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() {}
|
||||
@ -100,40 +123,76 @@ void gpio::clock_cb() {
|
||||
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() {
|
||||
sc_core::sc_inout_rv<32>::data_type out_val;
|
||||
for(size_t i=0, msk = 1; i<32; ++i, msk=msk<<1)
|
||||
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);
|
||||
pins_io.write(out_val);
|
||||
tlm::tlm_signal_gp<sc_dt::sc_logic> gp;
|
||||
for(size_t i=0, mask = 1; i<32; ++i, mask<<=1){
|
||||
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 */
|
||||
|
@ -40,6 +40,8 @@ namespace sysc {
|
||||
|
||||
platform::platform(sc_core::sc_module_name nm)
|
||||
: sc_core::sc_module(nm)
|
||||
, NAMED(pins_o, 32)
|
||||
, NAMED(pins_i, 32)
|
||||
, NAMED(i_core_complex)
|
||||
, NAMED(i_router, 12, 1)
|
||||
, NAMED(i_uart0)
|
||||
@ -54,12 +56,15 @@ platform::platform(sc_core::sc_module_name nm)
|
||||
, NAMED(i_clint)
|
||||
, NAMED(i_mem_qspi)
|
||||
, NAMED(i_mem_ram)
|
||||
, NAMED(s_clk)
|
||||
, NAMED(s_tlclk)
|
||||
, NAMED(s_rst)
|
||||
, NAMED(s_global_int, 256)
|
||||
, NAMED(s_local_int, 16)
|
||||
, 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]);
|
||||
size_t i = 0;
|
||||
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.add_target_range(i, 0x80000000, 128_kB);
|
||||
|
||||
i_uart0.clk_i(s_clk);
|
||||
i_uart1.clk_i(s_clk);
|
||||
i_qspi0.clk_i(s_clk);
|
||||
i_qspi1.clk_i(s_clk);
|
||||
i_qspi2.clk_i(s_clk);
|
||||
i_gpio0.clk_i(s_clk);
|
||||
i_plic.clk_i(s_clk);
|
||||
i_aon.clk_i(s_clk);
|
||||
i_prci.clk_i(s_clk);
|
||||
i_clint.clk_i(s_clk);
|
||||
i_core_complex.clk_i(s_clk);
|
||||
i_uart0.clk_i(s_tlclk);
|
||||
i_uart1.clk_i(s_tlclk);
|
||||
i_qspi0.clk_i(s_tlclk);
|
||||
i_qspi1.clk_i(s_tlclk);
|
||||
i_qspi2.clk_i(s_tlclk);
|
||||
i_gpio0.clk_i(s_tlclk);
|
||||
i_plic.clk_i(s_tlclk);
|
||||
i_aon.clk_i(s_tlclk);
|
||||
i_prci.clk_i(s_tlclk);
|
||||
i_clint.tlclk_i(s_tlclk);
|
||||
i_clint.lfclk_i(s_lfclk);
|
||||
i_core_complex.clk_i(s_tlclk);
|
||||
|
||||
i_uart0.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.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);
|
||||
|
||||
for(auto& sock:s_dummy_sck_i) sock.error_if_no_callback=false;
|
||||
}
|
||||
|
||||
void platform::gen_reset() {
|
||||
s_clk = 10_ns;
|
||||
s_tlclk = 10_ns;
|
||||
s_lfclk = 30517_ns;
|
||||
s_rst = true;
|
||||
wait(10_ns);
|
||||
s_rst = false;
|
||||
|
30
riscv.sc/src/sysc/system.cpp
Normal file
30
riscv.sc/src/sysc/system.cpp
Normal 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() {
|
||||
}
|
||||
|
57
riscv.sc/src/sysc/terminal.cpp
Normal file
57
riscv.sc/src/sysc/terminal.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@
|
||||
#include "sysc/SiFive/uart.h"
|
||||
|
||||
#include "sysc/sc_comm_singleton.h"
|
||||
#include "sysc/tlm_extensions.h"
|
||||
#include "scc/report.h"
|
||||
#include "scc/utilities.h"
|
||||
#include "sysc/SiFive/gen/uart_regs.h"
|
||||
@ -56,25 +57,62 @@ uart::uart(sc_core::sc_module_name nm)
|
||||
, tlm_target<>(clk)
|
||||
, NAMED(clk_i)
|
||||
, NAMED(rst_i)
|
||||
, NAMED(tx_o)
|
||||
, NAMED(rx_i)
|
||||
, NAMED(irq_o)
|
||||
, NAMED(write_to_ws, false)
|
||||
, NAMEDD(uart_regs, regs)
|
||||
, NAMED(write_to_ws, false) {
|
||||
{
|
||||
regs->registerResources(*this);
|
||||
SC_METHOD(clock_cb);
|
||||
sensitive << clk_i;
|
||||
SC_METHOD(reset_cb);
|
||||
sensitive << rst_i;
|
||||
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> ®, uint32_t data) -> bool {
|
||||
if (!this->regs->in_reset()) {
|
||||
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;
|
||||
});
|
||||
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.data=val;
|
||||
if(regs->r_rxctrl.rxcnt<=rx_fifo.num_available()){
|
||||
regs->r_ip.rxwm=1;
|
||||
update_irq();
|
||||
}
|
||||
}
|
||||
data = reg.get()®.rdmask;
|
||||
}
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
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() {
|
||||
if(write_to_ws.get_value()) {
|
||||
LOG(TRACE)<<"Adding WS handler for "<<(std::string{"/ws/"}+name());
|
||||
@ -95,19 +133,74 @@ void uart::reset_cb() {
|
||||
}
|
||||
|
||||
void uart::transmit_data() {
|
||||
if(regs->r_txdata.data != '\r') queue.push_back(regs->r_txdata.data);
|
||||
if (queue.size() >> 0 && (regs->r_txdata.data == '\n' || regs->r_txdata.data == 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();
|
||||
uint8_t txdata;
|
||||
sc_core::sc_time delay(SC_ZERO_TIME);
|
||||
tlm::tlm_phase phase(tlm::BEGIN_REQ);
|
||||
tlm::tlm_signal_gp<> gp;
|
||||
gp.set_command(tlm::TLM_WRITE_COMMAND);
|
||||
gp.set_value(true);
|
||||
tx_o->nb_transport_fw(gp, phase, delay);
|
||||
while(true){
|
||||
wait(tx_fifo.data_written_event());
|
||||
while(tx_fifo.nb_read(txdata)){
|
||||
regs->r_txdata.full=tx_fifo.num_free()==0;
|
||||
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 */
|
||||
|
||||
|
@ -697,7 +697,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const iss::addr_t &addr, unsigned leng
|
||||
} break;
|
||||
case traits<BASE>::RES: {
|
||||
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);
|
||||
atomic_reservation.erase(addr.val);
|
||||
} else
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit b50df83ebfbf06299613a973552856954ed383c1
|
||||
Subproject commit 019a04132a8beb7fcab24d504e3347ca0771ea5f
|
@ -1,11 +1,13 @@
|
||||
{
|
||||
"i_simple_system":{
|
||||
"i_uart0":{
|
||||
"write_to_ws": true
|
||||
},
|
||||
"i_uart1":{
|
||||
"write_to_ws": false
|
||||
},
|
||||
"i_gpio0.write_to_ws": true
|
||||
"i_platform": {
|
||||
"i_uart0":{
|
||||
"write_to_ws": false
|
||||
},
|
||||
"i_uart1":{
|
||||
"write_to_ws": false
|
||||
},
|
||||
"i_gpio0.write_to_ws": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user