start implementing FW to control SPN HW
This commit is contained in:
		
							
								
								
									
										22
									
								
								raven_spn/src/bsp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								raven_spn/src/bsp.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
/*
 | 
			
		||||
 * bsp.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: 30.07.2018
 | 
			
		||||
 *      Author: eyck
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef BSP_H_
 | 
			
		||||
#define BSP_H_
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
#include <fe300prci/fe300prci_driver.h>
 | 
			
		||||
#include <platform.h>
 | 
			
		||||
#include <encoding.h>
 | 
			
		||||
extern void trap_entry();
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* BSP_H_ */
 | 
			
		||||
							
								
								
									
										123
									
								
								raven_spn/src/delay.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								raven_spn/src/delay.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
			
		||||
/*
 | 
			
		||||
 * delay.c
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: 30.07.2018
 | 
			
		||||
 *      Author: eyck
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "delay.h"
 | 
			
		||||
 | 
			
		||||
#define rdmcycle(x)  {                     \
 | 
			
		||||
    uint32_t lo, hi, hi2;                  \
 | 
			
		||||
    __asm__ __volatile__ ("1:\n\t"             \
 | 
			
		||||
              "csrr %0, mcycleh\n\t"       \
 | 
			
		||||
              "csrr %1, mcycle\n\t"        \
 | 
			
		||||
              "csrr %2, mcycleh\n\t"       \
 | 
			
		||||
              "bne  %0, %2, 1b\n\t"         \
 | 
			
		||||
              : "=r" (hi), "=r" (lo), "=r" (hi2)) ; \
 | 
			
		||||
    *(x) = lo | ((uint64_t) hi << 32);              \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t n;
 | 
			
		||||
    uint32_t mult;
 | 
			
		||||
    uint32_t shift;
 | 
			
		||||
} int_inverse ;
 | 
			
		||||
 | 
			
		||||
int_inverse f_cpu_1000_inv;
 | 
			
		||||
int_inverse f_cpu_1000000_inv;
 | 
			
		||||
 | 
			
		||||
uint32_t F_CPU=1000000;
 | 
			
		||||
 | 
			
		||||
void calc_inv(uint32_t n, int_inverse * res){
 | 
			
		||||
    uint32_t one = ~0;
 | 
			
		||||
    uint32_t d = one/n;
 | 
			
		||||
    uint32_t r = one%n + 1;
 | 
			
		||||
    if (r >= n) ++d;
 | 
			
		||||
    if (d == 0) --d;
 | 
			
		||||
    uint32_t shift = 0;
 | 
			
		||||
    while ((d & 0x80000000) == 0){
 | 
			
		||||
        d <<= 1;
 | 
			
		||||
        ++shift;
 | 
			
		||||
    }
 | 
			
		||||
    res->n = n;
 | 
			
		||||
    res->mult = d;
 | 
			
		||||
    res->shift = shift;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t divide32_using_inverse(uint32_t n, int_inverse *inv){
 | 
			
		||||
    uint32_t d =  (uint32_t)(((uint64_t)n * inv->mult) >> 32);
 | 
			
		||||
    d >>= inv->shift;
 | 
			
		||||
    if (n - d*inv->n >= inv->n) ++d;
 | 
			
		||||
    return d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Almost full-range 64/32 divide.
 | 
			
		||||
// If divisor-1 has i bits, then the answer is exact for n of up to 64-i bits
 | 
			
		||||
// e.g. for divisors up to a million, n can have up to 45 bits
 | 
			
		||||
// On RV32IM with divide32_using_inverse inlines this uses 5 multiplies,
 | 
			
		||||
// 33 instructions, zero branches, 3 loads, 0 stores.
 | 
			
		||||
uint64_t divide64_using_inverse(uint64_t n, int_inverse *inv){
 | 
			
		||||
    uint32_t preshift = (31 - inv->shift) & 31;
 | 
			
		||||
    uint64_t d = (uint64_t)divide32_using_inverse(n >> preshift, inv) << preshift;
 | 
			
		||||
    uint32_t r = n - d * inv->n;
 | 
			
		||||
    d += divide32_using_inverse(r, inv);
 | 
			
		||||
    return d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
uint32_t millis(){
 | 
			
		||||
    uint64_t x;
 | 
			
		||||
    rdmcycle(&x);
 | 
			
		||||
    x = divide64_using_inverse(x, &f_cpu_1000_inv);
 | 
			
		||||
    return((uint32_t) (x & 0xFFFFFFFF));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t micros(void){
 | 
			
		||||
    uint64_t x;
 | 
			
		||||
    rdmcycle(&x);
 | 
			
		||||
    // For Power-of-two MHz F_CPU,
 | 
			
		||||
    // this compiles into a simple shift,
 | 
			
		||||
    // and is faster than the general solution.
 | 
			
		||||
#if F_CPU==16000000
 | 
			
		||||
    x = x / (F_CPU / 1000000);
 | 
			
		||||
#else
 | 
			
		||||
#if  F_CPU==256000000
 | 
			
		||||
    x = x / (F_CPU / 1000000);
 | 
			
		||||
#else
 | 
			
		||||
    x = divide64_using_inverse(x, &f_cpu_1000000_inv);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
    return((uint32_t) (x & 0xFFFFFFFF));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void delayMS(uint32_t dwMs){
 | 
			
		||||
    uint64_t current, later;
 | 
			
		||||
    rdmcycle(¤t);
 | 
			
		||||
    later = current + dwMs * (F_CPU/1000);
 | 
			
		||||
    if (later > current){ // usual case
 | 
			
		||||
        while (later > current)
 | 
			
		||||
            rdmcycle(¤t);
 | 
			
		||||
    } else { // wrap. Though this is unlikely to be hit w/ 64-bit mcycle
 | 
			
		||||
        while (later < current)
 | 
			
		||||
            rdmcycle(¤t);
 | 
			
		||||
        while (current < later)
 | 
			
		||||
            rdmcycle(¤t);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void delayUS(uint32_t dwUs){
 | 
			
		||||
    uint64_t current, later;
 | 
			
		||||
    rdmcycle(¤t);
 | 
			
		||||
    later = current + dwUs * (F_CPU/1000000);
 | 
			
		||||
    if (later > current){ // usual case
 | 
			
		||||
        while (later > current)
 | 
			
		||||
            rdmcycle(¤t);
 | 
			
		||||
    } else  {// wrap. Though this is unlikely to be hit w/ 64-bit mcycle
 | 
			
		||||
        while (later < current)
 | 
			
		||||
            rdmcycle(¤t);
 | 
			
		||||
        while (current < later)
 | 
			
		||||
            rdmcycle(¤t);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								raven_spn/src/delay.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								raven_spn/src/delay.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
/*
 | 
			
		||||
 * delay.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: 30.07.2018
 | 
			
		||||
 *      Author: eyck
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef DELAY_H_
 | 
			
		||||
#define DELAY_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
extern uint32_t F_CPU;
 | 
			
		||||
 | 
			
		||||
void delayMS(uint32_t dwMs);
 | 
			
		||||
void delayUS(uint32_t dwUs);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* DELAY_H_ */
 | 
			
		||||
							
								
								
									
										89
									
								
								raven_spn/src/io/gpio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								raven_spn/src/io/gpio.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
/*
 | 
			
		||||
 * gpio.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: 29.07.2018
 | 
			
		||||
 *      Author: eyck
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef GPIO_H_
 | 
			
		||||
#define GPIO_H_
 | 
			
		||||
 | 
			
		||||
#include <sifive/devices/gpio.h>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
template<uint32_t BASE_ADDR>
 | 
			
		||||
class gpio_regs {
 | 
			
		||||
public:
 | 
			
		||||
    static inline uint32_t& value_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_INPUT_VAL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& input_en_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_INPUT_EN);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& output_en_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_OUTPUT_EN);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& port_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_OUTPUT_VAL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& pue_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_PULLUP_EN);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& ds_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_DRIVE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& rise_ie_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_RISE_IE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& rise_ip_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_RISE_IP);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& fall_ie_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_FALL_IE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& fall_ip_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_FALL_IP);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& high_ie_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_HIGH_IE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& high_ip_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_HIGH_IP);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& low_ie_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_LOW_IE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& low_ip_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_LOW_IP);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& iof_en_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_IOF_EN);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& iof_sel_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_IOF_SEL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& out_xor_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+GPIO_OUTPUT_XOR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* GPIO_H_ */
 | 
			
		||||
							
								
								
									
										122
									
								
								raven_spn/src/io/pwm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								raven_spn/src/io/pwm.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
			
		||||
/*
 | 
			
		||||
 * pwm.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: 29.07.2018
 | 
			
		||||
 *      Author: eyck
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef PWM_H_
 | 
			
		||||
#define PWM_H_
 | 
			
		||||
 | 
			
		||||
#include <sifive/devices/pwm.h>
 | 
			
		||||
#include "util/bit_field.h"
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
template<uint32_t BASE_ADDR>
 | 
			
		||||
class pwm_regs {
 | 
			
		||||
public:
 | 
			
		||||
    BEGIN_BF_DECL(pwmcfg_t, uint32_t);
 | 
			
		||||
        BF_FIELD(scale, 0, 4);
 | 
			
		||||
        BF_FIELD(sticky, 8, 1);
 | 
			
		||||
        BF_FIELD(zerocmp, 9, 1);
 | 
			
		||||
        BF_FIELD(deglitch, 10, 1);
 | 
			
		||||
        BF_FIELD(enalways, 12, 1);
 | 
			
		||||
        BF_FIELD(enoneshot, 13, 1);
 | 
			
		||||
        BF_FIELD(cmp0center, 16, 1);
 | 
			
		||||
        BF_FIELD(cmp1center, 17, 1);
 | 
			
		||||
        BF_FIELD(cmp2center, 18, 1);
 | 
			
		||||
        BF_FIELD(cmp3center, 19, 1);
 | 
			
		||||
        BF_FIELD(cmp0gang, 24, 1);
 | 
			
		||||
        BF_FIELD(cmp1gang, 25, 1);
 | 
			
		||||
        BF_FIELD(cmp2gang, 26, 1);
 | 
			
		||||
        BF_FIELD(cmp3gang, 27, 1);
 | 
			
		||||
        BF_FIELD(cmp0ip, 28, 1);
 | 
			
		||||
        BF_FIELD(cmp1ip, 29, 1);
 | 
			
		||||
        BF_FIELD(cmp2ip, 30, 1);
 | 
			
		||||
        BF_FIELD(cmp3ip, 31, 1);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(pwms_t, uint32_t);
 | 
			
		||||
        BF_FIELD(s, 0, 16);
 | 
			
		||||
    END_BF_DECL() r_pwms;
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(pwmcmp0_t, uint32_t);
 | 
			
		||||
        BF_FIELD(cmp0, 0, 16);
 | 
			
		||||
    END_BF_DECL() r_pwmcmp0;
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(pwmcmp1_t, uint32_t);
 | 
			
		||||
        BF_FIELD(cmp0, 0, 16);
 | 
			
		||||
    END_BF_DECL() r_pwmcmp1;
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(pwmcmp2_t, uint32_t);
 | 
			
		||||
        BF_FIELD(cmp0, 0, 16);
 | 
			
		||||
    END_BF_DECL() r_pwmcmp2;
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(pwmcmp3_t, uint32_t);
 | 
			
		||||
        BF_FIELD(cmp0, 0, 16);
 | 
			
		||||
    END_BF_DECL() r_pwmcmp3;
 | 
			
		||||
 | 
			
		||||
    static inline pwmcfg_t& cfg_reg(){
 | 
			
		||||
        return *reinterpret_cast<pwmcfg_t*>(BASE_ADDR+PWM_CFG);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& count_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+PWM_COUNT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline pwms_t& s_reg(){
 | 
			
		||||
        return *reinterpret_cast<pwms_t*>(BASE_ADDR+PWM_S);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline pwmcmp0_t& cmp0_reg(){
 | 
			
		||||
        return *reinterpret_cast<pwmcmp0_t*>(BASE_ADDR+PWM_CMP0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline pwmcmp1_t& cmp1_reg(){
 | 
			
		||||
        return *reinterpret_cast<pwmcmp1_t*>(BASE_ADDR+PWM_CMP1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline pwmcmp2_t& cmp2_reg(){
 | 
			
		||||
        return *reinterpret_cast<pwmcmp2_t*>(BASE_ADDR+PWM_CMP2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline pwmcmp3_t& cmp3_reg(){
 | 
			
		||||
        return *reinterpret_cast<pwmcmp3_t*>(BASE_ADDR+PWM_CMP3);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline bool oneshot_delay(long delay_us){
 | 
			
		||||
        auto scaling_factor=0;
 | 
			
		||||
        while(delay_us/(1<<scaling_factor) > std::numeric_limits<unsigned short>::max()){
 | 
			
		||||
            scaling_factor++;
 | 
			
		||||
        }
 | 
			
		||||
        cfg_reg()=0;
 | 
			
		||||
        count_reg()=0;
 | 
			
		||||
        cfg_reg().scale=4+scaling_factor; // divide by 16 so we get 1us per pwm clock
 | 
			
		||||
        cmp0_reg().cmp0 = delay_us/(1<<scaling_factor);
 | 
			
		||||
        pwm_active=true;
 | 
			
		||||
        cfg_reg().enoneshot=true;
 | 
			
		||||
        do{
 | 
			
		||||
            asm("wfi");
 | 
			
		||||
            asm("nop");
 | 
			
		||||
        }while(pwm_active);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void pwm_interrupt_handler(){
 | 
			
		||||
        cfg_reg().cmp0ip=false;
 | 
			
		||||
        pwm_active=false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline
 | 
			
		||||
    static bool is_active(){ return pwm_active; }
 | 
			
		||||
 | 
			
		||||
    inline
 | 
			
		||||
    static void set_active() {pwm_active=true;}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static volatile bool pwm_active;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* PWM_H_ */
 | 
			
		||||
							
								
								
									
										200
									
								
								raven_spn/src/io/spi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								raven_spn/src/io/spi.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,200 @@
 | 
			
		||||
