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
|
@ -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_ */
|
|
@ -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<> {
|
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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
# 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} )
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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,20 +102,23 @@ 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
|
||||||
mtime_evt.cancel();
|
regs->r_mtime+=elapsed_clks;
|
||||||
if (regs->r_mtimecmp > 0)
|
mtime_evt.cancel();
|
||||||
if(regs->r_mtimecmp > regs->r_mtime && clk > sc_core::SC_ZERO_TIME) {
|
if (regs->r_mtimecmp > 0)
|
||||||
sc_core::sc_time next_trigger = (clk * lfclk_mutiplier) * (regs->r_mtimecmp - regs->mtime) - cnt_fraction * clk;
|
if(regs->r_mtimecmp > regs->r_mtime && clk > sc_core::SC_ZERO_TIME) {
|
||||||
LOG(DEBUG)<<"Timer fires at "<< sc_time_stamp()+next_trigger;
|
sc_core::sc_time next_trigger = (clk * lfclk_mutiplier) * (regs->r_mtimecmp - regs->mtime) - cnt_fraction * clk;
|
||||||
mtime_evt.notify(next_trigger);
|
LOG(DEBUG)<<"Timer fires at "<< sc_time_stamp()+next_trigger;
|
||||||
mtime_int_o.write(false);
|
mtime_evt.notify(next_trigger);
|
||||||
} else
|
mtime_int_o.write(false);
|
||||||
mtime_int_o.write(true);
|
} else
|
||||||
last_updt = sc_core::sc_time_stamp();
|
mtime_int_o.write(true);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
last_updt = sc_time_stamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace sysc */
|
} /* namespace sysc */
|
||||||
|
|
|
@ -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> ®, uint32_t data) -> bool {
|
regs->port.set_write_cb([this](scc::sc_register<uint32_t> ®, 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> ®, 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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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() {
|
||||||
|
}
|
||||||
|
|
|
@ -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/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> ®, uint32_t data) -> bool {
|
regs->txdata.set_write_cb([this](scc::sc_register<uint32_t> ®, 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> ®, 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() {}
|
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 */
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -1,11 +1,13 @@
|
||||||
{
|
{
|
||||||
"i_simple_system":{
|
"i_simple_system":{
|
||||||
"i_uart0":{
|
"i_platform": {
|
||||||
"write_to_ws": true
|
"i_uart0":{
|
||||||
},
|
"write_to_ws": false
|
||||||
"i_uart1":{
|
},
|
||||||
"write_to_ws": false
|
"i_uart1":{
|
||||||
},
|
"write_to_ws": false
|
||||||
"i_gpio0.write_to_ws": true
|
},
|
||||||
|
"i_gpio0.write_to_ws": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue