まず、デザイン上にはシリアルコンソールとして以下のインタフェースが定義されている。
//------------------------------------------------------------------------------ // Module //------------------------------------------------------------------------------ module sim ( output wire sim_trace, input wire sys_clk, output wire serial_source_valid, input wire serial_source_ready, output wire [7:0] serial_source_data, input wire serial_sink_valid, output wire serial_sink_ready, input wire [7:0] serial_sink_data );
おそらく、serial_sink_xxx
がシリアルの入力で、serial_source_xxx
がシリアルの出力になるのだろう。
このインタフェースは、以下のC言語の実装により接続されているように見える。
build/sim/gateware/sim_init.cpp
extern "C" void litex_sim_init(void **out) { ... serial[0].signal = &sim->serial_source_valid; serial[1].signal = &sim->serial_source_ready; serial[2].signal = &sim->serial_source_data; serial[3].signal = &sim->serial_sink_valid; serial[4].signal = &sim->serial_sink_ready; serial[5].signal = &sim->serial_sink_data; litex_sim_register_pads(serial, (char*)"serial", 0); }
この時の、litex_sim_register_pads()
はLiteXのシミュレーション環境に、このシリアルデバイスをパッドとして登録する、ということだと思う。
おそらくこのイベントはserial2console
が管理している。
litex/build/sim/core/modules/serial2console/serial2console.c
static int serial2console_add_pads(void *sess, struct pad_list_s *plist) { int ret = RC_OK; struct session_s *s = (struct session_s*) sess; struct pad_s *pads; if(!sess || !plist) { ret = RC_INVARG; goto out; } pads = plist->pads; if(!strcmp(plist->name, "serial")) { litex_sim_module_pads_get(pads, "sink_data", (void**)&s->rx); litex_sim_module_pads_get(pads, "sink_valid", (void**)&s->rx_valid); litex_sim_module_pads_get(pads, "sink_ready", (void**)&s->rx_ready); litex_sim_module_pads_get(pads, "source_data", (void**)&s->tx); litex_sim_module_pads_get(pads, "source_valid", (void**)&s->tx_valid); litex_sim_module_pads_get(pads, "source_ready", (void**)&s->tx_ready); } if(!strcmp(plist->name, "sys_clk")) litex_sim_module_pads_get(pads, "sys_clk", (void**) &s->sys_clk); out: return ret; }
入力を受け付けるイベントの生成はこの辺。
static int serial2console_new(void **sess, char *args) { int ret = RC_OK; struct timeval tv = {1, 0}; struct session_s *s = NULL; if(!sess) { ret = RC_INVARG; goto out; } s = (struct session_s*) malloc(sizeof(struct session_s)); if(!s) { ret=RC_NOENMEM; goto out; } memset(s, 0, sizeof(struct session_s)); s->ev = event_new(base, fileno(stdin), EV_READ | EV_PERSIST , event_handler, s); event_add(s->ev, &tv); out: *sess = (void*) s; return ret; }
イベントハンドラにprintf()を入れてみても、正しく動作しているように見える。 そうすると、何かしらハードウェア側の動作がおかしい、ということになるか?