/*
 | 
			
		||||
 * spi.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: 29.07.2018
 | 
			
		||||
 *      Author: eyck
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SPI_H_
 | 
			
		||||
#define SPI_H_
 | 
			
		||||
 | 
			
		||||
#include <sifive/devices/spi.h>
 | 
			
		||||
#include "util/bit_field.h"
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
template<uint32_t BASE_ADDR>
 | 
			
		||||
class spi_regs {
 | 
			
		||||
public:
 | 
			
		||||
    // storage declarations
 | 
			
		||||
    BEGIN_BF_DECL(sckdiv_t, uint32_t);
 | 
			
		||||
        BF_FIELD(div, 0, 12);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(sckmode_t, uint32_t);
 | 
			
		||||
        BF_FIELD(pha, 0, 1);
 | 
			
		||||
        BF_FIELD(pol, 1, 1);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    uint32_t r_csid;
 | 
			
		||||
 | 
			
		||||
    uint32_t r_csdef;
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(csmode_t, uint32_t);
 | 
			
		||||
        BF_FIELD(mode, 0, 2);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(delay0_t, uint32_t);
 | 
			
		||||
        BF_FIELD(cssck, 0, 8);
 | 
			
		||||
        BF_FIELD(sckcs, 16, 8);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(delay1_t, uint32_t);
 | 
			
		||||
        BF_FIELD(intercs, 0, 16);
 | 
			
		||||
        BF_FIELD(interxfr, 16, 8);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(fmt_t, uint32_t);
 | 
			
		||||
        BF_FIELD(proto, 0, 2);
 | 
			
		||||
        BF_FIELD(endian, 2, 1);
 | 
			
		||||
        BF_FIELD(dir, 3, 1);
 | 
			
		||||
        BF_FIELD(len, 16, 4);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(txdata_t, uint32_t);
 | 
			
		||||
        BF_FIELD(data, 0, 8);
 | 
			
		||||
        BF_FIELD(full, 31, 1);
 | 
			
		||||
    END_BF_DECL() r_txdata;
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(rxdata_t, uint32_t);
 | 
			
		||||
        BF_FIELD(data, 0, 8);
 | 
			
		||||
        BF_FIELD(empty, 31, 1);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(txmark_t, uint32_t);
 | 
			
		||||
        BF_FIELD(txmark, 0, 3);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(rxmark_t, uint32_t);
 | 
			
		||||
        BF_FIELD(rxmark, 0, 3);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(fctrl_t, uint32_t);
 | 
			
		||||
        BF_FIELD(en, 0, 1);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(ffmt_t, uint32_t);
 | 
			
		||||
        BF_FIELD(cmd_en, 0, 1);
 | 
			
		||||
        BF_FIELD(addr_len, 1, 2);
 | 
			
		||||
        BF_FIELD(pad_cnt, 3, 4);
 | 
			
		||||
        BF_FIELD(cmd_proto, 7, 2);
 | 
			
		||||
        BF_FIELD(addr_proto, 9, 2);
 | 
			
		||||
        BF_FIELD(data_proto, 11, 2);
 | 
			
		||||
        BF_FIELD(cmd_code, 16, 8);
 | 
			
		||||
        BF_FIELD(pad_code, 24, 8);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(ie_t, uint32_t);
 | 
			
		||||
        BF_FIELD(txwm, 0, 1);
 | 
			
		||||
        BF_FIELD(rxwm, 1, 1);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(ip_t, uint32_t);
 | 
			
		||||
        BF_FIELD(txwm, 0, 1);
 | 
			
		||||
        BF_FIELD(rxwm, 1, 1);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    static inline sckdiv_t& sckdiv_reg(){
 | 
			
		||||
        return *reinterpret_cast<sckdiv_t*>(BASE_ADDR+SPI_REG_SCKDIV);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline sckmode_t& sckmode_reg(){
 | 
			
		||||
        return *reinterpret_cast<sckmode_t*>(BASE_ADDR+SPI_REG_SCKMODE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& csid_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+SPI_REG_CSID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& csdef_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+SPI_REG_CSDEF);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline csmode_t& csmode_reg(){
 | 
			
		||||
        return *reinterpret_cast<csmode_t*>(BASE_ADDR+SPI_REG_CSMODE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline delay0_t& dcssck_reg(){
 | 
			
		||||
        return *reinterpret_cast<delay0_t*>(BASE_ADDR+SPI_REG_DCSSCK);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& dsckcs_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+SPI_REG_DSCKCS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline delay1_t& dintercs_reg(){
 | 
			
		||||
        return *reinterpret_cast<delay1_t*>(BASE_ADDR+SPI_REG_DINTERCS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline uint32_t& dinterxfr_reg(){
 | 
			
		||||
        return *reinterpret_cast<uint32_t*>(BASE_ADDR+SPI_REG_DINTERXFR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline fmt_t& fmt_reg(){
 | 
			
		||||
        return *reinterpret_cast<fmt_t*>(BASE_ADDR+SPI_REG_FMT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline txdata_t& txfifo_reg(){
 | 
			
		||||
        return *reinterpret_cast<txdata_t*>(BASE_ADDR+SPI_REG_TXFIFO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline rxdata_t& rxfifo_reg(){
 | 
			
		||||
        return *reinterpret_cast<rxdata_t*>(BASE_ADDR+SPI_REG_RXFIFO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline txmark_t& txctrl_reg(){
 | 
			
		||||
        return *reinterpret_cast<txmark_t*>(BASE_ADDR+SPI_REG_TXCTRL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline rxmark_t& rxctrl_reg(){
 | 
			
		||||
        return *reinterpret_cast<rxmark_t*>(BASE_ADDR+SPI_REG_RXCTRL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline fctrl_t& fctrl_reg(){
 | 
			
		||||
        return *reinterpret_cast<fctrl_t*>(BASE_ADDR+SPI_REG_FCTRL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline ffmt_t& ffmt_reg(){
 | 
			
		||||
        return *reinterpret_cast<ffmt_t*>(BASE_ADDR+SPI_REG_FFMT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline ie_t& ie_reg(){
 | 
			
		||||
        return *reinterpret_cast<ie_t*>(BASE_ADDR+SPI_REG_IE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline ip_t& ip_reg(){
 | 
			
		||||
        return *reinterpret_cast<ip_t*>(BASE_ADDR+SPI_REG_IP);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<size_t SIZE>
 | 
			
		||||
    static bool transfer(std::array<uint8_t, SIZE>& bytes){
 | 
			
		||||
        csmode_reg().mode=2; // HOLD mode
 | 
			
		||||
        rxctrl_reg().rxmark=bytes.size()-1; // trigger irq if more than 2 bytes are received;
 | 
			
		||||
        ie_reg().rxwm=1;
 | 
			
		||||
        // write data bytes
 | 
			
		||||
        for(size_t i=0; i<bytes.size(); ++i)
 | 
			
		||||
            txfifo_reg()=bytes[i];
 | 
			
		||||
        // wait until SPI is done
 | 
			
		||||
        spi_active=true;
 | 
			
		||||
        do{
 | 
			
		||||
            asm("wfi");
 | 
			
		||||
            asm("nop");
 | 
			
		||||
        }while(spi_active);
 | 
			
		||||
        // deactivate SPI
 | 
			
		||||
        csmode_reg().mode=0; // AUTO mode, deactivates CS
 | 
			
		||||
        // fetch results
 | 
			
		||||
        for(size_t i=0; i<bytes.size(); ++i) bytes[i]=rxfifo_reg();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void spi_rx_interrupt_handler(){
 | 
			
		||||
        ip_reg().rxwm=0;
 | 
			
		||||
        ie_reg().rxwm=0;
 | 
			
		||||
        spi_active=false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static volatile bool spi_active;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* SPI_H_ */
 | 
			
		||||
							
								
								
									
										83
									
								
								raven_spn/src/io/uart.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								raven_spn/src/io/uart.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 * spi.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: 29.07.2018
 | 
			
		||||
 *      Author: eyck
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef UART_H_
 | 
			
		||||
