上一节分析了怎么实现printf但是在实践时候又发现了点东西分享一下,本节主要是在linux平台用gcc实现打印。
在南大JYY的实验课程里M1需要自己实现Printf,给了putch和putstr接口
#ifndef KLIB_MACROS_H__
#define KLIB_MACROS_H__
#define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz) - 1) & ~((sz) - 1))
#define ROUNDDOWN(a, sz) ((((uintptr_t)a)) & ~((sz) - 1))
#define LENGTH(arr) (sizeof(arr) / sizeof((arr)[0]))
#define RANGE(st, ed) (Area) { .start = (void *)(st), .end = (void *)(ed) }
#define IN_RANGE(ptr, area) ((area).start <= (ptr) && (ptr) < (area).end)
#define STRINGIFY(s) #s
#define TOSTRING(s) STRINGIFY(s)
#define _CONCAT(x, y) x ## y
#define CONCAT(x, y) _CONCAT(x, y)
#define putstr(s) \
({ for (const char *p = s; *p; p++) putch(*p); })
#define io_read(reg) \
({ reg##_T __io_param; \
ioe_read(reg, &__io_param); \
__io_param; })
#define io_write(reg, ...) \
({ reg##_T __io_param = (reg##_T) { __VA_ARGS__ }; \
ioe_write(reg, &__io_param); })
#define static_assert(const_cond) \
static char CONCAT(_static_assert_, __LINE__) [(const_cond) ? 1 : -1] __attribute__((unused))
#define panic_on(cond, s) \
({ if (cond) { \
putstr("AM Panic: "); putstr(s); \
putstr(" @ " __FILE__ ":" TOSTRING(__LINE__) " \n"); \
halt(1); \
} })
#define panic(s) panic_on(1, s)
#endif
所以我们在此基础上完成prinf的打印
首先定义变量
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
#define _INTSIZE_(n) 4
#define ap_start(ap,v) (ap=(char *)&v + _INTSIE_(v))
#define ap_arg(ap,t) (*(t*)(ap=ap+_INTSIZE_(n),ap-_INTSIZE_(n)))
#define ap_end (ap = (char *)0)
然后以下是stdio.c里的代码;需要注意编译器不一样有的地方要自己稍微改改
#include <am.h>
#include <klib.h>
#include <klib-macros.h>
#include <stdarg.h>
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
#define _INTSIZE_(n) 4
#define ap_start(ap,v) (ap=(char *)&v + _INTSIE_(v))
#define ap_arg(ap,t) (*(t*)(ap=ap+_INTSIZE_(n),ap-_INTSIZE_(n)))
#define ap_end (ap = (char *)0)
unsigned char hex_tab[] = { '0','1','2','3','4','5','6','7',\
'8','9','a','b','c','d','e','f' }; //输出各种进制下的字符
int _fun_int_(char * ap)
{
{
//long n=ap_arg(ap,int);
unsigned long m=0 ;
char buf[250],* s = buf + sizeof(buf);
int count = 0;
*--s = '\0';
m=(ap_arg(ap,int));
do{
*--s = hex_tab[m%10];
count++;
}while((m/=10)!=0);
if ((ap_arg(ap,int)) < 0)
*--s = '-';
putstr(s);
}
return 0;
}
int printf(const char *fmt, ...) {
//panic("Not implemented");
char * ap;int maxwidth;
ap = (char *)&fmt + _INTSIZE_(fmt);
for (const char *p = fmt; *p; p++)
{
if(*p != '%')
putch(*p);
else
{
if(*p++);
while((*p)>= '0' && (*p)<='9')
{
maxwidth *= 10;
maxwidth +=(*p - '0');
if ( *p++);
}
switch(*p)
{
case 'd' :_fun_int_(ap);break;
case 'c' :putch(*ap_arg(ap,char *));break;
case 's' :putstr(ap_arg(ap,char *));break;
}
}
}
return 0;
}
int vsprintf(char *out, const char *fmt, va_list ap) {
panic("Not implemented");
}
int sprintf(char *out, const char *fmt, ...) {
panic("Not implemented");
}
int snprintf(char *out, size_t n, const char *fmt, ...) {
panic("Not implemented");
}
int vsnprintf(char *out, size_t n, const char *fmt, va_list ap) {
panic("Not implemented");
}
#endif
下面是应用程序:
#include <am.h>
#include <klib.h>
#include <klib-macros.h>
#define MAX_CPU 8
typedef union task {
struct {
const char *name;
union task *next;
void (*entry)(void *);
Context *context;
};
uint8_t stack[8192];
} Task;
Task *currents[MAX_CPU];
#define current currents[cpu_current()]
// user-defined tasks
int locked = 0;
void lock() { while (atomic_xchg(&locked, 1)); }
void unlock() { atomic_xchg(&locked, 0); }
void func(void *arg) {
while (1) {
lock();
printf("Thread-%s on CPU #%d\n", arg, cpu_current());
unlock();
for (int volatile i = 0; i < 100000; i++) ;
}
}
Task tasks[] = {
{ .name = "A", .entry = func },
{ .name = "B", .entry = func },
{ .name = "C", .entry = func },
{ .name = "D", .entry = func },
{ .name = "E", .entry = func },
};
// ------------------
Context *on_interrupt(Event ev, Context *ctx) {
extern Task tasks[];
if (!current) current = &tasks[0];
else current->context = ctx;
do {
current = current->next;
} while ((current - tasks) % cpu_count() != cpu_current());
return current->context;
}
void mp_entry() {
iset(true);
yield();
}
int main() {
cte_init(on_interrupt);
for (int i = 0; i < LENGTH(tasks); i++) {
Task *task = &tasks[i];
Area stack = (Area) { &task->context + 1, task + 1 };
task->context = kcontext(stack, task->entry, (void *)task->name);
task->next = &tasks[(i + 1) % LENGTH(tasks)];
}
mpe_init(mp_entry);
}
结果: