循序渐进,学习开发一个RISC-V 上的操作系统 第 7 章 Hello RVOS练习7.1

标题练 7-1

  • 要求:完全采⽤汇编语⾔重写 code/os/01-helloRVOS,运⾏后在控制台上打印输出 “Hello, RVOS!”
    kernel.S 汇编代码,需关注函数调用的声明
#extern void uart_init(void);
#extern void uart_puts(char *s);
        .extern uart_init
        .extern uart_puts
        .global start_kernel
        .data
display_str:
        .string "Hello, RVOS!"
        .text
start_kernel:
        call uart_init
        la a0, display_str
        call uart_puts
kernel_loop:
        nop
        j kernel_loop
        .end
/*
void start_kernel(void)
{
        uart_init();
        uart_puts("Hello, RVOS!\n");

        while (1) {}; // stop here!
}

*/
  • uart.S c语言的代码再注释可以对照查看,再调测过程中主要宏定义的使用和函数调用寄存器入栈出栈要注意
#include "platform.h"


/*
 * The UART control registers are memory-mapped at address UART0.
 * This macro returns the address of one of the registers.
 *
 * code
#define UART_REG(reg) ((volatile uint8_t *)(UART0 + reg))

 */


/*
 uart_puts

void uart_puts(char *s)
{
        while (*s) {
                uart_putc(*s++);
        }
}

*/

#define THR     0
#define BOOT_STATUS_RELOCATE_DONE       1

.macro UART_REG reg:req
       \reg(UART0)
.endm

/*
 * Reference
 * [1]: TECHNICAL DATA ON 16550, http://byterunner.com/16550.html
 */

/*
 * UART control registers map. see [1] "PROGRAMMING TABLE"
 * note some are reused by multiple functions
 * 0 (write mode): THR/DLL
 * 1 (write mode): IER/DLM
 */
#define RHR 0   // Receive Holding Register (read mode)

#define THR 0   // Transmit Holding Register (write mode)
#define DLL 0   // LSB of Divisor Latch (write mode)
#define IER 1   // Interrupt Enable Register (write mode)
#define DLM 1   // MSB of Divisor Latch (write mode)
#define FCR 2   // FIFO Control Register (write mode)
#define ISR 2   // Interrupt Status Register (read mode)
#define LCR 3   // Line Control Register
#define MCR 4   // Modem Control Register
#define LSR 5   // Line Status Register
#define MSR 6   // Modem Status Register
#define SPR 7   // ScratchPad Register

/*
 * POWER UP DEFAULTS
 * IER = 0: TX/RX holding register interrupts are both disabled
 * ISR = 1: no interrupt penting
 * LCR = 0
 * MCR = 0
 * LSR = 60 HEX
 * MSR = BITS 0-3 = 0, BITS 4-7 = inputs
 * FCR = 0
 * TX = High
 * OP1 = High
 * OP2 = High
 * RTS = High
 * DTR = High
 * RXRDY = High
 * TXRDY = Low
 * INT = Low
 */

/*
 * LINE STATUS REGISTER (LSR)
 * LSR BIT 0:
 * 0 = no data in receive holding register or FIFO.
 * 1 = data has been receive and saved in the receive holding register or FIFO.
 * ......
 * LSR BIT 5:
 * 0 = transmit holding register is full. 16550 will not accept any data for transmission.
 * 1 = transmitter hold register (or FIFO) is empty. CPU can load the next character.
 * ......
#define LSR_RX_READY (1 << 0)
#define LSR_TX_IDLE  (1 << 5)
 */
.macro LSR_RX_READY
        li s1, 1
        slli s1, s1, 0
.endm
.macro LSR_TX_IDLE
        li s1, 1
        slli s1, s1, 5
.endm



.macro uart_read_reg regs:vararg
        li s1, UART0
        lb s0, \regs(s1)
.endm
.macro uart_write_reg reg,val
        li s1, UART0
        sb \val, \reg(s1)
.endm



.global uart_puts
uart_puts:
        add sp, sp,-16
        sw s0, THR(sp)
        sw s1, 4(sp)
        sw s2, 8(sp)
        sw x1, 12(sp)
        mv s2, a0
putc_loop:
        lb s0, 0(s2)
        beqz s0,uart_puts_exit
        lb s1, 0(s2)
        addi s2,s2,1
        mv a0, s1
        call uart_putc
        j putc_loop
uart_puts_exit:
        lw x1, 12(sp)
        lw s2, 8(sp)
        lw s1, 4(sp)
        lw s0, 0(sp)
        add sp,sp,16
        ret
/*
int uart_putc(char ch)
{
        while ((uart_read_reg(LSR) & LSR_TX_IDLE) == 0);
        return uart_write_reg(THR, ch);
}
*/

.global uart_putc
uart_putc:
        add sp, sp,-12
        sw s0, 0(sp)
        sw s1, 4(sp)
        sw s2, 8(sp)
        mv s2, a0
check_lsr_tx_idle:
        uart_read_reg LSR
        LSR_RX_READY
        and s0, s0, s1
        beq s0,s1,check_lsr_tx_idle
        uart_write_reg THR, s2
        lw s2, 8(sp)
        lw s1, 4(sp)
        lw s0, 0(sp)
        add sp,sp,12
        ret
#if 0
void uart_init()
{
        /* disable interrupts. */
        uart_write_reg(IER, 0x00);

        /*
         * Setting baud rate. Just a demo here if we care about the divisor,
         * but for our purpose [QEMU-virt], this doesn't really do anything.
         *
         * Notice that the divisor register DLL (divisor latch least) and DLM (divisor
         * latch most) have the same base address as the receiver/transmitter and the
         * interrupt enable register. To change what the base address points to, we
         * open the "divisor latch" by writing 1 into the Divisor Latch Access Bit
         * (DLAB), which is bit index 7 of the Line Control Register (LCR).
         *
         * Regarding the baud rate value, see [1] "BAUD RATE GENERATOR PROGRAMMING TABLE".
         * We use 38.4K when 1.8432 MHZ crystal, so the corresponding value is 3.
         * And due to the divisor register is two bytes (16 bits), so we need to
         * split the value of 3(0x0003) into two bytes, DLL stores the low byte,
         * DLM stores the high byte.
         */
        uint8_t lcr = uart_read_reg(LCR);
        uart_write_reg(LCR, lcr | (1 << 7));
        uart_write_reg(DLL, 0x03);
        uart_write_reg(DLM, 0x00);

        /*
         * Continue setting the asynchronous data communication format.
         * - number of the word length: 8 bits
         * - number of stop bits:1 bit when word length is 8 bits
         * - no parity
         * - no break control
         * - disabled baud latch
         */
        lcr = 0;
        uart_write_reg(LCR, lcr | (3 << 0));
}
#endif
.global uart_init
uart_init:
        add sp, sp,-12
        sw s0, THR(sp)
        sw s1, 4(sp)
        sw s2, 8(sp)
        li s0, 0x00
        uart_write_reg IER s0
        li s2, 1
        slli s2,s2,7
        uart_read_reg LCR
        and s0,s0,s2
        uart_write_reg LCR s0
        li s0, 0x03
        uart_write_reg DLL s0
        li s0, 0x00
        uart_write_reg DLM s0
        li s0,3
        uart_write_reg LCR s0
        lw s2, 8(sp)
        lw s1, 4(sp)
        lw s0, 0(sp)
        add sp,sp,12
        ret

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值