#define UART_H_
 | 
			
		||||
 | 
			
		||||
#include <sifive/devices/uart.h>
 | 
			
		||||
#include "util/bit_field.h"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
template<uint32_t BASE_ADDR>
 | 
			
		||||
class uart_regs {
 | 
			
		||||
public:
 | 
			
		||||
    BEGIN_BF_DECL(txdata_t, uint32_t);
 | 
			
		||||
        BF_FIELD(data, 0, 8);
 | 
			
		||||
        BF_FIELD(full, 31, 1);
 | 
			
		||||
    END_BF_DECL() ;
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(rxdata_t, uint32_t);
 | 
			
		||||
        BF_FIELD(data, 0, 8);
 | 
			
		||||
        BF_FIELD(empty, 31, 1);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(txctrl_t, uint32_t);
 | 
			
		||||
        BF_FIELD(txen, 0, 1);
 | 
			
		||||
        BF_FIELD(nstop, 1, 1);
 | 
			
		||||
        BF_FIELD(txcnt, 16, 3);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(rxctrl_t, uint32_t);
 | 
			
		||||
        BF_FIELD(rxen, 0, 1);
 | 
			
		||||
        BF_FIELD(rxcnt, 16, 3);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(ie_t, uint32_t);
 | 
			
		||||
        BF_FIELD(txwm, 0, 1);
 | 
			
		||||
        BF_FIELD(rxwm, 1, 1);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(ip_t, uint32_t);
 | 
			
		||||
        BF_FIELD(txwm, 0, 1);
 | 
			
		||||
        BF_FIELD(rxwm, 1, 1);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    BEGIN_BF_DECL(div_t, uint32_t);
 | 
			
