mirror of
https://github.com/olofk/serv.git
synced 2025-04-20 11:57:07 -04:00
Initial commit
This commit is contained in:
commit
e10c41be8d
38 changed files with 35681 additions and 0 deletions
43
barrel.mem
Normal file
43
barrel.mem
Normal 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
70
bench/serv_alu_tb.v
Normal 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
81
bench/serv_ctrl_tb.v
Normal 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
43
decode.mem
Normal 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
16384
firmware.hex
Normal file
File diff suppressed because it is too large
Load diff
2
firmware/README
Normal file
2
firmware/README
Normal 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
102
firmware/custom_ops.S
Normal 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
BIN
firmware/firmware.bin
Normal file
Binary file not shown.
BIN
firmware/firmware.elf
Normal file
BIN
firmware/firmware.elf
Normal file
Binary file not shown.
36
firmware/firmware.h
Normal file
36
firmware/firmware.h
Normal 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
16384
firmware/firmware.hex
Normal file
File diff suppressed because it is too large
Load diff
396
firmware/firmware.map
Normal file
396
firmware/firmware.map
Normal 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
140
firmware/irq.c
Normal 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
BIN
firmware/irq.o
Normal file
Binary file not shown.
27
firmware/makehex.py
Normal file
27
firmware/makehex.py
Normal 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
85
firmware/multest.c
Normal 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
BIN
firmware/multest.o
Normal file
Binary file not shown.
41
firmware/print.c
Normal file
41
firmware/print.c
Normal 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
BIN
firmware/print.o
Normal file
Binary file not shown.
200
firmware/riscv.ld
Normal file
200
firmware/riscv.ld
Normal 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
236
firmware/riscv.ld.orig
Normal 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
24
firmware/sections.lds
Normal 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
84
firmware/sieve.c
Normal 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
BIN
firmware/sieve.o
Normal file
Binary file not shown.
507
firmware/start.S
Normal file
507
firmware/start.S
Normal 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
BIN
firmware/start.o
Normal file
Binary file not shown.
42
firmware/stats.c
Normal file
42
firmware/stats.c
Normal 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
BIN
firmware/stats.o
Normal file
Binary file not shown.
17
rtl/ser_add.v
Normal file
17
rtl/ser_add.v
Normal 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
69
rtl/serv_alu.v
Normal 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
131
rtl/serv_ctrl.v
Normal 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
68
rtl/serv_decode.v
Normal 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
147
rtl/serv_regfile.v
Normal 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
126
rtl/serv_top.v
Normal 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
18
rtl/shift_reg.v
Normal 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
78
ser_add_tb.v
Normal 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
55
serv.core
Normal 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
45
serv_top_tb.v
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue