【RISC-V设计-14】- RISC-V处理器设计K0A之打印输出
文章目录
- 【RISC-V设计-14】- RISC-V处理器设计K0A之打印输出
- 1.简介
- 2.验证用例
- 3.软件代码
- 4.链接脚本
- 5.编译脚本
- 6.仿真结果
- 6.1 复位结束
- 6.2 运行成功
- 6.3 终端打印
- 7.总结
1.简介
本文将详细阐述如何利用 printf
来打印字符串,在此过程中使用了一个开源的库 xprintf
。xprintf
是一个紧凑的字符串 I/O 库,它非常适用于程序存储器不足以用于常规 printf 函数的微型微控制器。通过调用 xprintf
函数成功输出了“Hello RISC-V World!”,同时还对该库的使用方法以及如何进行编译等内容加以介绍。xprintf
库的地址为:http://elm-chan.org/fsw/strf/xprintf.html,下载后使将使用xprintf.c
和xprintf.h
两个文件。
2.验证用例
// -------------------------------------------------------------------------------------------------
// Copyright 2024 Kearn Chen, kearn.chen@aliyun.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------
// Description :
// 1. Run Hello World!
// -------------------------------------------------------------------------------------------------
task initcase;
load_instr("hello_world_test/hello_world_test.bin");
endtask
task testcase;
#2_000_000;
endtask
在验证用例中,任务initcase
加载Bin文件到仿真模型中,任务testcase
延迟2毫秒,等待CPU执行完软件指令。
3.软件代码
// -------------------------------------------------------------------------------------------------
// Copyright 2024 Kearn Chen, kearn.chen@aliyun.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------
#include "xprintf.h"
void xfunc_output_callback(int c)
{
*((volatile unsigned int *)0xc0000) = c;
}
void simulation_finish(void)
{
*((volatile unsigned int *)0xc0004) = 0x12345678;
}
int main(void)
{
xfunc_output = xfunc_output_callback;
xprintf("Hello RISC-V World!\n");
simulation_finish();
while(1);
}
上述代码中,首先是初始化打印输出的回调函数,在回调函数中,将要输出的字符写入地址0xc0000寄存器中,这个寄存器在之前的文章【RISC-V设计-12】- RISC-V处理器设计K0A之验证环境中第4部分有描述,写入此寄存器的数据会存入到一个队列里面,在遇到输出字符为\n
时,将整个队列内的输出到终端。在输出完字符后,调用simulation_finish
函数,仿真运行结束。在xprintf
库中,有一些宏定义,如下所示,根据需要可以打开和关闭。
#define XF_USE_OUTPUT 1 /* 1: Enable output functions */
#define XF_CRLF 0 /* 1: Convert \n ==> \r\n in the output char */
#define XF_USE_DUMP 0 /* 1: Enable put_dump function */
#define XF_USE_LLI 0 /* 1: Enable long long integer in size prefix ll */
#define XF_USE_FP 0 /* 1: Enable support for floating point in type e and f */
#define XF_DPC '.' /* Decimal separator for floating point */
#define XF_USE_INPUT 0 /* 1: Enable input functions */
#define XF_INPUT_ECHO 0 /* 1: Echo back input chars in xgets function */
4.链接脚本
ENTRY( _start )
__stack_size = 2048;
PROVIDE( _stack_size = __stack_size );
MEMORY
{
ROM (rx) : ORIGIN = 0x00000, LENGTH = 512K
RAM (xrw) : ORIGIN = 0x80000, LENGTH = 256K
}
SECTIONS
{
.init :
{
_sinit = .;
. = ALIGN(4);
KEEP(*(SORT_NONE(.init)))
. = ALIGN(4);
_einit = .;
} >ROM
.text :
{
. = ALIGN(4);
*(.text)
*(.text.*)
*(.rodata)
*(.rodata*)
*(.gnu.linkonce.t.*)
. = ALIGN(4);
} >ROM
.fini :
{
KEEP(*(SORT_NONE(.fini)))
. = ALIGN(4);
} >ROM
PROVIDE( _etext = . );
PROVIDE( _eitcm = . );
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >ROM
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >ROM
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >ROM
.ctors :
{
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >ROM
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >ROM
.dalign :
{
. = ALIGN(4);
PROVIDE(_data_vma = .);
} >RAM AT>ROM
.dlalign :
{
. = ALIGN(4);
PROVIDE(_data_lma = .);
} >ROM
.data :
{
. = ALIGN(4);
*(.gnu.linkonce.r.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.sdata2*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
. = ALIGN(4);
PROVIDE( _edata = .);
} >RAM AT>ROM
.bss :
{
. = ALIGN(4);
PROVIDE( _sbss = .);
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss*)
*(.gnu.linkonce.b.*)
*(COMMON*)
. = ALIGN(4);
PROVIDE( _ebss = .);
} >RAM AT>ROM
PROVIDE( _end = _ebss);
PROVIDE( end = . );
.stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size :
{
PROVIDE( _heap_end = . );
. = ALIGN(4);
PROVIDE(_susrstack = . );
. = . + __stack_size;
PROVIDE( _eusrstack = .);
} >RAM
}
5.编译脚本
# -------------------------------------------------------------------------------------------------
# Copyright 2024 Kearn Chen, kearn.chen@aliyun.com
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -------------------------------------------------------------------------------------------------
PREFIX := riscv-none-embed-
LINKER := ../common/link.ld
OBJECT += ../common/startup.o
OBJECT += ../common/xprintf.o
OBJECT += main.o
CFLAGS := -march=rv32e -mabi=ilp32e -I../common
LFLAGS := -march=rv32e -mabi=ilp32e -T$(LINKER) -nostartfiles
TARGET := $(notdir $(shell pwd))
all : $(TARGET).asm $(TARGET).bin
%.bin : %.elf
$(PREFIX)objcopy -Obinary $< $@
%.asm : %.elf
$(PREFIX)objdump -D $< > $@
%.elf : $(OBJECT)
$(PREFIX)gcc $(LFLAGS) -o $@ $^
$(PREFIX)size $@
%.o : %.S
$(PREFIX)gcc $(CFLAGS) -c -o $@ $<
%.o : %.c
$(PREFIX)gcc $(CFLAGS) -c -o $@ $<
clean :
@rm -rf *.o *.elf *.asm *.bin ../common/*.o
.PHONY: clean all
.SECONDARY:
上述脚本中所使用的startup.o文件为startup.S文件所编译产生,这个文件在之前的文章【RISC-V设计-09】- RISC-V处理器设计K0A之CIC中第5部分已有介绍,这个文件为RISCV-K0A
的启动文件,同时还具有中断处理的功能。编译结果如下
riscv-none-embed-gcc -march=rv32e -mabi=ilp32e -I../common -c -o ../common/startup.o ../common/startup.S
riscv-none-embed-gcc -march=rv32e -mabi=ilp32e -I../common -c -o ../common/xprintf.o ../common/xprintf.c
riscv-none-embed-gcc -march=rv32e -mabi=ilp32e -I../common -c -o main.o main.c
riscv-none-embed-gcc -march=rv32e -mabi=ilp32e -T../common/link.ld -nostartfiles -o hello_world_test.elf ../common/startup.o ../common/xprintf.o main.o
riscv-none-embed-size hello_world_test.elf
text data bss dec hex filename
3164 0 2056 5220 1464 hello_world_test.elf
riscv-none-embed-objdump -D hello_world_test.elf > hello_world_test.asm
riscv-none-embed-objcopy -Obinary hello_world_test.elf hello_world_test.bin
6.仿真结果
6.1 复位结束
6.2 运行成功
6.3 终端打印
*Verdi* FSDB WARNING: The FSDB file already exists. Overwriting the FSDB file may crash the programs that are using this file.
*Verdi* : Create FSDB file 'novas.fsdb'
*Verdi* : Begin traversing the scopes, layer (0).
*Verdi* : End of traversing.
[MCU_INFO] : Hello RISC-V World!
$finish called from file "../env/slave_model.v", line 136.
$finish at simulation time 43210
7.总结
本文介绍了如何在RISCV-K0A
上使用xprintf
库文件,并通过xprintf
输出了"Hello RISC-V World!"到终端显示。