		||||
        BF_FIELD(div, 0, 16);
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
    static inline txdata_t& txdata_reg(){
 | 
			
		||||
        return *reinterpret_cast<txdata_t*>(BASE_ADDR+UART_REG_TXFIFO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline rxdata_t& rxdata_reg(){
 | 
			
		||||
        return *reinterpret_cast<rxdata_t*>(BASE_ADDR+UART_REG_RXFIFO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline txctrl_t& txctrl_reg(){
 | 
			
		||||
        return *reinterpret_cast<txctrl_t*>(BASE_ADDR+UART_REG_TXCTRL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline rxctrl_t& rxctrl_reg(){
 | 
			
		||||
        return *reinterpret_cast<rxctrl_t*>(BASE_ADDR+UART_REG_RXCTRL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline ie_t& ie_reg(){
 | 
			
		||||
        return *reinterpret_cast<ie_t*>(BASE_ADDR+UART_REG_IE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline ip_t& ip_reg(){
 | 
			
		||||
        return *reinterpret_cast<ip_t*>(BASE_ADDR+UART_REG_IP);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline div_t& div_reg(){
 | 
			
		||||
        return *reinterpret_cast<div_t*>(BASE_ADDR+UART_REG_DIV);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* SPI_H_ */
 | 
			
		||||
							
								
								
									
										105
									
								
								raven_spn/src/raven_spn.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								raven_spn/src/raven_spn.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
#include "raven_spn.h"
 | 
			
		||||
#include "spn_regs.h"
 | 
			
		||||
#include "delay.h"
 | 
			
		||||
#include "bsp.h"
 | 
			
		||||
#include "plic/plic_driver.h"
 | 
			
		||||
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
using spn =spn_regs<0x90000000>;
 | 
			
		||||
 | 
			
		||||
#define IOF_ENABLE_TERMINAL (0x30000)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef void (*function_ptr_t) (void);
 | 
			
		||||
//! Instance data for the PLIC.
 | 
			
		||||
plic_instance_t g_plic;
 | 
			
		||||
std::array<function_ptr_t,PLIC_NUM_INTERRUPTS>  g_ext_interrupt_handlers;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*! \brief external interrupt handler
 | 
			
		||||
 *
 | 
			
		||||
 * routes the peripheral interrupts to the the respective handler
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
extern "C" void handle_m_ext_interrupt() {
 | 
			
		||||
    plic_source int_num  = PLIC_claim_interrupt(&g_plic);
 | 
			
		||||
    if ((int_num >=1 ) && (int_num < PLIC_NUM_INTERRUPTS))
 | 
			
		||||
      g_ext_interrupt_handlers[int_num]();
 | 
			
		||||
    else
 | 
			
		||||
      exit(1 + (uintptr_t) int_num);
 | 
			
		||||
    PLIC_complete_interrupt(&g_plic, int_num);
 | 
			
		||||
}
 | 
			
		||||
/*! \brief dummy interrupt handler
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void no_interrupt_handler (void) {};
 | 
			
		||||
/*! \brief configure the per-interrupt handler
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void configure_irq(size_t irq_num, function_ptr_t handler, unsigned char prio=1) {
 | 
			
		||||
    g_ext_interrupt_handlers[irq_num] = handler;
 | 
			
		||||
    // Priority must be set > 0 to trigger the interrupt.
 | 
			
		||||
    PLIC_set_priority(&g_plic, irq_num, prio);
 | 
			
		||||
    // Have to enable the interrupt both at the GPIO level, and at the PLIC level.
 | 
			
		||||
    PLIC_enable_interrupt(&g_plic, irq_num);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void msi_interrupt_handler(){
 | 
			
		||||
    int * local_mem_base = (int *) 0x80000100;
 | 
			
		||||
    int hartid = read_csr(mhartid);
 | 
			
		||||
 | 
			
		||||
	int val_a = *local_mem_base;
 | 
			
		||||
	int val_b = *(local_mem_base+1);
 | 
			
		||||
	int sum = val_a + val_b;
 | 
			
		||||
	*(local_mem_base+100) = sum;
 | 
			
		||||
	if (sum == 0xF)
 | 
			
		||||
		printf("HW thread ID %d: sum of A+B=0x%x\n", hartid, sum);
 | 
			
		||||
	else {
 | 
			
		||||
		printf("HW thread ID %d: sum of A+B is not 0x%x. Test FAILED!!!\n", hartid, sum);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*!\brief initializes platform
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void platform_init(){
 | 
			
		||||
	// UART init section TODO: clarify how to get the functions from init.c?
 | 
			
		||||
	GPIO_REG(GPIO_IOF_SEL) &= ~IOF0_UART0_MASK;
 | 
			
		||||
	GPIO_REG(GPIO_IOF_EN) |= IOF0_UART0_MASK;
 | 
			
		||||
	UART0_REG(UART_REG_TXCTRL) |= UART_TXEN;
 | 
			
		||||
 | 
			
		||||
    F_CPU=PRCI_measure_mcycle_freq(20, RTC_FREQ);
 | 
			
		||||
    printf("core freq at %d Hz\n", F_CPU);
 | 
			
		||||
    // initialie interupt & trap handling
 | 
			
		||||
    write_csr(mtvec, &trap_entry);
 | 
			
		||||
 | 
			
		||||
    PLIC_init(&g_plic, PLIC_CTRL_ADDR, PLIC_NUM_INTERRUPTS, PLIC_NUM_PRIORITIES, 0);
 | 
			
		||||
    // Disable the machine & timer interrupts until setup is done.
 | 
			
		||||
    clear_csr(mie, MIP_MEIP);
 | 
			
		||||
    clear_csr(mie, MIP_MTIP);
 | 
			
		||||
    for (auto& h:g_ext_interrupt_handlers) h=no_interrupt_handler;
 | 
			
		||||
    configure_irq(1, msi_interrupt_handler);
 | 
			
		||||
    // Enable interrupts in general.
 | 
			
		||||
    set_csr(mstatus, MSTATUS_MIE);
 | 
			
		||||
    // Enable the Machine-External bit in MIE
 | 
			
		||||
    set_csr(mie, MIP_MEIP);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! \brief main function
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
int main() {
 | 
			
		||||
    platform_init();
 | 
			
		||||
 | 
			
		||||
    spn::start_reg()=1;
 | 
			
		||||
 | 
			
		||||
    printf("set SPN Mode: 1\n");
 | 
			
		||||
 | 
			
		||||
    delayUS(100);
 | 
			
		||||
 | 
			
		||||
    printf("End of execution");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								raven_spn/src/raven_spn.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								raven_spn/src/raven_spn.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
#ifndef RAVEN_SPN_H_
 | 
			
		||||
#define RAVEN_SPN_H_
 | 
			
		||||
 | 
			
		||||
extern "C" void handle_m_ext_interrupt();
 | 
			
		||||
 | 
			
		||||
#endif /* RAVEN_SPN_H_ */
 | 
			
		||||
							
								
								
									
										78
									
								
								raven_spn/src/spn_regs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								raven_spn/src/spn_regs.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017, MINRES Technologies GmbH
 | 
			
		||||
// All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without
 | 
			
		||||
// modification, are permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
//    this list of conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
//    this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
//    and/or other materials provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// 3. Neither the name of the copyright holder nor the names of its contributors
 | 
			
		||||
//    may be used to endorse or promote products derived from this software
 | 
			
		||||
//    without specific prior written permission.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
			
		||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
// POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// Created on: Thu Oct 01 15:45:55 CEST 2020
 | 
			
		||||
//             *      spn_regs.h Author: <RDL Generator>
 | 
			
		||||
//
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#ifndef _SPN_REGS_H_
 | 
			
		||||
#define _SPN_REGS_H_
 | 
			
		||||
 | 
			
		||||
#include <util/bit_field.h>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#define SPN_REG_START               0x00
 | 
			
		||||
#define SPN_REG_RET_VAL             0x10
 | 
			
		||||
#define SPN_REG_MODE                0x20
 | 
			
		||||
#define SPN_REG_INPUT_LENGTH        0x30
 | 
			
		||||
#define SPN_REG_INPUT_ADDR          0x40
 | 
			
		||||
#define SPN_REG_OUTPUT_ADDR         0x50
 | 
			
		||||
#define SPN_REG_NUM_OF_INPUT_BEATS  0x60
 | 
			
		||||
#define SPN_REG_NUM_OF_OUTPUT_BEATS 0x70
 | 
			
		||||
 | 
			
		||||
template<uint32_t BASE_ADDR>
 | 
			
		||||
class spn_regs {
 | 
			
		||||
public:
 | 
			
		||||
    // storage declarations
 | 
			
		||||
    BEGIN_BF_DECL(start_t, uint32_t);
 | 
			
		||||
        BF_FIELD(start, 0, 1);
 | 
			
		||||
    END_BF_DECL() r_start;
 | 
			
		||||
 | 
			
		||||
    uint32_t r_ret_val;
 | 
			
		||||
 | 
			
		||||
    uint32_t r_mode;
 | 
			
		||||
 | 
			
		||||
    uint32_t r_input_length;
 | 
			
		||||
 | 
			
		||||
    uint32_t r_input_addr;
 | 
			
		||||
 | 
			
		||||
    uint32_t r_output_addr;
 | 
			
		||||
 | 
			
		||||
    uint32_t r_num_of_input_beats;
 | 
			
		||||
 | 
			
		||||
    uint32_t r_num_of_output_beats;
 | 
			
		||||
 | 
			
		||||
    static inline start_t& start_reg(){
 | 
			
		||||
        return *reinterpret_cast<start_t*>(BASE_ADDR+SPN_REG_START);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // _SPN_REGS_H_
 | 
			
		||||
							
								
								
									
										179
									
								
								raven_spn/src/util/bit_field.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								raven_spn/src/util/bit_field.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,179 @@
 | 
			
		||||
/*---------------------------------------------------------
 | 
			
		||||
Copyright (c) 2015 Jeff Preshing
 | 
			
		||||
 | 
			
		||||
This software is provided 'as-is', without any express or implied
 | 
			
		||||
warranty. In no event will the authors be held liable for any damages
 | 
			
		||||
arising from the use of this software.
 | 
			
		||||
 | 
			
		||||
Permission is granted to anyone to use this software for any purpose,
 | 
			
		||||
including commercial applications, and to alter it and redistribute it
 | 
			
		||||
freely, subject to the following restrictions:
 | 
			
		||||
 | 
			
		||||
1. The origin of this software must not be misrepresented; you must not
 | 
			
		||||
   claim that you wrote the original software. If you use this software
 | 
			
		||||
   in a product, an acknowledgement in the product documentation would be
 | 
			
		||||
   appreciated but is not required.
 | 
			
		||||
2. Altered source versions must be plainly marked as such, and must not be
 | 
			
		||||
   misrepresented as being the original software.
 | 
			
		||||
3. This notice may not be removed or altered from any source distribution.
 | 
			
		||||
---------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
#ifndef BIT_FIELD_H_
 | 
			
		||||
#define BIT_FIELD_H_
 | 
			
		||||
 | 
			
		||||
#ifndef __CPP11OM_BITFIELD_H__
 | 
			
		||||
#define __CPP11OM_BITFIELD_H__
 | 
			
		||||
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
//---------------------------------------------------------
 | 
			
		||||
// BitFieldMember<>: Used internally by ADD_BITFIELD_MEMBER macro.
 | 
			
		||||
// All members are public to simplify compliance with sections 9.0.7 and
 | 
			
		||||
// 9.5.1 of the C++11 standard, thereby avoiding undefined behavior.
 | 
			
		||||
//---------------------------------------------------------
 | 
			
		||||
template <typename T, int Offset, int Bits> struct BitFieldMember {
 | 
			
		||||
    T value;
 | 
			
		||||
 | 
			
		||||
    static_assert(Offset + Bits <= (int)sizeof(T) * 8, "Member exceeds bitfield boundaries");
 | 
			
		||||
    static_assert(Bits < (int)sizeof(T) * 8, "Can't fill entire bitfield with one member");
 | 
			
		||||
 | 
			
		||||
    static const T Maximum = (T(1) << Bits) - 1;
 | 
			
		||||
    static const T Mask = Maximum << Offset;
 | 
			
		||||
    T maximum() const { return Maximum; }
 | 
			
		||||
    T one() const { return T(1) << Offset; }
 | 
			
		||||
 | 
			
		||||
    operator T() const { return (value >> Offset) & Maximum; }
 | 
			
		||||
 | 
			
		||||
    BitFieldMember &operator=(T v) {
 | 
			
		||||
        assert(v <= Maximum); // v must fit inside the bitfield member
 | 
			
		||||
        value = (value & ~Mask) | (v << Offset);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BitFieldMember &operator+=(T v) {
 | 
			
		||||
        assert(T(*this) + v <= Maximum); // result must fit inside the bitfield member
 | 
			
		||||
        value += v << Offset;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BitFieldMember &operator-=(T v) {
 | 
			
		||||
        assert(T(*this) >= v); // result must not underflow
 | 
			
		||||
        value -= v << Offset;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BitFieldMember &operator++() { return *this += 1; }
 | 
			
		||||
    BitFieldMember operator++(int) { // postfix form
 | 
			
		||||
        BitFieldMember tmp(*this);
 | 
			
		||||
        operator++();
 | 
			
		||||
        return tmp;
 | 
			
		||||
    }
 | 
			
		||||
    BitFieldMember &operator--() { return *this -= 1; }
 | 
			
		||||
    BitFieldMember operator--(int) { // postfix form
 | 
			
		||||
        BitFieldMember tmp(*this);
 | 
			
		||||
        operator--();
 | 
			
		||||
        return tmp;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//---------------------------------------------------------
 | 
			
		||||
// BitFieldArray<>: Used internally by ADD_BITFIELD_ARRAY macro.
 | 
			
		||||
// All members are public to simplify compliance with sections 9.0.7 and
 | 
			
		||||
// 9.5.1 of the C++11 standard, thereby avoiding undefined behavior.
 | 
			
		||||
//---------------------------------------------------------
 | 
			
		||||
template <typename T, int BaseOffset, int BitsPerItem, int NumItems> class BitFieldArray {
 | 
			
		||||
public:
 | 
			
		||||
    T value;
 | 
			
		||||
 | 
			
		||||
    static_assert(BaseOffset + BitsPerItem * NumItems <= (int)sizeof(T) * 8, "Array exceeds bitfield boundaries");
 | 
			
		||||
    static_assert(BitsPerItem < (int)sizeof(T) * 8, "Can't fill entire bitfield with one array element");
 | 
			
		||||
 | 
			
		||||
    static const T Maximum = (T(1) << BitsPerItem) - 1;
 | 
			
		||||
    T maximum() const { return Maximum; }
 | 
			
		||||
    int numItems() const { return NumItems; }
 | 
			
		||||
 | 
			
		||||
    class Element {
 | 
			
		||||
    private:
 | 
			
		||||
        T &value;
 | 
			
		||||
        int offset;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        Element(T &value, int offset)
 | 
			
		||||
        : value(value)
 | 
			
		||||
        , offset(offset) {}
 | 
			
		||||
        T mask() const { return Maximum << offset; }
 | 
			
		||||
 | 
			
		||||
        operator T() const { return (value >> offset) & Maximum; }
 | 
			
		||||
 | 
			
		||||
        Element &operator=(T v) {
 | 
			
		||||
            assert(v <= Maximum); // v must fit inside the bitfield member
 | 
			
		||||
            value = (value & ~mask()) | (v << offset);
 | 
			
		||||
            return *this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Element &operator+=(T v) {
 | 
			
		||||
            assert(T(*this) + v <= Maximum); // result must fit inside the bitfield member
 | 
			
		||||
            value += v << offset;
 | 
			
		||||
            return *this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Element &operator-=(T v) {
 | 
			
		||||
            assert(T(*this) >= v); // result must not underflow
 | 
			
		||||
            value -= v << offset;
 | 
			
		||||
            return *this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Element &operator++() { return *this += 1; }
 | 
			
		||||
        Element operator++(int) { // postfix form
 | 
			
		||||
            Element tmp(*this);
 | 
			
		||||
            operator++();
 | 
			
		||||
            return tmp;
 | 
			
		||||
        }
 | 
			
		||||
        Element &operator--() { return *this -= 1; }
 | 
			
		||||
        Element operator--(int) { // postfix form
 | 
			
		||||
            Element tmp(*this);
 | 
			
		||||
            operator--();
 | 
			
		||||
            return tmp;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Element operator[](int i) {
 | 
			
		||||
        assert(i >= 0 && i < NumItems); // array index must be in range
 | 
			
		||||
        return Element(value, BaseOffset + BitsPerItem * i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const Element operator[](int i) const {
 | 
			
		||||
        assert(i >= 0 && i < NumItems); // array index must be in range
 | 
			
		||||
        return Element(value, BaseOffset + BitsPerItem * i);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//---------------------------------------------------------
 | 
			
		||||
// Bitfield definition macros.
 | 
			
		||||
// All members are public to simplify compliance with sections 9.0.7 and
 | 
			
		||||
// 9.5.1 of the C++11 standard, thereby avoiding undefined behavior.
 | 
			
		||||
//---------------------------------------------------------
 | 
			
		||||
#define BEGIN_BF_DECL(typeName, T)                                                                                     \
 | 
			
		||||
    union typeName {                                                                                                   \
 | 
			
		||||
        struct Wrapper {                                                                                               \
 | 
			
		||||
            T value;                                                                                                   \
 | 
			
		||||
        };                                                                                                             \
 | 
			
		||||
        Wrapper flat;                                                                                                    \
 | 
			
		||||
        typeName(T v = 0) { flat.value = v; }                                                                            \
 | 
			
		||||
        typeName &operator=(T v) {                                                                                     \
 | 
			
		||||
            flat.value = v;                                                                                              \
 | 
			
		||||
            return *this;                                                                                              \
 | 
			
		||||
        }                                                                                                              \
 | 
			
		||||
        operator T &() { return flat.value; }                                                                            \
 | 
			
		||||
        operator T() const { return flat.value; }                                                                        \
 | 
			
		||||
        using StorageType = T;
 | 
			
		||||
 | 
			
		||||
#define BF_FIELD(memberName, offset, bits) BitFieldMember<StorageType, offset, bits> memberName;
 | 
			
		||||
 | 
			
		||||
#define BF_ARRAY(memberName, offset, bits, numItems) BitFieldArray<StorageType, offset, bits, numItems> memberName;
 | 
			
		||||
 | 
			
		||||
#define END_BF_DECL() }
 | 
			
		||||
 | 
			
		||||
#endif // __CPP11OM_BITFIELD_H__
 | 
			
		||||
 | 
			
		||||
#endif /* BIT_FIELD_H_ */
 | 
			
		||||
							
								
								
									
										271
									
								
								raven_spn/src/wrap_printf.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								raven_spn/src/wrap_printf.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,271 @@
 | 
			
		||||
/* The functions in this file are only meant to support Dhrystone on an
 | 
			
		||||
 * embedded RV32 system and are obviously incorrect in general. */
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#undef putchar
 | 
			
		||||
int putchar(int ch)
 | 
			
		||||
{
 | 
			
		||||
  return write(STDOUT_FILENO, &ch, 1) == 1 ? ch : -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sprintf_putch(int ch, void** data)
 | 
			
		||||
{
 | 
			
		||||
  char** pstr = (char**)data;
 | 
			
		||||
  **pstr = ch;
 | 
			
		||||
  (*pstr)++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned long getuint(va_list *ap, int lflag)
 | 
			
		||||
{
 | 
			
		||||
  if (lflag)
 | 
			
		||||
    return va_arg(*ap, unsigned long);
 | 
			
		||||
  else
 | 
			
		||||
    return va_arg(*ap, unsigned int);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static long getint(va_list *ap, int lflag)
 | 
			
		||||
{
 | 
			
		||||
  if (lflag)
 | 
			
		||||
    return va_arg(*ap, long);
 | 
			
		||||
  else
 | 
			
		||||
    return va_arg(*ap, int);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void printnum(void (*putch)(int, void**), void **putdat,
 | 
			
		||||
                    unsigned long num, unsigned base, int width, int padc)
 | 
			
		||||
{
 | 
			
		||||
  unsigned digs[sizeof(num)*8];
 | 
			
		||||
  int pos = 0;
 | 
			
		||||
 | 
			
		||||
  while (1)
 | 
			
		||||
  {
 | 
			
		||||
    digs[pos++] = num % base;
 | 
			
		||||
    if (num < base)
 | 
			
		||||
      break;
 | 
			
		||||
    num /= base;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  while (width-- > pos)
 | 
			
		||||
    putch(padc, putdat);
 | 
			
		||||
 | 
			
		||||
  while (pos-- > 0)
 | 
			
		||||
    putch(digs[pos] + (digs[pos] >= 10 ? 'a' - 10 : '0'), putdat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void print_double(void (*putch)(int, void**), void **putdat,
 | 
			
		||||
                                double num, int width, int prec)
 | 
			
		||||
{
 | 
			
		||||
  union {
 | 
			
		||||
    double d;
 | 
			
		||||
    uint64_t u;
 | 
			
		||||
  } u;
 | 
			
		||||
  u.d = num;
 | 
			
		||||
 | 
			
		||||
  if (u.u & (1ULL << 63)) {
 | 
			
		||||
    putch('-', putdat);
 | 
			
		||||
    u.u &= ~(1ULL << 63);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < prec; i++)
 | 
			
		||||
    u.d *= 10;
 | 
			
		||||
 | 
			
		||||
  char buf[32], *pbuf = buf;
 | 
			
		||||
  printnum(sprintf_putch, (void**)&pbuf, (unsigned long)u.d, 10, 0, 0);
 | 
			
		||||
  if (prec > 0) {
 | 
			
		||||
    for (int i = 0; i < prec; i++) {
 | 
			
		||||
      pbuf[-i] = pbuf[-i-1];
 | 
			
		||||
    }
 | 
			
		||||
    pbuf[-prec] = '.';
 | 
			
		||||
    pbuf++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (char* p = buf; p < pbuf; p++)
 | 
			
		||||
    putch(*p, putdat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void vprintfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_list ap)
 | 
			
		||||
{
 | 
			
		||||
  register const char* p;
 | 
			
		||||
  const char* last_fmt;
 | 
			
		||||
  register int ch, err;
 | 
			
		||||
  unsigned long num;
 | 
			
		||||
  int base, lflag, width, precision, altflag;
 | 
			
		||||
  char padc;
 | 
			
		||||
 | 
			
		||||
  while (1) {
 | 
			
		||||
    while ((ch = *(unsigned char *) fmt) != '%') {
 | 
			
		||||
      if (ch == '\0')
 | 
			
		||||
        return;
 | 
			
		||||
      fmt++;
 | 
			
		||||
      putch(ch, putdat);
 | 
			
		||||
    }
 | 
			
		||||
    fmt++;
 | 
			
		||||
 | 
			
		||||
    // Process a %-escape sequence
 | 
			
		||||
    last_fmt = fmt;
 | 
			
		||||
    padc = ' ';
 | 
			
		||||
    width = -1;
 | 
			
		||||
    precision = -1;
 | 
			
		||||
    lflag = 0;
 | 
			
		||||
    altflag = 0;
 | 
			
		||||
  reswitch:
 | 
			
		||||
    switch (ch = *(unsigned char *) fmt++) {
 | 
			
		||||
 | 
			
		||||
    // flag to pad on the right
 | 
			
		||||
    case '-':
 | 
			
		||||
      padc = '-';
 | 
			
		||||
      goto reswitch;
 | 
			
		||||
      
 | 
			
		||||
    // flag to pad with 0's instead of spaces
 | 
			
		||||
    case '0':
 | 
			
		||||
      padc = '0';
 | 
			
		||||
      goto reswitch;
 | 
			
		||||
 | 
			
		||||
    // width field
 | 
			
		||||
    case '1':
 | 
			
		||||
    case '2':
 | 
			
		||||
    case '3':
 | 
			
		||||
    case '4':
 | 
			
		||||
    case '5':
 | 
			
		||||
    case '6':
 | 
			
		||||
    case '7':
 | 
			
		||||
    case '8':
 | 
			
		||||
    case '9':
 | 
			
		||||
      for (precision = 0; ; ++fmt) {
 | 
			
		||||
        precision = precision * 10 + ch - '0';
 | 
			
		||||
        ch = *fmt;
 | 
			
		||||
        if (ch < '0' || ch > '9')
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
      goto process_precision;
 | 
			
		||||
 | 
			
		||||
    case '*':
 | 
			
		||||
      precision = va_arg(ap, int);
 | 
			
		||||
      goto process_precision;
 | 
			
		||||
 | 
			
		||||
    case '.':
 | 
			
		||||
      if (width < 0)
 | 
			
		||||
        width = 0;
 | 
			
		||||
      goto reswitch;
 | 
			
		||||
 | 
			
		||||
    case '#':
 | 
			
		||||
      altflag = 1;
 | 
			
		||||
      goto reswitch;
 | 
			
		||||
 | 
			
		||||
    process_precision:
 | 
			
		||||
      if (width < 0)
 | 
			
		||||
        width = precision, precision = -1;
 | 
			
		||||
      goto reswitch;
 | 
			
		||||
 | 
			
		||||
    // long flag
 | 
			
		||||
    case 'l':
 | 
			
		||||
      if (lflag)
 | 
			
		||||
        goto bad;
 | 
			
		||||
      goto reswitch;
 | 
			
		||||
 | 
			
		||||
    // character
 | 
			
		||||
    case 'c':
 | 
			
		||||
      putch(va_arg(ap, int), putdat);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    // double
 | 
			
		||||
    case 'f':
 | 
			
		||||
      print_double(putch, putdat, va_arg(ap, double), width, precision);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    // string
 | 
			
		||||
    case 's':
 | 
			
		||||
      if ((p = va_arg(ap, char *)) == NULL)
 | 
			
		||||
        p = "(null)";
 | 
			
		||||
      if (width > 0 && padc != '-')
 | 
			
		||||
        for (width -= strnlen(p, precision); width > 0; width--)
 | 
			
		||||
          putch(padc, putdat);
 | 
			
		||||
      for (; (ch = *p) != '\0' && (precision < 0 || --precision >= 0); width--) {
 | 
			
		||||
        putch(ch, putdat);
 | 
			
		||||
        p++;
 | 
			
		||||
      }
 | 
			
		||||
      for (; width > 0; width--)
 | 
			
		||||
        putch(' ', putdat);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    // (signed) decimal
 | 
			
		||||
    case 'd':
 | 
			
		||||
      num = getint(&ap, lflag);
 | 
			
		||||
      if ((long) num < 0) {
 | 
			
		||||
        putch('-', putdat);
 | 
			
		||||
        num = -(long) num;
 | 
			
		||||
      }
 | 
			
		||||
      base = 10;
 | 
			
		||||
      goto signed_number;
 | 
			
		||||
 | 
			
		||||
    // unsigned decimal
 | 
			
		||||
    case 'u':
 | 
			
		||||
      base = 10;
 | 
			
		||||
      goto unsigned_number;
 | 
			
		||||
 | 
			
		||||
    // (unsigned) octal
 | 
			
		||||
    case 'o':
 | 
			
		||||
      // should do something with padding so it's always 3 octits
 | 
			
		||||
      base = 8;
 | 
			
		||||
      goto unsigned_number;
 | 
			
		||||
 | 
			
		||||
    // pointer
 | 
			
		||||
    case 'p':
 | 
			
		||||
      lflag = 1;
 | 
			
		||||
      putch('0', putdat);
 | 
			
		||||
      putch('x', putdat);
 | 
			
		||||
      /* fall through to 'x' */
 | 
			
		||||
 | 
			
		||||
    // (unsigned) hexadecimal
 | 
			
		||||
    case 'x':
 | 
			
		||||
      base = 16;
 | 
			
		||||
    unsigned_number:
 | 
			
		||||
      num = getuint(&ap, lflag);
 | 
			
		||||
    signed_number:
 | 
			
		||||
      printnum(putch, putdat, num, base, width, padc);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    // escaped '%' character
 | 
			
		||||
    case '%':
 | 
			
		||||
      putch(ch, putdat);
 | 
			
		||||
      break;
 | 
			
		||||
      
 | 
			
		||||
    // unrecognized escape sequence - just print it literally
 | 
			
		||||
    default:
 | 
			
		||||
    bad:
 | 
			
		||||
      putch('%', putdat);
 | 
			
		||||
      fmt = last_fmt;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int __wrap_printf(const char* fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
  va_list ap;
 | 
			
		||||
  va_start(ap, fmt);
 | 
			
		||||
 | 
			
		||||
  vprintfmt((void*)putchar, 0, fmt, ap);
 | 
			
		||||
 | 
			
		||||
  va_end(ap);
 | 
			
		||||
  return 0; // incorrect return value, but who cares, anyway?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int __wrap_sprintf(char* str, const char* fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
  va_list ap;
 | 
			
		||||
  char* str0 = str;
 | 
			
		||||
  va_start(ap, fmt);
 | 
			
		||||
 | 
			
		||||
  vprintfmt(sprintf_putch, (void**)&str, fmt, ap);
 | 
			
		||||
  *str = 0;
 | 
			
		||||
 | 
			
		||||
  va_end(ap);
 | 
			
		||||
  return str - str0;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user