RISC是“精简指令集计算机”的缩写:Reduced Instruction Set Computing RISC)。RISC的指令系统相对简单,它只要求硬件执行很有限且最常用的那部分指令,大部分复杂的操作则使用成熟的编译技术,由简单指令合成。RISC结构采用精简的,长短划一的指令集,使大多数的操作获得了尽可能高的效率。某些在传统结构中要用多周期指令实现的操作,在RISC结构中,通过机器语言编程,就代之以多条单周期指令了。【参考1】
接下来用一个例子来说明二者的区别。
假设我们有一个这样的计算机:内存是一个 6×4 的数组, 有A-F 6个寄存器。
对于 CISC 来说,如果想完成内存中2个数值的相乘的操作,可以直接使用下面的指令:
MULT 2:3,5:2
这里的 MULT 就是一个“复杂指令”。 进一步,如果设定变量 x 为内存 2:3 中的值。 y 为内存 5:2 的值,上面的指令就可以理解为C语言的 x=x*y。
如果用 RISC 来完成,那么需要写成如下的指令:
LOAD A, 2:3 LOAD B, 5:2 PROD A, B STORE 2:3, A
从这个结果上来看,RISC 效率更低,因为需要执行更多的代码,使用更多的内存。但是实际上 RISC 的指令通常只需要1个机器周期来完成,所以整体上消耗时间和CISC 的 MULT 指令相同,另外因为 RISC 机器码指令长度相同,执行时只需要一个机器周期所以更适合流水线方式执行(我的理解是方便硬件预读取和判断)。【参考2】
虽然 Intel X86 CPU 是 CISC 的典型代表,但是它的内部也存在RISC 的设计概念。所有的操作都会被分解为微指令再执行。微指令是典型的 CISC 的指令。
USB 键盘鼠标是最常见的输入设备了,之前如果想在 Arduino 上使用这两种设备,一个可行的方法是使用 USB Host Shield。这种方法的缺点是:成本比较高(MAX3421E芯片贵),操作复杂(SPI接口),资料少。因为这样缺点的存在,USB Host Shield 在使用上存在诸多不便。偶然间看到USB键鼠转串口通讯控制芯片CH9350(南京沁恒,WCH,阅读过我文章的朋友都知道CH340 也是他们家的产品)。这款能够将 USB 键盘鼠标的有效信息转为串口数据。芯片特点如下:
MRedef.c(20): error C2220: warning treated as error - no 'object' file generated
MRedef.c(20): warning C4005: 'SUM': macro redefinition
MRedef.c(19): note: see previous definition of 'SUM'
解决方法是在文件头部加入 Disable 这个 Warning 的指令如下:
#pragma warning (disable : 4005)
完整的代码如下:
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#pragma warning (disable : 4005)
/*
MRedef.c(20): error C2220: warning treated as error - no 'object' file generated
MRedef.c(20): warning C4005: 'SUM': macro redefinition
MRedef.c(19): note: see previous definition of 'SUM'
*/
#define SUM(a,b) a+b
#define SUM(a,b) a*b
/***
Print a welcoming message.
Establishes the main structure of the application.
@retval 0 The application exited normally.
@retval Other An error occurred.
***/
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
int c =3,d=4;
Print(L"Hello there fellow Programmer.\n");
Print(L"Welcome to the world of EDK II.\n");
Print(L"Macro test %d\n",SUM(c,d));
return(0);
}
//
// Support for variable argument lists in freestanding edk2 modules.
//
// For modules that use the ISO C library interfaces for variable
// argument lists, refer to "StdLib/Include/stdarg.h".
//
// VA_LIST - typedef for argument list.
// VA_START (VA_LIST Marker, argument before the ...) - Init Marker for use.
// VA_END (VA_LIST Marker) - Clear Marker
// VA_ARG (VA_LIST Marker, var arg type) - Use Marker to get an argument from
// the ... list. You must know the type and pass it in this macro. Type
// must be compatible with the type of the actual next argument (as promoted
// according to the default argument promotions.)
// VA_COPY (VA_LIST Dest, VA_LIST Start) - Initialize Dest as a copy of Start.
//
// Example:
//
// UINTN
// EFIAPI
// ExampleVarArg (
// IN UINTN NumberOfArgs,
// ...
// )
// {
// VA_LIST Marker;
// UINTN Index;
// UINTN Result;
//
// //
// // Initialize the Marker
// //
// VA_START (Marker, NumberOfArgs);
// for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) {
// //
// // The ... list is a series of UINTN values, so sum them up.
// //
// Result += VA_ARG (Marker, UINTN);
// }
//
// VA_END (Marker);
// return Result;
// }
//
// Notes:
// - Functions that call VA_START() / VA_END() must have a variable
// argument list and must be declared EFIAPI.
// - Functions that call VA_COPY() / VA_END() must be declared EFIAPI.
// - Functions that only use VA_LIST and VA_ARG() need not be EFIAPI.
//
根据上面的代码,编写测试例子如下:
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
UINTN
EFIAPI
VarSum (
IN UINTN NumberOfArgs,
...
)
{
VA_LIST Marker;
UINTN Index;
UINTN Result;
//
// Initialize the Marker
//
VA_START (Marker, NumberOfArgs);
for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) {
//
// The ... list is a series of UINTN values, so sum them up.
//
Result += VA_ARG (Marker, UINTN);
}
VA_END (Marker);
return Result;
}
UINTN
EFIAPI
VarString (
IN UINTN NumberOfArgs,
...
)
{
VA_LIST Marker;
UINTN Index;
UINTN Result;
//
// Initialize the Marker
//
VA_START (Marker, NumberOfArgs);
for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) {
//
// The ... list is a series of UINTN values, so sum them up.
//
//Result += VA_ARG (Marker, UINTN);
Print(L"String %d: %s\n",Index,VA_ARG (Marker, CHAR16*));
}
VA_END (Marker);
return Result;
}
/***
Print a welcoming message.
Establishes the main structure of the application.
@retval 0 The application exited normally.
@retval Other An error occurred.
***/
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
Print(L"VarSum(2,1,2)=%d\n",VarSum(2,1,2));
Print(L"VarSum(3,1,2,3)=%d\n",VarSum(3,1,2,3));
Print(L"VarSum(4,1,2,3,4)=%d\n",VarSum(4,1,2,3,4));
Print(L"VarString(4,L\"abcde\",L\"1234\",L\"efgh\",L\"5678\")\n",
VarString(4,L"abcde",L"1234",L"efgh",L"5678"));
return(0);
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management;
using System.Collections;
namespace ConsoleApplication29
{
class Program
{
private static void GatherUsbInformation()
{
var mos = new ManagementObjectSearcher("select DeviceID from Win32_PnPEntity");
var mbos = new ArrayList(mos.Get());
var data = new Dictionary<string, string[]>();
for (var i = 0; i < mbos.Count; i++)
{
var managementBaseObject = mbos[i] as ManagementBaseObject;
if (managementBaseObject == null)
{
continue;
}
var deviceId = managementBaseObject.Properties["DeviceID"].Value as string;
if (deviceId == null || !deviceId.StartsWith("USB"))
{
continue;
}
if (!data.ContainsKey(deviceId))
{
data.Add(deviceId, new string[8]);
}
else if (data.ContainsKey(deviceId))
{
continue;
}
var mo = managementBaseObject as ManagementObject;
var inParams = mo.GetMethodParameters("GetDeviceProperties");
var result = mo.InvokeMethod(
"GetDeviceProperties",
inParams,
new InvokeMethodOptions()
);
if (result?.Properties["deviceProperties"].Value == null)
{
continue;
}
foreach (var deviceProperties in result.Properties["deviceProperties"].Value as ManagementBaseObject[])
{
var keyName = deviceProperties.Properties["KeyName"].Value as string;
var value = deviceProperties.Properties["Data"].Value as string;
if (string.IsNullOrWhiteSpace(value) || string.IsNullOrWhiteSpace(keyName))
{
//MachineInformationGatherer.Logger.LogTrace(
// $"KeyName {keyName} or Value {value} was null or whitespace for device ID {deviceId}");
continue;
}
Console.WriteLine(keyName);
Console.WriteLine(value);
switch (keyName)
{
case "DEVPKEY_Device_BusReportedDeviceDesc":
{
data[deviceId][0] = value;
break;
}
case "DEVPKEY_Device_DriverDesc":
{
data[deviceId][1] = value;
break;
}
case "DEVPKEY_Device_DriverVersion":
{
data[deviceId][2] = value;
break;
}
case "DEVPKEY_Device_DriverDate":
{
var year = int.Parse(value.Substring(0, 4));
var month = int.Parse(value.Substring(4, 2));
var day = int.Parse(value.Substring(6, 2));
var hour = int.Parse(value.Substring(8, 2));
var minute = int.Parse(value.Substring(10, 2));
var second = int.Parse(value.Substring(12, 2));
data[deviceId][3] =
new DateTime(year, month, day, hour, minute, second).ToString();
break;
}
case "DEVPKEY_Device_Class":
{
data[deviceId][4] = value;
break;
}
case "DEVPKEY_Device_DriverProvider":
{
data[deviceId][5] = value;
break;
}
case "DEVPKEY_NAME":
{
data[deviceId][6] = value;
break;
}
case "DEVPKEY_Device_Manufacturer":
{
data[deviceId][7] = value;
break;
}
case "DEVPKEY_Device_Children":
{
var children = deviceProperties.Properties["DEVPKEY_Device_Children"];
if (children.Value != null)
{
if (children.IsArray)
{
foreach (var child in children.Value as string[])
{
mos.Query = new ObjectQuery(
$"select * from Win32_PnPEntity where DeviceID = {child}");
var childs = mos.Get();
foreach (var child1 in childs)
{
mbos.Add(child1);
}
}
}
}
break;
}
}
}
}
}
static void Main(string[] args)
{
GatherUsbInformation();
Console.ReadKey();
}
}
}