Initial commit

This commit is contained in:
Olof Kindgren 2018-10-23 23:45:41 +02:00
commit e10c41be8d
38 changed files with 35681 additions and 0 deletions

43
barrel.mem Normal file
View file

@ -0,0 +1,43 @@
/*
8 imm_31_12
7 imm_11_0
6 rd
5 rs2
4 rs1
3 funct3
2 funct7
1 opcode
0 halt
*/
000000001
000000000
000000010
000000010
000000010
000000010
000000010
001000000
001000000
001000000
001000000
001000000
100001000
100001000
100001000
100010000
100010000
100010000
100010000
100010000
110100000
110100000
110100000
110100000
110100000
110000100
110000100
110000100
110000100
110000100
110000100
110000100

70
bench/serv_alu_tb.v Normal file
View file

@ -0,0 +1,70 @@
`default_nettype none
module serv_alu_tb;
reg clk = 1'b1;
reg go;
reg instr;
reg jal;
wire [31:0] pc_data;
wire pc_valid;
reg pc_ready = 1'b1;
wire rd;
wire rd_valid;
wire done;
reg reg11;
reg [8:0] reg2012;
wire reg2012_en;
always #5 clk <= !clk;
vlog_tb_utils vtu();
serv_ctrl dut
(
.clk (clk),
.i_go (go),
.i_instr (instr),
.i_jal (jal),
.i_reg11 (reg11),
.i_reg2012 (reg2012[0]),
.o_reg2012_en (reg2012_en),
.o_rd (rd),
.o_rd_valid (rd_valid),
.o_pc_data (pc_data),
.o_pc_valid (pc_valid),
.i_pc_ready (pc_ready));
reg [31:0] instruction;
integer idx;
initial begin
instruction = 32'h3d80006f;
reg11 = instruction[20];
reg2012 = {instruction[31],instruction[19:12]};
for (idx=0;idx < 31;idx=idx+1) begin
go <= (idx == 19); //Check this
instr <= instruction[idx];
jal <= (idx > 7);
if (reg2012_en) reg2012 <= (reg2012 >> 1);
@(posedge clk);
end
while (!done)
@(posedge clk);
end // initial begin
reg [31:0] rd_word;
always @(posedge clk) begin
if (rd_valid)
rd_word = {rd, rd_word[31:1]};
if (pc_valid & pc_ready) begin
$display("New PC is %08x", pc_data);
$display("RD is %08x", rd_word);
end
end
endmodule

81
bench/serv_ctrl_tb.v Normal file
View file

@ -0,0 +1,81 @@
`default_nettype none
module serv_ctrl_tb;
reg clk = 1'b1;
reg go;
reg instr;
reg jal;
wire [31:0] pc_data;
wire pc_valid;
reg pc_ready = 1'b1;
wire rd;
wire rd_valid;
wire done;
reg reg11;
reg [8:0] reg2012;
wire reg2012_en;
always #5 clk <= !clk;
vlog_tb_utils vtu();
serv_ctrl
#(.RESET_PC (32'h464))
dut
(
.clk (clk),
.i_go (go),
.i_instr (instr),
.i_jal (jal),
.i_reg11 (reg11),
.i_reg2012 (reg2012[0]),
.o_reg2012_en (reg2012_en),
.o_rd (rd),
.o_rd_valid (rd_valid),
.o_pc_data (pc_data),
.o_pc_valid (pc_valid),
.i_pc_ready (pc_ready));
reg [31:0] instruction;
integer idx;
reg [20:0] offset;
initial begin
instruction = 32'h3d80006f;
instruction = 32'h0080706f;
reg11 = instruction[20];
reg2012 = {instruction[31],instruction[19:12]};
offset = {instruction[31],
instruction[19:12],
instruction[20],
instruction[30:21],1'b0};
$display("Reconstructured offset %08x", offset);
for (idx=0;idx < 31;idx=idx+1) begin
go <= (idx == 19); //Check this
instr <= instruction[idx];
jal <= (idx > 7);
if (reg2012_en) reg2012 <= (reg2012 >> 1);
@(posedge clk);
end
while (!done)
@(posedge clk);
end // initial begin
reg [31:0] rd_word;
always @(posedge clk) begin
if (rd_valid)
rd_word = {rd, rd_word[31:1]};
if (pc_valid & pc_ready) begin
$display("New PC is %08x", pc_data);
$display("RD is %08x", rd_word);
end
end
endmodule

43
decode.mem Normal file
View file

@ -0,0 +1,43 @@
/*
8 imm_31_12
7 imm_11_0
6 rd
5 rs2
4 rs1
3 funct3
2 funct7
1 opcode
0 halt
*/
000000001
000000000
000000010
000000010
000000010
000000010
000000010
001000000
001000000
001000000
001000000
001000000
100001000
100001000
100001000
100010000
100010000
100010000
100010000
100010000
110100000
110100000
110100000
110100000
110100000
110000100
110000100
110000100
110000100
110000100
110000100
110000100

16384
firmware.hex Normal file

File diff suppressed because it is too large Load diff

2
firmware/README Normal file
View file

@ -0,0 +1,2 @@
A simple test firmware. This code is in the public domain. Simply copy whatever
you can use.

102
firmware/custom_ops.S Normal file
View file

@ -0,0 +1,102 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#define regnum_q0 0
#define regnum_q1 1
#define regnum_q2 2
#define regnum_q3 3
#define regnum_x0 0
#define regnum_x1 1
#define regnum_x2 2
#define regnum_x3 3
#define regnum_x4 4
#define regnum_x5 5
#define regnum_x6 6
#define regnum_x7 7
#define regnum_x8 8
#define regnum_x9 9
#define regnum_x10 10
#define regnum_x11 11
#define regnum_x12 12
#define regnum_x13 13
#define regnum_x14 14
#define regnum_x15 15
#define regnum_x16 16
#define regnum_x17 17
#define regnum_x18 18
#define regnum_x19 19
#define regnum_x20 20
#define regnum_x21 21
#define regnum_x22 22
#define regnum_x23 23
#define regnum_x24 24
#define regnum_x25 25
#define regnum_x26 26
#define regnum_x27 27
#define regnum_x28 28
#define regnum_x29 29
#define regnum_x30 30
#define regnum_x31 31
#define regnum_zero 0
#define regnum_ra 1
#define regnum_sp 2
#define regnum_gp 3
#define regnum_tp 4
#define regnum_t0 5
#define regnum_t1 6
#define regnum_t2 7
#define regnum_s0 8
#define regnum_s1 9
#define regnum_a0 10
#define regnum_a1 11
#define regnum_a2 12
#define regnum_a3 13
#define regnum_a4 14
#define regnum_a5 15
#define regnum_a6 16
#define regnum_a7 17
#define regnum_s2 18
#define regnum_s3 19
#define regnum_s4 20
#define regnum_s5 21
#define regnum_s6 22
#define regnum_s7 23
#define regnum_s8 24
#define regnum_s9 25
#define regnum_s10 26
#define regnum_s11 27
#define regnum_t3 28
#define regnum_t4 29
#define regnum_t5 30
#define regnum_t6 31
// x8 is s0 and also fp
#define regnum_fp 8
#define r_type_insn(_f7, _rs2, _rs1, _f3, _rd, _opc) \
.word (((_f7) << 25) | ((_rs2) << 20) | ((_rs1) << 15) | ((_f3) << 12) | ((_rd) << 7) | ((_opc) << 0))
#define picorv32_getq_insn(_rd, _qs) \
r_type_insn(0b0000000, 0, regnum_ ## _qs, 0b100, regnum_ ## _rd, 0b0001011)
#define picorv32_setq_insn(_qd, _rs) \
r_type_insn(0b0000001, 0, regnum_ ## _rs, 0b010, regnum_ ## _qd, 0b0001011)
#define picorv32_retirq_insn() \
r_type_insn(0b0000010, 0, 0, 0b000, 0, 0b0001011)
#define picorv32_maskirq_insn(_rd, _rs) \
r_type_insn(0b0000011, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
#define picorv32_waitirq_insn(_rd) \
r_type_insn(0b0000100, 0, 0, 0b100, regnum_ ## _rd, 0b0001011)
#define picorv32_timer_insn(_rd, _rs) \
r_type_insn(0b0000101, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)

BIN
firmware/firmware.bin Normal file

Binary file not shown.

BIN
firmware/firmware.elf Normal file

Binary file not shown.

36
firmware/firmware.h Normal file
View file

@ -0,0 +1,36 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#ifndef FIRMWARE_H
#define FIRMWARE_H
#include <stdint.h>
#include <stdbool.h>
// irq.c
uint32_t *irq(uint32_t *regs, uint32_t irqs);
// print.c
void print_chr(char ch);
void print_str(const char *p);
void print_dec(unsigned int val);
void print_hex(unsigned int val, int digits);
// sieve.c
void sieve(void);
// multest.c
uint32_t hard_mul(uint32_t a, uint32_t b);
uint32_t hard_mulh(uint32_t a, uint32_t b);
uint32_t hard_mulhsu(uint32_t a, uint32_t b);
uint32_t hard_mulhu(uint32_t a, uint32_t b);
void multest(void);
// stats.c
void stats(void);
#endif

16384
firmware/firmware.hex Normal file

File diff suppressed because it is too large Load diff

396
firmware/firmware.map Normal file
View file

@ -0,0 +1,396 @@
Archive member included to satisfy reference by file (symbol)
/opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(muldi3.o)
firmware/multest.o (__mulsi3)
/opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(multi3.o)
firmware/multest.o (__muldi3)
/opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(div.o)
firmware/print.o (__udivsi3)
Discarded input sections
.debug_line 0x0000000000000000 0x93 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(muldi3.o)
.debug_info 0x0000000000000000 0x26 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(muldi3.o)
.debug_abbrev 0x0000000000000000 0x14 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(muldi3.o)
.debug_aranges
0x0000000000000000 0x20 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(muldi3.o)
.debug_str 0x0000000000000000 0x9d /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(muldi3.o)
.debug_line 0x0000000000000000 0x129 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(multi3.o)
.debug_info 0x0000000000000000 0x26 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(multi3.o)
.debug_abbrev 0x0000000000000000 0x14 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(multi3.o)
.debug_aranges
0x0000000000000000 0x20 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(multi3.o)
.debug_str 0x0000000000000000 0x9d /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(multi3.o)
.debug_line 0x0000000000000000 0x169 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(div.o)
.debug_info 0x0000000000000000 0x26 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(div.o)
.debug_abbrev 0x0000000000000000 0x14 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(div.o)
.debug_aranges
0x0000000000000000 0x20 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(div.o)
.debug_str 0x0000000000000000 0x9a /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(div.o)
Memory Configuration
Name Origin Length Attributes
mem 0x0000000000000000 0x000000000000c000
*default* 0x0000000000000000 0xffffffffffffffff
Linker script and memory map
.memory 0x0000000000000000 0xb080
0x0000000000000000 . = 0x0
start*(.text)
*(.text)
.text 0x0000000000000000 0x6f8 firmware/start.o
0x0000000000000468 lui_ret
0x0000000000000474 auipc_ret
0x0000000000000480 j_ret
0x000000000000048c jal_ret
0x0000000000000498 jalr_ret
0x00000000000004a4 beq_ret
0x00000000000004b0 bne_ret
0x00000000000004bc blt_ret
0x00000000000004c8 bge_ret
0x00000000000004d4 bltu_ret
0x00000000000004e0 bgeu_ret
0x00000000000004ec lb_ret
0x00000000000004f8 lh_ret
0x0000000000000504 lw_ret
0x0000000000000510 lbu_ret
0x000000000000051c lhu_ret
0x0000000000000528 sb_ret
0x0000000000000534 sh_ret
0x0000000000000540 sw_ret
0x000000000000054c addi_ret
0x0000000000000558 slti_ret
0x0000000000000564 xori_ret
0x0000000000000570 ori_ret
0x000000000000057c andi_ret
0x0000000000000588 slli_ret
0x0000000000000594 srli_ret
0x00000000000005a0 srai_ret
0x00000000000005ac add_ret
0x00000000000005b8 sub_ret
0x00000000000005c4 sll_ret
0x00000000000005d0 slt_ret
0x00000000000005dc xor_ret
0x00000000000005e8 srl_ret
0x00000000000005f4 sra_ret
0x0000000000000600 or_ret
0x000000000000060c and_ret
0x0000000000000618 mulh_ret
0x0000000000000624 mulhsu_ret
0x0000000000000630 mulhu_ret
0x000000000000063c mul_ret
0x0000000000000648 div_ret
0x0000000000000654 divu_ret
0x0000000000000660 rem_ret
0x000000000000066c remu_ret
0x0000000000000678 simple_ret
0x00000000000006d4 hard_mul
0x00000000000006dc hard_mulh
0x00000000000006e4 hard_mulhsu
0x00000000000006ec hard_mulhu
.text 0x00000000000006f8 0x3d8 firmware/irq.o
0x00000000000006f8 irq
.text 0x0000000000000ad0 0xe0 firmware/print.o
0x0000000000000ad0 print_chr
0x0000000000000adc print_str
0x0000000000000af8 print_dec
0x0000000000000b78 print_hex
.text 0x0000000000000bb0 0x280 firmware/sieve.o
0x0000000000000c9c sieve
.text 0x0000000000000e30 0x2a8 firmware/multest.o
0x0000000000000e58 multest
.text 0x00000000000010d8 0x19c firmware/stats.o
0x00000000000011b0 stats
.text 0x0000000000001274 0x268 tests/xori.o
0x0000000000001274 xori
.text 0x00000000000014dc 0x544 tests/or.o
0x00000000000014dc or
.text 0x0000000000001a20 0x540 tests/xor.o
0x0000000000001a20 xor
.text 0x0000000000001f60 0x540 tests/sub.o
0x0000000000001f60 sub
.text 0x00000000000024a0 0x2cc tests/lb.o
0x00000000000024a0 lb
.text 0x000000000000276c 0x2ec tests/lh.o
0x000000000000276c lh
.text 0x0000000000002a58 0x63c tests/srl.o
0x0000000000002a58 srl
.text 0x0000000000003094 0x340 tests/blt.o
0x0000000000003094 blt
.text 0x00000000000033d4 0x538 tests/and.o
0x00000000000033d4 and
.text 0x000000000000390c 0x33c tests/srai.o
0x000000000000390c srai
.text 0x0000000000003c48 0x340 tests/beq.o
0x0000000000003c48 beq
.text 0x0000000000003f88 0x15c tests/rem.o
0x0000000000003f88 rem
.text 0x00000000000040e4 0x30c tests/addi.o
0x00000000000040e4 addi
.text 0x00000000000043f0 0x548 tests/mul.o
0x00000000000043f0 mul
.text 0x0000000000004938 0x164 tests/divu.o
0x0000000000004938 divu
.text 0x0000000000004a9c 0x504 tests/sw.o
0x0000000000004a9c sw
.text 0x0000000000004fa0 0x344 tests/bne.o
0x0000000000004fa0 bne
*fill* 0x00000000000052e4 0x4
.text 0x00000000000052e8 0xcc tests/auipc.o
0x00000000000052e8 auipc
.text 0x00000000000053b4 0x184 tests/jalr.o
0x00000000000053b4 jalr
.text 0x0000000000005538 0x3d8 tests/bgeu.o
0x0000000000005538 bgeu
.text 0x0000000000005910 0x30c tests/lw.o
0x0000000000005910 lw
.text 0x0000000000005c1c 0x54c tests/mulhu.o
0x0000000000005c1c mulhu
.text 0x0000000000006168 0x2f8 tests/slti.o
0x0000000000006168 slti
.text 0x0000000000006460 0x548 tests/slt.o
0x0000000000006460 slt
.text 0x00000000000069a8 0x2cc tests/lbu.o
0x00000000000069a8 lbu
.text 0x0000000000006c74 0x300 tests/lhu.o
0x0000000000006c74 lhu
.text 0x0000000000006f74 0x4f8 tests/sh.o
0x0000000000006f74 sh
.text 0x000000000000746c 0xe0 tests/lui.o
0x000000000000746c lui
.text 0x000000000000754c 0x378 tests/bltu.o
0x000000000000754c bltu
.text 0x00000000000078c4 0x5ec tests/sll.o
0x00000000000078c4 sll
.text 0x0000000000007eb0 0x54 tests/simple.o
0x0000000000007eb0 simple
.text 0x0000000000007f04 0x308 tests/slli.o
0x0000000000007f04 slli
.text 0x000000000000820c 0x160 tests/remu.o
0x000000000000820c remu
.text 0x000000000000836c 0x25c tests/ori.o
0x000000000000836c ori
.text 0x00000000000085c8 0x474 tests/sb.o
0x00000000000085c8 sb
.text 0x0000000000008a3c 0xd8 tests/jal.o
0x0000000000008a3c jal
.text 0x0000000000008b14 0x560 tests/add.o
0x0000000000008b14 add
.text 0x0000000000009074 0xbc tests/j.o
0x0000000000009074 j
.text 0x0000000000009130 0x244 tests/andi.o
0x0000000000009130 andi
.text 0x0000000000009374 0x61c tests/sra.o
0x0000000000009374 sra
.text 0x0000000000009990 0x3a0 tests/bge.o
0x0000000000009990 bge
.text 0x0000000000009d30 0x15c tests/div.o
0x0000000000009d30 div
.text 0x0000000000009e8c 0x54c tests/mulh.o
0x0000000000009e8c mulh
.text 0x000000000000a3d8 0x54c tests/mulhsu.o
0x000000000000a3d8 mulhsu
.text 0x000000000000a924 0x338 tests/srli.o
0x000000000000a924 srli
.text 0x000000000000ac5c 0x24 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(muldi3.o)
0x000000000000ac5c __mulsi3
.text 0x000000000000ac80 0x88 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(multi3.o)
0x000000000000ac80 __muldi3
.text 0x000000000000ad08 0xb4 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(div.o)
0x000000000000ad08 __divsi3
0x000000000000ad10 __udivsi3
0x000000000000ad58 __umodsi3
0x000000000000ad8c __modsi3
*(*)
.data 0x000000000000adbc 0x0 firmware/start.o
.bss 0x000000000000adbc 0x0 firmware/start.o
.rela.text 0x000000000000adbc 0x0 firmware/start.o
.data 0x000000000000adbc 0x0 firmware/irq.o
.bss 0x000000000000adbc 0x0 firmware/irq.o
.rodata.str1.4
0x000000000000adbc 0x167 firmware/irq.o
0x16b (size before relaxing)
*fill* 0x000000000000af23 0x1
.sbss 0x000000000000af24 0xc firmware/irq.o
.comment 0x000000000000af30 0x11 firmware/irq.o
0x12 (size before relaxing)
.data 0x000000000000af41 0x0 firmware/print.o
.bss 0x000000000000af41 0x0 firmware/print.o
*fill* 0x000000000000af41 0x3
.rodata.str1.4
0x000000000000af44 0x11 firmware/print.o
.comment 0x000000000000af55 0x12 firmware/print.o
.data 0x000000000000af55 0x0 firmware/sieve.o
.bss 0x000000000000af55 0x0 firmware/sieve.o
*fill* 0x000000000000af55 0x3
.rodata.str1.4
0x000000000000af58 0x40 firmware/sieve.o
.sbss 0x000000000000af98 0xc firmware/sieve.o
.comment 0x000000000000afa4 0x12 firmware/sieve.o
.data 0x000000000000afa4 0x0 firmware/multest.o
.bss 0x000000000000afa4 0x0 firmware/multest.o
.rodata.str1.4
0x000000000000afa4 0x2c firmware/multest.o
0x31 (size before relaxing)
.sdata 0x000000000000afd0 0x4 firmware/multest.o
.comment 0x000000000000afd4 0x12 firmware/multest.o
.data 0x000000000000afd4 0x0 firmware/stats.o
.bss 0x000000000000afd4 0x0 firmware/stats.o
.rodata.str1.4
0x000000000000afd4 0x3c firmware/stats.o
0x3e (size before relaxing)
.comment 0x000000000000b010 0x12 firmware/stats.o
.data 0x000000000000b010 0x0 tests/xori.o
.bss 0x000000000000b010 0x0 tests/xori.o
.data 0x000000000000b010 0x0 tests/or.o
.bss 0x000000000000b010 0x0 tests/or.o
.data 0x000000000000b010 0x0 tests/xor.o
.bss 0x000000000000b010 0x0 tests/xor.o
.data 0x000000000000b010 0x0 tests/sub.o
.bss 0x000000000000b010 0x0 tests/sub.o
.data 0x000000000000b010 0x4 tests/lb.o
.bss 0x000000000000b014 0x0 tests/lb.o
.data 0x000000000000b014 0x8 tests/lh.o
.bss 0x000000000000b01c 0x0 tests/lh.o
.data 0x000000000000b01c 0x0 tests/srl.o
.bss 0x000000000000b01c 0x0 tests/srl.o
.data 0x000000000000b01c 0x0 tests/blt.o
.bss 0x000000000000b01c 0x0 tests/blt.o
.data 0x000000000000b01c 0x0 tests/and.o
.bss 0x000000000000b01c 0x0 tests/and.o
.data 0x000000000000b01c 0x0 tests/srai.o
.bss 0x000000000000b01c 0x0 tests/srai.o
.data 0x000000000000b01c 0x0 tests/beq.o
.bss 0x000000000000b01c 0x0 tests/beq.o
.data 0x000000000000b01c 0x0 tests/rem.o
.bss 0x000000000000b01c 0x0 tests/rem.o
.data 0x000000000000b01c 0x0 tests/addi.o
.bss 0x000000000000b01c 0x0 tests/addi.o
.data 0x000000000000b01c 0x0 tests/mul.o
.bss 0x000000000000b01c 0x0 tests/mul.o
.data 0x000000000000b01c 0x0 tests/divu.o
.bss 0x000000000000b01c 0x0 tests/divu.o
.data 0x000000000000b01c 0x28 tests/sw.o
.bss 0x000000000000b044 0x0 tests/sw.o
.data 0x000000000000b044 0x0 tests/bne.o
.bss 0x000000000000b044 0x0 tests/bne.o
.data 0x000000000000b044 0x0 tests/auipc.o
.bss 0x000000000000b044 0x0 tests/auipc.o
.data 0x000000000000b044 0x0 tests/jalr.o
.bss 0x000000000000b044 0x0 tests/jalr.o
.data 0x000000000000b044 0x0 tests/bgeu.o
.bss 0x000000000000b044 0x0 tests/bgeu.o
.data 0x000000000000b044 0x10 tests/lw.o
.bss 0x000000000000b054 0x0 tests/lw.o
.data 0x000000000000b054 0x0 tests/mulhu.o
.bss 0x000000000000b054 0x0 tests/mulhu.o
.data 0x000000000000b054 0x0 tests/slti.o
.bss 0x000000000000b054 0x0 tests/slti.o
.data 0x000000000000b054 0x0 tests/slt.o
.bss 0x000000000000b054 0x0 tests/slt.o
.data 0x000000000000b054 0x4 tests/lbu.o
.bss 0x000000000000b058 0x0 tests/lbu.o
.data 0x000000000000b058 0x8 tests/lhu.o
.bss 0x000000000000b060 0x0 tests/lhu.o
.data 0x000000000000b060 0x14 tests/sh.o
.bss 0x000000000000b074 0x0 tests/sh.o
.data 0x000000000000b074 0x0 tests/lui.o
.bss 0x000000000000b074 0x0 tests/lui.o
.data 0x000000000000b074 0x0 tests/bltu.o
.bss 0x000000000000b074 0x0 tests/bltu.o
.data 0x000000000000b074 0x0 tests/sll.o
.bss 0x000000000000b074 0x0 tests/sll.o
.data 0x000000000000b074 0x0 tests/simple.o
.bss 0x000000000000b074 0x0 tests/simple.o
.data 0x000000000000b074 0x0 tests/slli.o
.bss 0x000000000000b074 0x0 tests/slli.o
.data 0x000000000000b074 0x0 tests/remu.o
.bss 0x000000000000b074 0x0 tests/remu.o
.data 0x000000000000b074 0x0 tests/ori.o
.bss 0x000000000000b074 0x0 tests/ori.o
.data 0x000000000000b074 0xa tests/sb.o
.bss 0x000000000000b07e 0x0 tests/sb.o
*fill* 0x000000000000b07e 0x2
.data 0x000000000000b080 0x0 tests/jal.o
.bss 0x000000000000b080 0x0 tests/jal.o
.data 0x000000000000b080 0x0 tests/add.o
.bss 0x000000000000b080 0x0 tests/add.o
.data 0x000000000000b080 0x0 tests/j.o
.bss 0x000000000000b080 0x0 tests/j.o
.data 0x000000000000b080 0x0 tests/andi.o
.bss 0x000000000000b080 0x0 tests/andi.o
.data 0x000000000000b080 0x0 tests/sra.o
.bss 0x000000000000b080 0x0 tests/sra.o
.data 0x000000000000b080 0x0 tests/bge.o
.bss 0x000000000000b080 0x0 tests/bge.o
.data 0x000000000000b080 0x0 tests/div.o
.bss 0x000000000000b080 0x0 tests/div.o
.data 0x000000000000b080 0x0 tests/mulh.o
.bss 0x000000000000b080 0x0 tests/mulh.o
.data 0x000000000000b080 0x0 tests/mulhsu.o
.bss 0x000000000000b080 0x0 tests/mulhsu.o
.data 0x000000000000b080 0x0 tests/srli.o
.bss 0x000000000000b080 0x0 tests/srli.o
.data 0x000000000000b080 0x0 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(muldi3.o)
.bss 0x000000000000b080 0x0 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(muldi3.o)
.data 0x000000000000b080 0x0 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(multi3.o)
.bss 0x000000000000b080 0x0 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(multi3.o)
.data 0x000000000000b080 0x0 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(div.o)
.bss 0x000000000000b080 0x0 /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a(div.o)
0x000000000000b080 end = .
LOAD firmware/start.o
LOAD firmware/irq.o
LOAD firmware/print.o
LOAD firmware/sieve.o
LOAD firmware/multest.o
LOAD firmware/stats.o
LOAD tests/xori.o
LOAD tests/or.o
LOAD tests/xor.o
LOAD tests/sub.o
LOAD tests/lb.o
LOAD tests/lh.o
LOAD tests/srl.o
LOAD tests/blt.o
LOAD tests/and.o
LOAD tests/srai.o
LOAD tests/beq.o
LOAD tests/rem.o
LOAD tests/addi.o
LOAD tests/mul.o
LOAD tests/divu.o
LOAD tests/sw.o
LOAD tests/bne.o
LOAD tests/auipc.o
LOAD tests/jalr.o
LOAD tests/bgeu.o
LOAD tests/lw.o
LOAD tests/mulhu.o
LOAD tests/slti.o
LOAD tests/slt.o
LOAD tests/lbu.o
LOAD tests/lhu.o
LOAD tests/sh.o
LOAD tests/lui.o
LOAD tests/bltu.o
LOAD tests/sll.o
LOAD tests/simple.o
LOAD tests/slli.o
LOAD tests/remu.o
LOAD tests/ori.o
LOAD tests/sb.o
LOAD tests/jal.o
LOAD tests/add.o
LOAD tests/j.o
LOAD tests/andi.o
LOAD tests/sra.o
LOAD tests/bge.o
LOAD tests/div.o
LOAD tests/mulh.o
LOAD tests/mulhsu.o
LOAD tests/srli.o
LOAD /opt/riscv32i/lib/gcc/riscv32-unknown-elf/7.2.0/libgcc.a
OUTPUT(firmware/firmware.elf elf32-littleriscv)

140
firmware/irq.c Normal file
View file

@ -0,0 +1,140 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include "firmware.h"
uint32_t *irq(uint32_t *regs, uint32_t irqs)
{
static unsigned int ext_irq_4_count = 0;
static unsigned int ext_irq_5_count = 0;
static unsigned int timer_irq_count = 0;
// checking compressed isa q0 reg handling
if ((irqs & 6) != 0) {
uint32_t pc = (regs[0] & 1) ? regs[0] - 3 : regs[0] - 4;
uint32_t instr = *(uint16_t*)pc;
if ((instr & 3) == 3)
instr = instr | (*(uint16_t*)(pc + 2)) << 16;
if (((instr & 3) != 3) != (regs[0] & 1)) {
print_str("Mismatch between q0 LSB and decoded instruction word! q0=0x");
print_hex(regs[0], 8);
print_str(", instr=0x");
if ((instr & 3) == 3)
print_hex(instr, 8);
else
print_hex(instr, 4);
print_str("\n");
__asm__ volatile ("ebreak");
}
}
if ((irqs & (1<<4)) != 0) {
ext_irq_4_count++;
// print_str("[EXT-IRQ-4]");
}
if ((irqs & (1<<5)) != 0) {
ext_irq_5_count++;
// print_str("[EXT-IRQ-5]");
}
if ((irqs & 1) != 0) {
timer_irq_count++;
// print_str("[TIMER-IRQ]");
}
if ((irqs & 6) != 0)
{
uint32_t pc = (regs[0] & 1) ? regs[0] - 3 : regs[0] - 4;
uint32_t instr = *(uint16_t*)pc;
if ((instr & 3) == 3)
instr = instr | (*(uint16_t*)(pc + 2)) << 16;
print_str("\n");
print_str("------------------------------------------------------------\n");
if ((irqs & 2) != 0) {
if (instr == 0x00100073 || instr == 0x9002) {
print_str("EBREAK instruction at 0x");
print_hex(pc, 8);
print_str("\n");
} else {
print_str("Illegal Instruction at 0x");
print_hex(pc, 8);
print_str(": 0x");
print_hex(instr, ((instr & 3) == 3) ? 8 : 4);
print_str("\n");
}
}
if ((irqs & 4) != 0) {
print_str("Bus error in Instruction at 0x");
print_hex(pc, 8);
print_str(": 0x");
print_hex(instr, ((instr & 3) == 3) ? 8 : 4);
print_str("\n");
}
for (int i = 0; i < 8; i++)
for (int k = 0; k < 4; k++)
{
int r = i + k*8;
if (r == 0) {
print_str("pc ");
} else
if (r < 10) {
print_chr('x');
print_chr('0' + r);
print_chr(' ');
print_chr(' ');
} else
if (r < 20) {
print_chr('x');
print_chr('1');
print_chr('0' + r - 10);
print_chr(' ');
} else
if (r < 30) {
print_chr('x');
print_chr('2');
print_chr('0' + r - 20);
print_chr(' ');
} else {
print_chr('x');
print_chr('3');
print_chr('0' + r - 30);
print_chr(' ');
}
print_hex(regs[r], 8);
print_str(k == 3 ? "\n" : " ");
}
print_str("------------------------------------------------------------\n");
print_str("Number of fast external IRQs counted: ");
print_dec(ext_irq_4_count);
print_str("\n");
print_str("Number of slow external IRQs counted: ");
print_dec(ext_irq_5_count);
print_str("\n");
print_str("Number of timer IRQs counted: ");
print_dec(timer_irq_count);
print_str("\n");
__asm__ volatile ("ebreak");
}
return regs;
}

BIN
firmware/irq.o Normal file

Binary file not shown.

27
firmware/makehex.py Normal file
View file

@ -0,0 +1,27 @@
#!/usr/bin/env python3
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
from sys import argv
binfile = argv[1]
nwords = int(argv[2])
with open(binfile, "rb") as f:
bindata = f.read()
assert len(bindata) < 4*nwords
assert len(bindata) % 4 == 0
for i in range(nwords):
if i < len(bindata) // 4:
w = bindata[4*i : 4*i+4]
print("%02x%02x%02x%02x" % (w[3], w[2], w[1], w[0]))
else:
print("0")

85
firmware/multest.c Normal file
View file

@ -0,0 +1,85 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include "firmware.h"
static uint32_t xorshift32(void) {
static uint32_t x = 314159265;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return x;
}
void multest(void)
{
for (int i = 0; i < 10; i++)
{
uint32_t a = xorshift32();
uint32_t b = xorshift32();
uint64_t au = a, bu = b;
int64_t as = (int32_t)a, bs = (int32_t)b;
print_str("input [");
print_hex(as >> 32, 8);
print_str("] ");
print_hex(a, 8);
print_str(" [");
print_hex(bs >> 32, 8);
print_str("] ");
print_hex(b, 8);
print_chr('\n');
uint32_t h_mul, h_mulh, h_mulhsu, h_mulhu;
print_str("hard ");
h_mul = hard_mul(a, b);
print_hex(h_mul, 8);
print_str(" ");
h_mulh = hard_mulh(a, b);
print_hex(h_mulh, 8);
print_str(" ");
h_mulhsu = hard_mulhsu(a, b);
print_hex(h_mulhsu, 8);
print_str(" ");
h_mulhu = hard_mulhu(a, b);
print_hex(h_mulhu, 8);
print_chr('\n');
uint32_t s_mul, s_mulh, s_mulhsu, s_mulhu;
print_str("soft ");
s_mul = a * b;
print_hex(s_mul, 8);
print_str(" ");
s_mulh = (as * bs) >> 32;
print_hex(s_mulh, 8);
print_str(" ");
s_mulhsu = (as * bu) >> 32;
print_hex(s_mulhsu, 8);
print_str(" ");
s_mulhu = (au * bu) >> 32;
print_hex(s_mulhu, 8);
print_str(" ");
if (s_mul != h_mul || s_mulh != h_mulh || s_mulhsu != h_mulhsu || s_mulhu != h_mulhu) {
print_str("ERROR!\n");
__asm__ volatile ("ebreak");
return;
}
print_str(" OK\n");
}
}

BIN
firmware/multest.o Normal file

Binary file not shown.

41
firmware/print.c Normal file
View file

@ -0,0 +1,41 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include "firmware.h"
#define OUTPORT 0x10000000
void print_chr(char ch)
{
*((volatile uint32_t*)OUTPORT) = ch;
}
void print_str(const char *p)
{
while (*p != 0)
*((volatile uint32_t*)OUTPORT) = *(p++);
}
void print_dec(unsigned int val)
{
char buffer[10];
char *p = buffer;
while (val || p == buffer) {
*(p++) = val % 10;
val = val / 10;
}
while (p != buffer) {
*((volatile uint32_t*)OUTPORT) = '0' + *(--p);
}
}
void print_hex(unsigned int val, int digits)
{
for (int i = (4*digits)-4; i >= 0; i -= 4)
*((volatile uint32_t*)OUTPORT) = "0123456789ABCDEF"[(val >> i) % 16];
}

BIN
firmware/print.o Normal file

Binary file not shown.

200
firmware/riscv.ld Normal file
View file

@ -0,0 +1,200 @@
/* ---- Original Script: /opt/riscv32i/riscv32-unknown-elf/lib/ldscripts/elf32lriscv.x ---- */
/* Default linker script, for normal executables */
/* Copyright (C) 2014-2017 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
"elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)
SECTIONS
{
. = 0x00010000;
.text :
{
*(.text)
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
}
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) }
.iplt : { *(.iplt) }
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.sdata2 :
{
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
}
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.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 = .);
}
.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 = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
. = DATA_SEGMENT_RELRO_END (0, .);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata :
{
__global_pointer$ = . + 0x800;
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
}
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.sbss :
{
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
}
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
. = ALIGN(32 / 8);
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(32 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

236
firmware/riscv.ld.orig Normal file
View file

@ -0,0 +1,236 @@
/* ---- Original Script: /opt/riscv32i/riscv32-unknown-elf/lib/ldscripts/elf32lriscv.x ---- */
/* Default linker script, for normal executables */
/* Copyright (C) 2014-2017 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
"elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)
SEARCH_DIR("/opt/riscv32i/riscv32-unknown-elf/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x10000)); . = SEGMENT_START("text-segment", 0x10000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.init : { *(.rela.init) }
.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
.rela.fini : { *(.rela.fini) }
.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
.rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) }
.rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
.rela.ctors : { *(.rela.ctors) }
.rela.dtors : { *(.rela.dtors) }
.rela.got : { *(.rela.got) }
.rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
.rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
.rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
.rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
.rela.iplt :
{
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.rela.plt :
{
*(.rela.plt)
}
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) }
.iplt : { *(.iplt) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.sdata2 :
{
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
}
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.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 = .);
}
.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 = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
. = DATA_SEGMENT_RELRO_END (0, .);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata :
{
__global_pointer$ = . + 0x800;
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
}
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.sbss :
{
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
}
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
. = ALIGN(32 / 8);
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(32 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

24
firmware/sections.lds Normal file
View file

@ -0,0 +1,24 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
*/
MEMORY {
/* the memory in the testbench is 64k in size;
* set LENGTH=48k and leave at least 16k for stack */
mem : ORIGIN = 0x00000000, LENGTH = 0x0000c000
}
SECTIONS {
.memory : {
. = 0x000000;
start*(.text);
*(.text);
*(*);
end = .;
} > mem
}

84
firmware/sieve.c Normal file
View file

@ -0,0 +1,84 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// A simple Sieve of Eratosthenes
#include "firmware.h"
#define BITMAP_SIZE 64
static uint32_t bitmap[BITMAP_SIZE/32];
static uint32_t hash;
static uint32_t mkhash(uint32_t a, uint32_t b)
{
// The XOR version of DJB2
return ((a << 5) + a) ^ b;
}
static void bitmap_set(int idx)
{
bitmap[idx/32] |= 1 << (idx % 32);
}
static bool bitmap_get(int idx)
{
return (bitmap[idx/32] & (1 << (idx % 32))) != 0;
}
static void print_prime(int idx, int val)
{
if (idx < 10)
print_str(" ");
print_dec(idx);
if (idx / 10 == 1)
goto force_th;
switch (idx % 10) {
case 1: print_str("st"); break;
case 2: print_str("nd"); break;
case 3: print_str("rd"); break;
force_th:
default: print_str("th"); break;
}
print_str(" prime is ");
print_dec(val);
print_str(".\n");
hash = mkhash(hash, idx);
hash = mkhash(hash, val);
}
void sieve(void)
{
int idx = 1;
hash = 5381;
print_prime(idx++, 2);
for (int i = 0; i < BITMAP_SIZE; i++) {
if (bitmap_get(i))
continue;
print_prime(idx++, 3+2*i);
for (int j = 2*(3+2*i);; j += 3+2*i) {
if (j%2 == 0)
continue;
int k = (j-3)/2;
if (k >= BITMAP_SIZE)
break;
bitmap_set(k);
}
}
print_str("checksum: ");
print_hex(hash, 8);
if (hash == 0x1772A48F) {
print_str(" OK\n");
} else {
print_str(" ERROR\n");
__asm__ volatile ("ebreak");
}
}

BIN
firmware/sieve.o Normal file

Binary file not shown.

507
firmware/start.S Normal file
View file

@ -0,0 +1,507 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#define ENABLE_QREGS
#define ENABLE_RVTST
#define ENABLE_SIEVE
#define ENABLE_MULTST
#define ENABLE_STATS
#ifndef ENABLE_QREGS
# undef ENABLE_RVTST
#endif
// Only save registers in IRQ wrapper that are to be saved by the caller in
// the RISC-V ABI, with the excpetion of the stack pointer. The IRQ handler
// will save the rest if necessary. I.e. skip x3, x4, x8, x9, and x18-x27.
#undef ENABLE_FASTIRQ
#include "custom_ops.S"
.section .text
.global irq
.global sieve
.global multest
.global hard_mul
.global hard_mulh
.global hard_mulhsu
.global hard_mulhu
.global stats
reset_vec:
// no more than 16 bytes here !
picorv32_waitirq_insn(zero)
picorv32_maskirq_insn(zero, zero)
j start
/* Interrupt handler
**********************************/
.balign 16
irq_vec:
/* save registers */
#ifdef ENABLE_QREGS
picorv32_setq_insn(q2, x1)
picorv32_setq_insn(q3, x2)
lui x1, %hi(irq_regs)
addi x1, x1, %lo(irq_regs)
picorv32_getq_insn(x2, q0)
sw x2, 0*4(x1)
picorv32_getq_insn(x2, q2)
sw x2, 1*4(x1)
picorv32_getq_insn(x2, q3)
sw x2, 2*4(x1)
#ifdef ENABLE_FASTIRQ
sw x5, 5*4(x1)
sw x6, 6*4(x1)
sw x7, 7*4(x1)
sw x10, 10*4(x1)
sw x11, 11*4(x1)
sw x12, 12*4(x1)
sw x13, 13*4(x1)
sw x14, 14*4(x1)
sw x15, 15*4(x1)
sw x16, 16*4(x1)
sw x17, 17*4(x1)
sw x28, 28*4(x1)
sw x29, 29*4(x1)
sw x30, 30*4(x1)
sw x31, 31*4(x1)
#else
sw x3, 3*4(x1)
sw x4, 4*4(x1)
sw x5, 5*4(x1)
sw x6, 6*4(x1)
sw x7, 7*4(x1)
sw x8, 8*4(x1)
sw x9, 9*4(x1)
sw x10, 10*4(x1)
sw x11, 11*4(x1)
sw x12, 12*4(x1)
sw x13, 13*4(x1)
sw x14, 14*4(x1)
sw x15, 15*4(x1)
sw x16, 16*4(x1)
sw x17, 17*4(x1)
sw x18, 18*4(x1)
sw x19, 19*4(x1)
sw x20, 20*4(x1)
sw x21, 21*4(x1)
sw x22, 22*4(x1)
sw x23, 23*4(x1)
sw x24, 24*4(x1)
sw x25, 25*4(x1)
sw x26, 26*4(x1)
sw x27, 27*4(x1)
sw x28, 28*4(x1)
sw x29, 29*4(x1)
sw x30, 30*4(x1)
sw x31, 31*4(x1)
#endif
#else // ENABLE_QREGS
#ifdef ENABLE_FASTIRQ
sw gp, 0*4+0x200(zero)
sw x1, 1*4+0x200(zero)
sw x2, 2*4+0x200(zero)
sw x5, 5*4+0x200(zero)
sw x6, 6*4+0x200(zero)
sw x7, 7*4+0x200(zero)
sw x10, 10*4+0x200(zero)
sw x11, 11*4+0x200(zero)
sw x12, 12*4+0x200(zero)
sw x13, 13*4+0x200(zero)
sw x14, 14*4+0x200(zero)
sw x15, 15*4+0x200(zero)
sw x16, 16*4+0x200(zero)
sw x17, 17*4+0x200(zero)
sw x28, 28*4+0x200(zero)
sw x29, 29*4+0x200(zero)
sw x30, 30*4+0x200(zero)
sw x31, 31*4+0x200(zero)
#else
sw gp, 0*4+0x200(zero)
sw x1, 1*4+0x200(zero)
sw x2, 2*4+0x200(zero)
sw x3, 3*4+0x200(zero)
sw x4, 4*4+0x200(zero)
sw x5, 5*4+0x200(zero)
sw x6, 6*4+0x200(zero)
sw x7, 7*4+0x200(zero)
sw x8, 8*4+0x200(zero)
sw x9, 9*4+0x200(zero)
sw x10, 10*4+0x200(zero)
sw x11, 11*4+0x200(zero)
sw x12, 12*4+0x200(zero)
sw x13, 13*4+0x200(zero)
sw x14, 14*4+0x200(zero)
sw x15, 15*4+0x200(zero)
sw x16, 16*4+0x200(zero)
sw x17, 17*4+0x200(zero)
sw x18, 18*4+0x200(zero)
sw x19, 19*4+0x200(zero)
sw x20, 20*4+0x200(zero)
sw x21, 21*4+0x200(zero)
sw x22, 22*4+0x200(zero)
sw x23, 23*4+0x200(zero)
sw x24, 24*4+0x200(zero)
sw x25, 25*4+0x200(zero)
sw x26, 26*4+0x200(zero)
sw x27, 27*4+0x200(zero)
sw x28, 28*4+0x200(zero)
sw x29, 29*4+0x200(zero)
sw x30, 30*4+0x200(zero)
sw x31, 31*4+0x200(zero)
#endif
#endif // ENABLE_QREGS
/* call interrupt handler C function */
lui sp, %hi(irq_stack)
addi sp, sp, %lo(irq_stack)
// arg0 = address of regs
lui a0, %hi(irq_regs)
addi a0, a0, %lo(irq_regs)
// arg1 = interrupt type
#ifdef ENABLE_QREGS
picorv32_getq_insn(a1, q1)
#else
addi a1, tp, 0
#endif
// call to C function
jal ra, irq
/* restore registers */
#ifdef ENABLE_QREGS
// new irq_regs address returned from C code in a0
addi x1, a0, 0
lw x2, 0*4(x1)
picorv32_setq_insn(q0, x2)
lw x2, 1*4(x1)
picorv32_setq_insn(q1, x2)
lw x2, 2*4(x1)
picorv32_setq_insn(q2, x2)
#ifdef ENABLE_FASTIRQ
lw x5, 5*4(x1)
lw x6, 6*4(x1)
lw x7, 7*4(x1)
lw x10, 10*4(x1)
lw x11, 11*4(x1)
lw x12, 12*4(x1)
lw x13, 13*4(x1)
lw x14, 14*4(x1)
lw x15, 15*4(x1)
lw x16, 16*4(x1)
lw x17, 17*4(x1)
lw x28, 28*4(x1)
lw x29, 29*4(x1)
lw x30, 30*4(x1)
lw x31, 31*4(x1)
#else
lw x3, 3*4(x1)
lw x4, 4*4(x1)
lw x5, 5*4(x1)
lw x6, 6*4(x1)
lw x7, 7*4(x1)
lw x8, 8*4(x1)
lw x9, 9*4(x1)
lw x10, 10*4(x1)
lw x11, 11*4(x1)
lw x12, 12*4(x1)
lw x13, 13*4(x1)
lw x14, 14*4(x1)
lw x15, 15*4(x1)
lw x16, 16*4(x1)
lw x17, 17*4(x1)
lw x18, 18*4(x1)
lw x19, 19*4(x1)
lw x20, 20*4(x1)
lw x21, 21*4(x1)
lw x22, 22*4(x1)
lw x23, 23*4(x1)
lw x24, 24*4(x1)
lw x25, 25*4(x1)
lw x26, 26*4(x1)
lw x27, 27*4(x1)
lw x28, 28*4(x1)
lw x29, 29*4(x1)
lw x30, 30*4(x1)
lw x31, 31*4(x1)
#endif
picorv32_getq_insn(x1, q1)
picorv32_getq_insn(x2, q2)
#else // ENABLE_QREGS
// new irq_regs address returned from C code in a0
addi a1, zero, 0x200
beq a0, a1, 1f
ebreak
1:
#ifdef ENABLE_FASTIRQ
lw gp, 0*4+0x200(zero)
lw x1, 1*4+0x200(zero)
lw x2, 2*4+0x200(zero)
lw x5, 5*4+0x200(zero)
lw x6, 6*4+0x200(zero)
lw x7, 7*4+0x200(zero)
lw x10, 10*4+0x200(zero)
lw x11, 11*4+0x200(zero)
lw x12, 12*4+0x200(zero)
lw x13, 13*4+0x200(zero)
lw x14, 14*4+0x200(zero)
lw x15, 15*4+0x200(zero)
lw x16, 16*4+0x200(zero)
lw x17, 17*4+0x200(zero)
lw x28, 28*4+0x200(zero)
lw x29, 29*4+0x200(zero)
lw x30, 30*4+0x200(zero)
lw x31, 31*4+0x200(zero)
#else
lw gp, 0*4+0x200(zero)
lw x1, 1*4+0x200(zero)
lw x2, 2*4+0x200(zero)
// do not restore x3 (gp)
lw x4, 4*4+0x200(zero)
lw x5, 5*4+0x200(zero)
lw x6, 6*4+0x200(zero)
lw x7, 7*4+0x200(zero)
lw x8, 8*4+0x200(zero)
lw x9, 9*4+0x200(zero)
lw x10, 10*4+0x200(zero)
lw x11, 11*4+0x200(zero)
lw x12, 12*4+0x200(zero)
lw x13, 13*4+0x200(zero)
lw x14, 14*4+0x200(zero)
lw x15, 15*4+0x200(zero)
lw x16, 16*4+0x200(zero)
lw x17, 17*4+0x200(zero)
lw x18, 18*4+0x200(zero)
lw x19, 19*4+0x200(zero)
lw x20, 20*4+0x200(zero)
lw x21, 21*4+0x200(zero)
lw x22, 22*4+0x200(zero)
lw x23, 23*4+0x200(zero)
lw x24, 24*4+0x200(zero)
lw x25, 25*4+0x200(zero)
lw x26, 26*4+0x200(zero)
lw x27, 27*4+0x200(zero)
lw x28, 28*4+0x200(zero)
lw x29, 29*4+0x200(zero)
lw x30, 30*4+0x200(zero)
lw x31, 31*4+0x200(zero)
#endif
#endif // ENABLE_QREGS
picorv32_retirq_insn()
#ifndef ENABLE_QREGS
.balign 0x200
#endif
irq_regs:
// registers are saved to this memory region during interrupt handling
// the program counter is saved as register 0
.fill 32,4
// stack for the interrupt handler
.fill 128,4
irq_stack:
/* Main program
**********************************/
start:
/* zero-initialize all registers */
addi x1, zero, 0
addi x2, zero, 0
addi x3, zero, 0
addi x4, zero, 0
addi x5, zero, 0
addi x6, zero, 0
addi x7, zero, 0
addi x8, zero, 0
addi x9, zero, 0
addi x10, zero, 0
addi x11, zero, 0
addi x12, zero, 0
addi x13, zero, 0
addi x14, zero, 0
addi x15, zero, 0
addi x16, zero, 0
addi x17, zero, 0
addi x18, zero, 0
addi x19, zero, 0
addi x20, zero, 0
addi x21, zero, 0
addi x22, zero, 0
addi x23, zero, 0
addi x24, zero, 0
addi x25, zero, 0
addi x26, zero, 0
addi x27, zero, 0
addi x28, zero, 0
addi x29, zero, 0
addi x30, zero, 0
addi x31, zero, 0
/* running tests from riscv-tests */
#ifdef ENABLE_RVTST
# define TEST(n) \
.global n; \
addi x1, zero, 1000; \
picorv32_timer_insn(zero, x1); \
jal zero,n; \
.global n ## _ret; \
n ## _ret:
#else
# define TEST(n) \
.global n ## _ret; \
n ## _ret:
#endif
TEST(lui)
TEST(auipc)
TEST(j)
TEST(jal)
TEST(jalr)
TEST(beq)
TEST(bne)
TEST(blt)
TEST(bge)
TEST(bltu)
TEST(bgeu)
TEST(lb)
TEST(lh)
TEST(lw)
TEST(lbu)
TEST(lhu)
TEST(sb)
TEST(sh)
TEST(sw)
TEST(addi)
TEST(slti) // also tests sltiu
TEST(xori)
TEST(ori)
TEST(andi)
TEST(slli)
TEST(srli)
TEST(srai)
TEST(add)
TEST(sub)
TEST(sll)
TEST(slt) // what is with sltu ?
TEST(xor)
TEST(srl)
TEST(sra)
TEST(or)
TEST(and)
TEST(mulh)
TEST(mulhsu)
TEST(mulhu)
TEST(mul)
TEST(div)
TEST(divu)
TEST(rem)
TEST(remu)
TEST(simple)
/* set stack pointer */
lui sp,(64*1024)>>12
/* set gp and tp */
lui gp, %hi(0xdeadbeef)
addi gp, gp, %lo(0xdeadbeef)
addi tp, gp, 0
#ifdef ENABLE_SIEVE
/* call sieve C code */
jal ra,sieve
#endif
#ifdef ENABLE_MULTST
/* call multest C code */
jal ra,multest
#endif
#ifdef ENABLE_STATS
/* call stats C code */
jal ra,stats
#endif
/* print "DONE\n" */
lui a0,0x10000000>>12
addi a1,zero,'D'
addi a2,zero,'O'
addi a3,zero,'N'
addi a4,zero,'E'
addi a5,zero,'\n'
sw a1,0(a0)
sw a2,0(a0)
sw a3,0(a0)
sw a4,0(a0)
sw a5,0(a0)
li a0, 0x20000000
li a1, 123456789
sw a1,0(a0)
/* trap */
ebreak
/* Hard mul functions for multest.c
**********************************/
hard_mul:
mul a0, a0, a1
ret
hard_mulh:
mulh a0, a0, a1
ret
hard_mulhsu:
mulhsu a0, a0, a1
ret
hard_mulhu:
mulhu a0, a0, a1
ret

BIN
firmware/start.o Normal file

Binary file not shown.

42
firmware/stats.c Normal file
View file

@ -0,0 +1,42 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include "firmware.h"
static void stats_print_dec(unsigned int val, int digits, bool zero_pad)
{
char buffer[32];
char *p = buffer;
while (val || digits > 0) {
if (val)
*(p++) = '0' + val % 10;
else
*(p++) = zero_pad ? '0' : ' ';
val = val / 10;
digits--;
}
while (p != buffer) {
if (p[-1] == ' ' && p[-2] == ' ') p[-1] = '.';
print_chr(*(--p));
}
}
void stats(void)
{
unsigned int num_cycles, num_instr;
__asm__ volatile ("rdcycle %0; rdinstret %1;" : "=r"(num_cycles), "=r"(num_instr));
print_str("Cycle counter ........");
stats_print_dec(num_cycles, 8, false);
print_str("\nInstruction counter ..");
stats_print_dec(num_instr, 8, false);
print_str("\nCPI: ");
stats_print_dec((num_cycles / num_instr), 0, false);
print_str(".");
stats_print_dec(((100 * num_cycles) / num_instr) % 100, 2, true);
print_str("\n");
}

BIN
firmware/stats.o Normal file

Binary file not shown.

17
rtl/ser_add.v Normal file
View file

@ -0,0 +1,17 @@
module ser_add
(
input clk,
input a,
input b,
input clear,
output reg q = 1'b0);
reg carry = 1'b0;
wire c = carry & ~clear;
always @(posedge clk) begin
q <= a ^ b ^ c;
carry <= a&b | a&c | b&c;
end
endmodule

69
rtl/serv_alu.v Normal file
View file

@ -0,0 +1,69 @@
`default_nettype none
module serv_alu
(
input clk,
input i_d,
input i_go,
input i_funct3_valid,
input i_rs1,
output o_rs_en,
output o_rd,
output o_rd_valid);
localparam [2:0]
ADDI = 3'b000,
SLTI = 3'b010,
SLTIU = 3'b011,
XORI = 3'b100,
ORI = 3'b110,
ANDI = 3'b111;
wire [2:0] funct3;
shift_reg #(3) shift_reg_funct3
(
.clk (clk),
.i_d (i_d),
.i_en (i_funct3_valid),
.o_q (funct3[0]),
.o_par (funct3[2:1]));
wire op_b;
wire result_add;
assign op_b = i_d; //FIXME mux for rs2
assign o_rs_en = running;
ser_add ser_add
(
.clk (clk),
.a (i_rs1),
.b (op_b),
.clear (i_go),
.q (result_add));
assign o_rd = (funct3 == ADDI) ? result_add : 1'b0;
assign o_rd_valid = (cnt > 0);
reg [5:0] cnt = 6'd0;
reg done;
reg running = 1'd0;
always @(posedge clk) begin
cnt <= 6'd0;
done <= 1'b0;
if (i_go)
running <= 1'b1;
else if (cnt == 32) begin
running <= 1'b0;
done <= 1'b1;
end
if (running) begin
cnt <= cnt + 1;
end
end
endmodule

131
rtl/serv_ctrl.v Normal file
View file

@ -0,0 +1,131 @@
`default_nettype none
module serv_ctrl
(
input clk,
input i_go,
input i_instr,
input i_jal,
input i_reg11,
input i_reg2012,
output o_reg2012_en,
output o_rd,
output o_rd_valid,
output [31:0] o_pc_data,
output reg o_pc_valid = 1'b1,
input i_pc_ready);
parameter RESET_PC = 32'd8;
localparam [2:0]
NULL = 3'd0,
INSTR = 3'd1,
REG11 = 3'd2,
REG2012 = 3'd3,
SIGNBIT = 3'd4;
wire offset;
reg signbit = 1'd0;
reg [5:0] cnt = 5'd0;
reg new_pc_sel = 1'b0;
wire pc_plus_4;
wire pc_plus_offset;
reg pc_plus_offset_clr = 1'b0;
wire plus_4;
wire pc_plus_4_clr;
reg running = 1'b0;
wire new_pc;
reg [2:0] offset_source;
assign pc_plus_4_clr = (cnt == 0);
assign plus_4 = (cnt == 2);
ser_add ser_add_pc_plus_4
(
.clk (clk),
.a (plus_4),
.b (o_pc_data[0]),
.clear (pc_plus_4_clr),
.q (pc_plus_4));
shift_reg
#(
.LEN (32),
.INIT (RESET_PC))
pc_reg
(
.clk (clk),
.i_en (running),
.i_d (new_pc),
.o_q (o_pc_data[0]),
.o_par (o_pc_data[31:1])
);
assign new_pc = new_pc_sel ? pc_plus_offset : pc_plus_4;
assign o_rd = pc_plus_4;
assign o_rd_valid = running & i_jal;
always @(cnt, i_jal, running) begin
offset_source = NULL;
new_pc_sel = 1'b0;
if (i_jal) begin
new_pc_sel = 1'b1;
if (cnt < 10)
offset_source = INSTR;
else if (cnt < 11)
offset_source = REG11;
else if (cnt < 20)
offset_source = REG2012;
else
offset_source = SIGNBIT;
end
end
wire o_reg11_en = (offset_source == REG11);
wire o_reg2012_en = (offset_source == REG2012);
assign offset = (offset_source == INSTR) ? i_instr :
(offset_source == REG11) ? i_reg11 :
(offset_source == REG2012) ? i_reg2012 :
(offset_source == SIGNBIT) ? signbit :
1'b0;
ser_add ser_add_pc_plus_offset
(
.clk (clk),
.a (o_pc_data[0]), //FIXME Need a mux before this
.b (offset),
.clear (pc_plus_offset_clr),
.q (pc_plus_offset));
reg done = 1'b0;
always @(posedge clk) begin
cnt <= 6'd0;
done <= 1'b0;
if (i_go)
running <= 1'b1;
else if (cnt == 32) begin
running <= 1'b0;
done <= 1'b1;
end
if (running) begin
cnt <= cnt + 1;
end
if (done)
o_pc_valid <= 1'b1;
if (o_pc_valid & i_pc_ready)
o_pc_valid <= 1'b0;
end
endmodule

68
rtl/serv_decode.v Normal file
View file

@ -0,0 +1,68 @@
module serv_decode
(
input clk,
input i_go,
input i_instr,
output o_imm_31_12,
output o_imm_11_0,
output o_rd,
output o_field_rs2,
output o_field_rs1,
output o_funct3,
output o_funct7,
output o_jal,
output o_opimm,
output o_alu_go,
output o_ctrl_go);
localparam [4:0]
OP_OPIMM = 5'b00100,
OP_JAL = 5'b11011;
reg [8:0] barrel [0:31];
reg [4:0] cnt = 5'd0;
reg running = 1'b0;
wire opcode_valid;
wire halt;
wire [8:0] cur = barrel[cnt];
assign o_imm_31_12 = cur[8];
assign o_imm_11_0 = cur[7];
assign o_rd = cur[6];
assign o_field_rs2 = cur[5] & (1'b0);
assign o_field_rs1 = cur[4] & (1'b0);
assign o_funct3 = cur[3];
assign o_funct7 = cur[2];
assign opcode_valid = cur[1];
assign halt = cur[0];
initial begin
$readmemb("decode.mem", barrel);
end
reg [4:0] opcode = 5'd0;
assign o_jal = (opcode == OP_JAL);
assign o_ctrl_go = (cnt == 19);
assign o_opimm = (opcode == OP_OPIMM);
assign o_alu_go = o_opimm & (cnt == 19);
// shift_reg #(5) shift_reg_opcode
always @(posedge clk) begin
if (opcode_valid)
opcode <= {opcode[3:0], i_instr};
cnt <= cnt + (i_go | running);
if (i_go)
running <= 1'd1;
else if (halt) begin
running <= 1'd0;
cnt <= 1'b0;
end
end
endmodule

147
rtl/serv_regfile.v Normal file
View file

@ -0,0 +1,147 @@
`default_nettype none
module serv_regfile
(
input clk,
input i_d,
input i_field_rs1,
input i_field_rs2,
input i_field_rd,
input i_rs_en,
output o_rs1,
output o_rs2,
input i_rd,
input i_rd_valid);
reg [31:0] rf [0:31];
function automatic [31:0] xreg;
input [4:0] regnum;
begin
xreg = {rf[31][regnum],rf[30][regnum],rf[29][regnum],rf[28][regnum],
rf[27][regnum],rf[26][regnum],rf[25][regnum],rf[24][regnum],
rf[23][regnum],rf[22][regnum],rf[21][regnum],rf[20][regnum],
rf[19][regnum],rf[18][regnum],rf[17][regnum],rf[16][regnum],
rf[15][regnum],rf[14][regnum],rf[13][regnum],rf[12][regnum],
rf[11][regnum],rf[10][regnum],rf[9][regnum] ,rf[8][regnum],
rf[7][regnum] ,rf[6][regnum] ,rf[5][regnum] ,rf[4][regnum],
rf[3][regnum] ,rf[2][regnum] ,rf[1][regnum] ,rf[0][regnum]};
end
endfunction // xreg
always @(*)
for (i=0;i<32;i=i+1) begin
dbg_x1[i] = rf[i][1];
dbg_x2[i] = rf[i][2];
dbg_x3[i] = rf[i][3];
dbg_x4[i] = rf[i][4];
dbg_x5[i] = rf[i][5];
dbg_x6[i] = rf[i][6];
dbg_x7[i] = rf[i][7];
dbg_x8[i] = rf[i][8];
dbg_x9[i] = rf[i][9];
dbg_x10[i] = rf[i][10];
dbg_x11[i] = rf[i][11];
dbg_x12[i] = rf[i][12];
dbg_x13[i] = rf[i][13];
dbg_x14[i] = rf[i][14];
dbg_x15[i] = rf[i][15];
dbg_x16[i] = rf[i][16];
dbg_x17[i] = rf[i][17];
dbg_x18[i] = rf[i][18];
dbg_x19[i] = rf[i][19];
dbg_x20[i] = rf[i][20];
dbg_x21[i] = rf[i][21];
dbg_x22[i] = rf[i][22];
dbg_x23[i] = rf[i][23];
dbg_x24[i] = rf[i][24];
dbg_x25[i] = rf[i][25];
dbg_x26[i] = rf[i][26];
dbg_x27[i] = rf[i][27];
dbg_x28[i] = rf[i][28];
dbg_x29[i] = rf[i][29];
dbg_x30[i] = rf[i][30];
dbg_x31[i] = rf[i][31];
end
reg [31:0] dbg_x0 ;
reg [31:0] dbg_x1 ;
reg [31:0] dbg_x2 ;
reg [31:0] dbg_x3 ;
reg [31:0] dbg_x4 ;
reg [31:0] dbg_x5 ;
reg [31:0] dbg_x6 ;
reg [31:0] dbg_x7 ;
reg [31:0] dbg_x8 ;
reg [31:0] dbg_x9 ;
reg [31:0] dbg_x10;
reg [31:0] dbg_x11;
reg [31:0] dbg_x12;
reg [31:0] dbg_x13;
reg [31:0] dbg_x14;
reg [31:0] dbg_x15;
reg [31:0] dbg_x16;
reg [31:0] dbg_x17;
reg [31:0] dbg_x18;
reg [31:0] dbg_x19;
reg [31:0] dbg_x20;
reg [31:0] dbg_x21;
reg [31:0] dbg_x22;
reg [31:0] dbg_x23;
reg [31:0] dbg_x24;
reg [31:0] dbg_x25;
reg [31:0] dbg_x26;
reg [31:0] dbg_x27;
reg [31:0] dbg_x28;
reg [31:0] dbg_x29;
reg [31:0] dbg_x30;
reg [31:0] dbg_x31;
reg [4:0] raddr = 5'd0;
reg [4:0] waddr = 5'd0;
reg [31:0] rs = 32'd0;
integer i;
initial for (i=0; i<32; i=i+1) rf[i] = 0;
always @(posedge clk) begin
if (i_rd_valid) begin
waddr <= waddr + 1;
rf[waddr][rd_addr] <= i_rd;
end
if (i_rs_en)
rs <= rf[raddr];
end
wire [4:0] rs1_addr;
wire [4:0] rs2_addr;
wire [4:0] rd_addr;
shift_reg #(5) shift_reg_rs1_addr
(.clk (clk),
.i_en (i_field_rs1),
.i_d (i_d),
.o_q (rs1_addr[0]),
.o_par (rs1_addr[4:1]));
shift_reg #(5) shift_reg_rs2_addr
(.clk (clk),
.i_en (i_field_rs2),
.i_d (i_d),
.o_q (rs2_addr[0]),
.o_par (rs2_addr[4:1]));
shift_reg #(5) shift_reg_rd_addr
(.clk (clk),
.i_en (i_field_rd),
.i_d (i_d),
.o_q (rd_addr[0]),
.o_par (rd_addr[4:1]));
assign o_rs1 = (|rs1_addr) ? rs[rs1_addr] : 1'b0;
assign o_rs2 = (|rs2_addr) ? rs[rs2_addr] : 1'b0;
endmodule

126
rtl/serv_top.v Normal file
View file

@ -0,0 +1,126 @@
`default_nettype none
module serv_top
(
input clk,
input [31:0] i_i_data,
input i_i_valid,
output reg o_i_ready = 1'b1,
output [31:0] o_pc_data,
output o_pc_valid,
input i_pc_ready);
reg [31:0] cur_instr = 32'd0;
reg instr;
wire imm_31_12;
wire imm_11_0;
wire field_rd;
wire field_rs1;
wire field_rs2;
wire funct3;
wire funct7;
reg decode_go = 1'b0;
wire ctrl_go;
wire alu_go;
wire rs_en;
wire rs1;
wire rs2;
wire rd;
wire ctrl_rd;
wire ctrl_rd_valid;
wire alu_rd;
wire alu_rd_valid;
wire funct3_valid;
wire jal;
wire opimm;
serv_decode decode
(
.clk (clk),
.i_instr (cur_instr[0]),
.i_go (decode_go),
.o_funct7 (funct7),
.o_funct3 (funct3_valid),
.o_field_rs1 (field_rs1),
.o_field_rs2 (field_rs2),
.o_rd (field_rd),
.o_imm_11_0 (imm_11_0),
.o_imm_31_12 (imm_31_12),
.o_jal (jal),
.o_opimm (opimm),
.o_alu_go (alu_go),
.o_ctrl_go (ctrl_go));
wire reg_2012_en_decode;
wire reg_2012_en_ctrl;
wire reg_2012_data;
wire reg_2012_en = reg_2012_en_decode | reg_2012_en_ctrl;
shift_reg
#(
.LEN (9))
reg_2012
(
.clk (clk),
.i_en (reg_2012_en),
.i_d (cur_instr[0]),
.o_q (reg_2012_data));
serv_alu alu
(
.clk (clk),
.i_go (alu_go),
.i_d (cur_instr[0]),
.i_funct3_valid (funct3_valid),
.i_rs1 (rs1),
.o_rs_en (rs_en),
.o_rd (alu_rd),
.o_rd_valid (alu_rd_valid));
serv_ctrl ctrl
(
.clk (clk),
.i_go (ctrl_go),
.i_instr (cur_instr[0]),
.i_jal (jal),
.i_reg11 (1'b0), //FIXME
.i_reg2012 (reg_2012_data),
.o_reg2012_en (reg_2012_en_ctrl),
.o_rd (ctrl_rd),
.o_rd_valid (ctrl_rd_valid),
.o_pc_data (o_pc_data),
.o_pc_valid (o_pc_valid),
.i_pc_ready (i_pc_ready));
serv_regfile regfile
(
.clk (clk),
.i_d (cur_instr[0]),
.i_field_rs1 (field_rs1),
.i_field_rs2 (field_rs2),
.i_field_rd (field_rd),
.i_rs_en (rs_en),
.o_rs1 (rs1),
.o_rs2 (rs2),
.i_rd ((ctrl_rd & ctrl_rd_valid) | (alu_rd & alu_rd_valid)),
.i_rd_valid (ctrl_rd_valid | alu_rd_valid));
always @(posedge clk) begin
decode_go <= 1'b0;
cur_instr <= {1'b0, cur_instr[31:1]};
if (o_pc_valid)
o_i_ready <= 1'b1;
if (i_i_valid & o_i_ready) begin
cur_instr <= i_i_data;
o_i_ready <= 1'b0;
decode_go <= 1'b1;
end
end // always @ (posedge clk)
endmodule

18
rtl/shift_reg.v Normal file
View file

@ -0,0 +1,18 @@
module shift_reg
(
input clk,
input i_en,
input i_d,
output o_q,
output [LEN-2:0] o_par);
parameter LEN = 0;
parameter INIT = 0;
reg [LEN-1:0] data = INIT;
assign o_q = data[0];
assign o_par = data[LEN-1:1];
always @(posedge clk)
if (i_en)
data <= {i_d, data[LEN-1:1]};
endmodule

78
ser_add_tb.v Normal file
View file

@ -0,0 +1,78 @@
`default_nettype none
module ser_add_tb;
localparam MAX_LEN = 6;
reg clk = 1'b1;
reg a = 1'b0;
reg b = 1'b0;
wire q;
reg clear = 1'b0;
vlog_tb_utils vtu();
always #5 clk <= !clk;
initial begin
@(posedge clk);
repeat (1000) do_transaction;
$finish;
end
task do_transaction;
integer len;
integer idx;
integer areg, breg;
integer received, expected;
beginUsing 0d bits
len = 0;
while (len < 1)
len = ($random % MAX_LEN) + 1;
areg = $random & ((2**len)-1);
breg = $random & ((2**len)-1);
expected = areg+breg;
received = 0/*'dx*/;
$write("Using %0d bits. Expecting %0d+%0d=%0d...", len, areg, breg, expected);
for (idx=0;idx<len;idx=idx+1) begin
clear <= (idx == 0);
a <= areg[idx];
b <= breg[idx];
@(posedge clk);
received[idx-1] = q;
end
clear <= 1'b0;
a <= 1'b0;
b <= 1'b0;
@(posedge clk);
received[len-1] = q;
@(posedge clk);
received[len] = q;
if (received == expected)
$display("OK");
else begin
$display("Crap! Got %0d", received);
#100 $finish;
end
@(posedge clk);
end
endtask
ser_add dut
(
.clk (clk),
.a (a),
.b (b),
.clear (clear),
.q (q));
endmodule

55
serv.core Normal file
View file

@ -0,0 +1,55 @@
CAPI=2:
name : ::serv:0
filesets:
core:
files:
- rtl/shift_reg.v
- rtl/ser_add.v
- rtl/serv_alu.v
- rtl/serv_decode.v
- rtl/serv_ctrl.v
- rtl/serv_regfile.v
- rtl/serv_top.v
file_type : verilogSource
ser_add_tb:
files:
- ser_add_tb.v
file_type : verilogSource
depend : [vlog_tb_utils]
serv_ctrl_tb:
files:
- bench/serv_ctrl_tb.v : {file_type : verilogSource}
depend : [vlog_tb_utils]
serv_top_tb:
files:
- firmware.hex : {copyto : firmware.hex, file_type : user}
- decode.mem : {copyto : decode.mem, file_type : user}
- serv_top_tb.v
file_type : verilogSource
depend : [vlog_tb_utils]
targets:
default:
default_tool : icarus
filesets : [core, tb]
toplevel : serv_top_tb
ser_add_tb:
default_tool : icarus
filesets: [core, ser_add_tb]
toplevel: ser_add_tb
serv_ctrl_tb:
default_tool: icarus
filesets : [core, serv_ctrl_tb]
toplevel : serv_ctrl_tb
serv_top_tb:
default_tool: icarus
filesets : [core, serv_top_tb]
toplevel : serv_top_tb

45
serv_top_tb.v Normal file
View file

@ -0,0 +1,45 @@
module serv_top_tb;
reg clk = 1'b1;
always #5 clk <= !clk;
vlog_tb_utils vtu();
reg [1023:0] firmware_file;
reg [31:0] memory [0:16383];
reg [31:0] i_data;
reg i_valid = 1'b0;
wire i_ready;
wire [31:0] pc_data;
wire pc_valid;
reg pc_ready = 1'b0;
initial begin
firmware_file = "firmware.hex";
$readmemh(firmware_file, memory);
end
always @(posedge clk) begin
pc_ready <= 1'b1; //Fuck knows
if (i_valid & i_ready)
i_valid <= 1'b0;
if (pc_valid & pc_ready) begin
i_data <= memory[pc_data>>2];
i_valid <= 1'b1;
pc_ready <= 1'b0;
end
end
serv_top dut
(.clk (clk),
.i_i_data (i_data),
.i_i_valid (i_valid),
.o_i_ready (i_ready),
.o_pc_data (pc_data),
.o_pc_valid (pc_valid),
.i_pc_ready (pc_ready));
endmodule