【RISC-V设计-14】- RISC-V处理器设计K0A之打印输出

发布于:2024-08-22 ⋅ 阅读:(27) ⋅ 点赞:(0)

【RISC-V设计-14】- RISC-V处理器设计K0A之打印输出

1.简介

本文将详细阐述如何利用 printf 来打印字符串,在此过程中使用了一个开源的库 xprintfxprintf 是一个紧凑的字符串 I/O 库,它非常适用于程序存储器不足以用于常规 printf 函数的微型微控制器。通过调用 xprintf 函数成功输出了“Hello RISC-V World!”,同时还对该库的使用方法以及如何进行编译等内容加以介绍。xprintf库的地址为:http://elm-chan.org/fsw/strf/xprintf.html,下载后使将使用xprintf.cxprintf.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!"到终端显示。


网站公告

今日签到

点亮在社区的每一天
去签到