554 lines
21 KiB
C#
Raw Normal View History

2019-02-16 15:02:27 +08:00
using System;
using System.IO;
2019-03-03 02:42:38 +08:00
using System.IO.Ports;
2019-02-16 15:02:27 +08:00
using System.Drawing;
using System.Text;
using System.Windows.Forms;
2019-03-03 02:42:38 +08:00
2019-02-16 15:02:27 +08:00
namespace USTCRVSoC_tool
{
public partial class MainForm : Form
{
2019-03-03 02:42:38 +08:00
private const string RISCV_TOOLS_PATH = ".\\riscv32-elf-tools-windows\\"; // RISC-V工具链的路径
2019-02-16 15:02:27 +08:00
2019-03-03 02:42:38 +08:00
#region
private uint _userPortCount;
private uint userPortCount // 接收字节数计数属性
2019-02-16 15:02:27 +08:00
{
get
{
return _userPortCount;
}
set
{
_userPortCount = value;
changeCountText(String.Format("接收: {0:D} B", _userPortCount));
2019-02-16 15:02:27 +08:00
}
}
2019-03-03 02:42:38 +08:00
#endregion
2019-02-16 15:02:27 +08:00
2019-03-03 02:42:38 +08:00
public MainForm() // 窗体构造函数
2019-02-16 15:02:27 +08:00
{
InitializeComponent();
InitializeCurrentPort(null, null);
}
2019-03-03 02:42:38 +08:00
#region
2019-02-16 15:02:27 +08:00
private void InitializeCurrentPort(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames();
portSelectionBox.Items.Clear();
portSelectionBox.Items.AddRange(ports);
if (portSelectionBox.Items.Count > 0)
{
portSelectionBox.SelectedIndex = 0;
}
else
{
compilePromptText.Text = "未找到串口,请插入设备,或者检查串口驱动是否安装";
}
}
2019-03-03 02:42:38 +08:00
#endregion
2019-02-16 15:02:27 +08:00
2019-03-03 02:42:38 +08:00
#region
2019-02-16 15:02:27 +08:00
private void fileSelectionBtn_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.InitialDirectory = ".\\"; //注意这里写路径时要用c:\\而不是c:\
openFileDialog.Filter = "汇编语言文件|*.S";
openFileDialog.RestoreDirectory = true;
openFileDialog.FilterIndex = 1;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
fileSelectionText.Text = openFileDialog.FileName;
try
{
codeText.Text = System.IO.File.ReadAllText(openFileDialog.FileName);
compilePromptText.Text = "已打开文件";
saveBtn.Enabled = true;
}
catch (Exception ex)
{
compilePromptText.Text = "打开文件失败\n " + ex.Message;
}
}
}
private void saveBtn_Click(object sender, EventArgs e)
{
try
{
System.IO.File.WriteAllText(fileSelectionText.Text, codeText.Text);
compilePromptText.Text = " 已保存文件";
}
catch (Exception ex)
{
compilePromptText.Text = " 保存文件失败\r\n" + ex.Message;
}
}
private void otherSaveBtn_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.InitialDirectory = ".\\"; //注意这里写路径时要用c:\\而不是c:\
saveFileDialog.Filter = "汇编语言文件|*.S";
saveFileDialog.RestoreDirectory = true;
saveFileDialog.FilterIndex = 1;
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
fileSelectionText.Text = saveFileDialog.FileName;
try
{
System.IO.File.WriteAllText(fileSelectionText.Text, codeText.Text);
compilePromptText.Text = "已保存文件";
}
catch (Exception ex)
{
compilePromptText.Text = "保存文件失败\n " + ex.Message;
}
}
}
2019-03-03 02:42:38 +08:00
#endregion
2019-02-16 15:02:27 +08:00
2019-03-03 02:42:38 +08:00
#region
public bool RunCmd(string path, string command, ref string msg) // 调用 CMD 运行一个命令
2019-02-16 15:02:27 +08:00
{
try
{
msg = ">" + command + "\r\n\r\n";
System.Diagnostics.Process pro = new System.Diagnostics.Process();
pro.StartInfo.FileName = "cmd.exe";
pro.StartInfo.CreateNoWindow = true; // 不创建新窗口
pro.StartInfo.UseShellExecute = false; // 不启用shell启动进程
pro.StartInfo.RedirectStandardInput = true; // 重定向输入
pro.StartInfo.RedirectStandardOutput = true; // 重定向标准输出
pro.StartInfo.RedirectStandardError = true;
pro.StartInfo.StandardErrorEncoding = System.Text.UTF8Encoding.UTF8;
pro.StartInfo.StandardOutputEncoding = System.Text.UTF8Encoding.UTF8; // 重定向错误输出
pro.StartInfo.WorkingDirectory = path;
pro.Start(); //开启cmd
pro.StandardInput.WriteLine(command);
pro.StandardInput.AutoFlush = true;
pro.StandardInput.WriteLine("exit"); //若是运行时间短可加入此命令
pro.WaitForExit();//若运行时间长,使用这个,等待程序执行完退出进程
string errorStr = pro.StandardError.ReadToEnd();
msg += errorStr;
pro.Close();
return errorStr.Trim().Length == 0;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\r\n请确保工具链目录与本程序在同一目录下");
return false;
}
}
2019-03-03 02:42:38 +08:00
private string dumpBin(string bin_file_path) // 读取汇编出的.bin 文件并调整字节序、转换为一行一行的指令
2019-02-16 15:02:27 +08:00
{
StringBuilder strbuild = new StringBuilder();
byte[] bin = System.IO.File.ReadAllBytes(bin_file_path);
for (int i = 0; i < bin.Length - 3; i += 4)
{
for (int j = 3; j >= 0; j--)
strbuild.Append(bin[i + j].ToString("x2"));
strbuild.AppendLine();
}
return strbuild.ToString();
}
2019-03-03 02:42:38 +08:00
private void compileBtn_Click(object sender, EventArgs e) // 点击“汇编”按钮时完成一系列CMD命令并把编译结果读入到 binText 这个控件里
2019-02-16 15:02:27 +08:00
{
bool stat;
string msg = "";
string asm_command = "riscv32-elf-as " + fileSelectionText.Text + " -o compile_tmp.o -march=rv32i";
string ld_command = "riscv32-elf-ld compile_tmp.o -o compile_tmp.om";
compilePromptText.Clear();
try
{
System.IO.File.WriteAllText(fileSelectionText.Text, codeText.Text);
}
catch (Exception ex)
{
compilePromptText.Text = "保存文件失败\n " + ex.Message;
return;
}
stat = RunCmd(RISCV_TOOLS_PATH, asm_command, ref msg);
compilePromptText.AppendText(msg);
if (!stat)
{
compilePromptText.AppendText(" *** 编译出错! ***");
return;
}
stat = RunCmd(RISCV_TOOLS_PATH, ld_command, ref msg);
compilePromptText.AppendText(msg);
if (!stat)
{
compilePromptText.AppendText(" *** 生成om文件出错! ***");
return;
}
stat = RunCmd(RISCV_TOOLS_PATH, "del compile_tmp.o", ref msg);
compilePromptText.AppendText(msg);
if (!stat)
{
compilePromptText.AppendText(" *** 删除中间文件出错! ***");
return;
}
stat = RunCmd(RISCV_TOOLS_PATH, "riscv32-elf-objcopy -O binary compile_tmp.om compile_tmp.bin", ref msg);
compilePromptText.AppendText(msg);
if (!stat)
{
compilePromptText.AppendText(" *** 生成bin文件出错! ***");
return;
}
stat = RunCmd(RISCV_TOOLS_PATH, "del compile_tmp.om", ref msg);
compilePromptText.AppendText(msg);
if (!stat)
{
compilePromptText.AppendText(" *** 删除中间文件出错! ***");
return;
}
try
{
binText.Text = dumpBin(RISCV_TOOLS_PATH + "compile_tmp.bin");
compilePromptText.AppendText(" *** 编译完成! ***");
}
catch
{
compilePromptText.AppendText(" *** 读取bin文件出错! ***");
return;
}
}
2019-03-03 02:42:38 +08:00
#endregion
#region Verilog InstrROM
private const string VerilogHead = "module instr_rom(\n input logic clk, rst_n,\n naive_bus.slave bus\n);\nlocalparam INSTR_CNT = 30'd";
private const string VerilogMid = ";\nwire [0:INSTR_CNT-1] [31:0] instr_rom_cell = {\n";
private const string VerilogTail = "};\n\nlogic [29:0] cell_rd_addr;\n\nassign bus.rd_gnt = bus.rd_req;\nassign bus.wr_gnt = bus.wr_req;\nassign cell_rd_addr = bus.rd_addr[31:2];\nalways @ (posedge clk or negedge rst_n)\n if(~rst_n)\n bus.rd_data <= 0;\n else begin\n if(bus.rd_req)\n bus.rd_data <= (cell_rd_addr>=INSTR_CNT) ? 0 : instr_rom_cell[cell_rd_addr];\n else\n bus.rd_data <= 0;\n end\n\nendmodule\n\n";
2019-02-16 15:02:27 +08:00
private string genVerilogRom()
{
StringBuilder strBuilder = new StringBuilder();
int index = 0;
string[] lines = binText.Text.Trim().Split();
for (int idx = 0; idx < lines.Length; idx++)
2019-02-16 15:02:27 +08:00
{
string line = lines[idx];
2019-02-16 15:02:27 +08:00
string hex_num = line.Trim();
if (hex_num.Length <= 0)
continue;
if (idx < lines.Length - 2)
strBuilder.Append(String.Format(" 32'h{1:S}, // 0x{0:x8}\n", index * 4, hex_num));
else
strBuilder.Append(String.Format(" 32'h{1:S} // 0x{0:x8}\n", index * 4, hex_num));
2019-02-16 15:02:27 +08:00
index += 1;
}
strBuilder.Insert(0, VerilogMid);
strBuilder.Insert(0, index.ToString());
strBuilder.Insert(0, VerilogHead);
strBuilder.Append(VerilogTail);
return strBuilder.ToString();
}
private void saveVerilog_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.InitialDirectory = ".\\"; //注意这里写路径时要用c:\\而不是c:\
saveFileDialog.Filter = "SystemVerilog源文件|*.sv";
saveFileDialog.RestoreDirectory = true;
saveFileDialog.FilterIndex = 1;
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
try
{
System.IO.File.WriteAllText(saveFileDialog.FileName, genVerilogRom());
compilePromptText.Text = "已保存 Verilog ROM 文件";
}
catch (Exception ex)
{
compilePromptText.Text = "保存 Verilog ROM 文件失败\r\n" + ex.Message;
}
}
}
2019-03-03 02:42:38 +08:00
#endregion
2019-02-16 15:02:27 +08:00
2019-03-03 02:42:38 +08:00
#region
private bool serialSessionA(string send, ref string response) // 发送一个命令并得到响应字符串
2019-02-16 15:02:27 +08:00
{
return serialSessionTry(send, ref response, "");
}
2019-03-03 02:42:38 +08:00
private bool serialSessionB(string send, string respectResponse) // 发送一个命令并等待指定的响应字符串到来
2019-02-16 15:02:27 +08:00
{
string response = "";
return serialSessionTry(send, ref response, respectResponse);
}
2019-03-03 02:42:38 +08:00
private bool serialSessionTry(string send, ref string response, string respectResponse, int try_time = 3) // 多次请求全部失败时,返回失败,否则返回成功
2019-02-16 15:02:27 +08:00
{
for (int i = 0; i < try_time; i++)
2019-03-03 02:42:38 +08:00
{
try { serialPort.ReadExisting(); }// 清空接收缓冲区
catch { }
if (serialSend(send))
2019-03-03 02:42:38 +08:00
{
if (serialRead(ref response, respectResponse))
return true;
2019-03-03 02:42:38 +08:00
}
}
2019-02-16 15:02:27 +08:00
compilePromptText.AppendText(" *** 串口调试多次尝试失败 ***\r\n");
return false;
}
private bool serialSend(string send)
2019-02-16 15:02:27 +08:00
{
compilePromptText.AppendText("send: " + send);
try
{
serialPort.Write(send + "\n");
}
catch (Exception ex)
{
compilePromptText.AppendText(" " + ex.Message + "\r\n");
return false;
}
return true;
}
private bool serialRead(ref string response, string respectResponse)
{
try
2019-02-16 15:02:27 +08:00
{
for (int i = 0; i < 8; i++)
{
response = serialPort.ReadLine().Trim();
bool is_respect = respectResponse.Equals("") || respectResponse.Equals(response);
if (is_respect)
{
compilePromptText.AppendText(" response: " + response + "\r\n");
return true;
}
}
2019-02-16 15:02:27 +08:00
}
catch (Exception ex)
2019-02-16 15:02:27 +08:00
{
compilePromptText.AppendText(" " + ex.Message + "\r\n");
2019-02-16 15:02:27 +08:00
return false;
}
compilePromptText.AppendText(" response: *** 超时 ***\r\n" + response);
return false;
2019-02-16 15:02:27 +08:00
}
2019-03-03 02:42:38 +08:00
#endregion
2019-02-16 15:02:27 +08:00
2019-03-03 02:42:38 +08:00
#region
private bool refreshSerial()
2019-02-16 15:02:27 +08:00
{
2019-03-03 02:42:38 +08:00
if (serialPort.IsOpen)
serialPort.Close();
try
{
serialPort.PortName = portSelectionBox.Text;
serialPort.Open();
}
catch (Exception ex)
{
compilePromptText.AppendText(" *** 打开串口出错 ***\r\n " + ex.Message);
refreshPortStatus();
return false;
}
return true;
2019-02-16 15:02:27 +08:00
}
2019-03-03 02:42:38 +08:00
private void refreshPortStatus()
{
if (serialPort.IsOpen)
userPortOpenCloseBtn.Text = "关闭";
else
userPortOpenCloseBtn.Text = "打开";
}
private void userPortOpenCloseBtn_Click(object sender, EventArgs e)
{
if (userPortOpenCloseBtn.Text == "打开")
{
compilePromptText.Clear();
refreshSerial();
serialSessionB("s", "debug");
serialSessionB("o", "user");
}
else
{
serialPort.Close();
}
refreshPortStatus();
}
#endregion
2019-02-16 15:02:27 +08:00
2019-03-03 02:42:38 +08:00
#region
private void programBtn_Click(object sender, EventArgs e) // 烧录程序
2019-02-16 15:02:27 +08:00
{
2019-03-03 02:42:38 +08:00
enableUartDisplay = false;
userPortTextBox.Clear();
2019-02-16 15:02:27 +08:00
compilePromptText.Clear();
uint boot_addr;
try
{
2019-03-03 02:42:38 +08:00
boot_addr = Convert.ToUInt32(bootAddrTextBox.Text, 16);
2019-02-16 15:02:27 +08:00
}
catch (Exception ex)
{
compilePromptText.AppendText(" *** Boot Addr格式有误 ***\r\n " + ex.Message);
return;
}
2019-03-03 02:42:38 +08:00
if (!refreshSerial())
return;
if (!serialSessionB("s", "debug"))
2019-02-16 15:02:27 +08:00
return;
uint index = 0;
foreach (string line in binText.Text.Split())
{
string hex_num = line.Trim();
if (hex_num.Length <= 0)
continue;
string send_str = String.Format("{0:x8} {1:S}", boot_addr + index * 4, hex_num);
index++;
if (!serialSessionB(send_str, "wr done"))
return;
}
if (!serialSessionB(string.Format("r{0:x8}", boot_addr), "rst done"))
return;
2019-03-03 02:42:38 +08:00
compilePromptText.AppendText(" *** 烧录完成 ***\r\n");
try { serialPort.ReadExisting(); }// 清空接收缓冲区
catch { }
userPortTextBox.Clear();
enableUartDisplay = true;
2019-02-16 15:02:27 +08:00
}
2019-03-03 02:42:38 +08:00
#endregion
2019-02-16 15:02:27 +08:00
2019-03-03 02:42:38 +08:00
#region DUMP内存
private void DUMP内存_Click(object sender, EventArgs e) // 查看内存
2019-02-16 15:02:27 +08:00
{
2019-03-03 02:42:38 +08:00
enableUartDisplay = false;
userPortTextBox.Clear();
compilePromptText.Clear();
uint start, len;
try
2019-02-16 15:02:27 +08:00
{
2019-03-03 02:42:38 +08:00
start = Convert.ToUInt32(.Text, 16);
len = Convert.ToUInt32(.Text, 16);
2019-02-16 15:02:27 +08:00
}
2019-03-03 02:42:38 +08:00
catch (Exception ex)
{
2019-03-03 02:42:38 +08:00
compilePromptText.AppendText(" *** 起始地址格式有误 ***\r\n " + ex.Message);
return;
}
2019-03-03 02:42:38 +08:00
start = 4 * (start / 4); // 起始地址自动与4对齐
if (len > 0x1000)
{
compilePromptText.AppendText(" *** 长度不能大于0x1000 ***\r\n ");
return;
}
len /= 4;
2019-03-03 02:42:38 +08:00
if (!refreshSerial())
return;
if (!serialSessionB("s", "debug"))
return;
.Clear();
uint index = 0;
for (index = 0; index < len; index++)
{
string send_str = String.Format("{0:x8}", start + index * 4);
string response = "";
if (!serialSessionA(send_str, ref response))
return;
.AppendText(String.Format("{0:x8} : {1:S}\r\n", start + index * 4, response.Trim()));
}
serialSessionB("o", "user");
compilePromptText.AppendText(" *** Dump内存完成 ***\r\n");
try { serialPort.ReadExisting(); }// 清空接收缓冲区
catch { }
userPortTextBox.Clear();
enableUartDisplay = true;
2019-02-16 15:02:27 +08:00
}
2019-03-03 02:42:38 +08:00
#endregion
2019-02-16 15:02:27 +08:00
2019-03-03 02:42:38 +08:00
#region
bool enableUartDisplay = true;
2019-02-16 15:02:27 +08:00
public delegate void changeTextHandler(object str);
private void appendUserPortText(object str)
{
if (userPortTextBox.InvokeRequired == true)
{
changeTextHandler ct = new changeTextHandler(appendUserPortText);
userPortTextBox.Invoke(ct, new object[] { str });
}
else
{
userPortTextBox.AppendText(str.ToString());
}
}
private void changeCountText(object str)
{
if (UserPortRecvCountLabel.InvokeRequired == true)
{
changeTextHandler ct = new changeTextHandler(changeCountText);
UserPortRecvCountLabel.Invoke(ct, new object[] { str });
}
else
{
UserPortRecvCountLabel.Text = str.ToString();
}
}
private void userPortClearBtn_Click(object sender, EventArgs e)
{
userPortTextBox.Clear();
}
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
2019-03-03 02:42:38 +08:00
if (enableUartDisplay)
{
2019-03-03 02:42:38 +08:00
SerialPort sp = (SerialPort)sender;
try
{
2019-03-03 02:42:38 +08:00
string recvdata = sp.ReadExisting();
if (userPortShowHex.Checked)
{
2019-03-03 02:42:38 +08:00
StringBuilder sb = new StringBuilder();
foreach (byte ch in recvdata)
{
sb.Append(String.Format("{0:X2} ", ch));
}
appendUserPortText(sb.ToString());
}
2019-03-03 02:42:38 +08:00
else
{
appendUserPortText(recvdata);
}
userPortCount += (uint)recvdata.Length;
}
2019-03-03 02:42:38 +08:00
catch { }
}
}
2019-03-03 02:42:38 +08:00
#endregion
2019-02-16 15:02:27 +08:00
}
}