Compare commits
256
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a67fbb643b | ||
|
|
25e3d4f36f | ||
|
|
3db7aa0fb4 | ||
|
|
523e216793 | ||
|
|
bd4b69206f | ||
|
|
61e740cc1d | ||
|
|
592c158275 | ||
|
|
791e97a873 | ||
|
|
0b5b8ceed7 | ||
|
|
31bd88a707 | ||
|
|
739921d7a9 | ||
|
|
cfb87bf755 | ||
|
|
73f7a85646 | ||
|
|
03780653b8 | ||
|
|
0dcb62d6ff | ||
|
|
8534d570e0 | ||
|
|
60bb979bb7 | ||
|
|
5681bf5693 | ||
|
|
1a26f8176a | ||
|
|
9ef46952e2 | ||
|
|
06bb5f8f0d | ||
|
|
987f426a57 | ||
|
|
6c03c853f6 | ||
|
|
d63cdf3cb1 | ||
|
|
4c482f1cda | ||
|
|
9f7547c68e | ||
|
|
dd6bd675f1 | ||
|
|
c882f1d469 | ||
|
|
9163ced247 | ||
|
|
0c8a1c2ec5 | ||
|
|
f053756416 | ||
|
|
70645de004 | ||
|
|
e91134a95f | ||
|
|
d9030dc07c | ||
|
|
1417d6f5cd | ||
|
|
ef9b538769 | ||
|
|
6a1d8f729f | ||
|
|
bcefe4639e | ||
|
|
cf548fd893 | ||
|
|
89723cf6d0 | ||
|
|
308d0d8f4a | ||
|
|
5483606f74 | ||
|
|
4e2cb68237 | ||
|
|
8d0bb58b5d | ||
|
|
bce7ba16b7 | ||
|
|
7649b3fff0 | ||
|
|
16e7312df1 | ||
|
|
dd42e17b18 | ||
|
|
748bd9e52a | ||
|
|
c403b3b22d | ||
|
|
9c45912627 | ||
|
|
170a65237b | ||
|
|
937e129a55 | ||
|
|
d059cf8109 | ||
|
|
ffa4eb81ca | ||
|
|
04e1b6fcbf | ||
|
|
8106295641 | ||
|
|
5f40d70789 | ||
|
|
83a9b4c417 | ||
|
|
a98a8bb0ba | ||
|
|
590734078c | ||
|
|
0ed5461442 | ||
|
|
c46a1caaf5 | ||
|
|
9c12bc9640 | ||
|
|
90a889a5f8 | ||
|
|
245c01ad45 | ||
|
|
9832fbfac9 | ||
|
|
650e5db110 | ||
|
|
58257266ad | ||
|
|
c10463c961 | ||
|
|
e4dc3e69a1 | ||
|
|
9a756d4ca8 | ||
|
|
f05c6bb829 | ||
|
|
fe60d9d7a4 | ||
|
|
9675773b2a | ||
|
|
1738a6c0b6 | ||
|
|
bc4c015150 | ||
|
|
d28b2225a7 | ||
|
|
fcdbc0e601 | ||
|
|
690c6c24f6 | ||
|
|
ba703d81df | ||
|
|
0ed3e397f2 | ||
|
|
eb818a15bb | ||
|
|
a165d37bb7 | ||
|
|
c574f7f0fd | ||
|
|
a10614df0a | ||
|
|
5f1b2738de | ||
|
|
d7ed0a9fb0 | ||
|
|
655cfb7f0d | ||
|
|
55a702d6bd | ||
|
|
e8ddaf8d98 | ||
|
|
377b8c0993 | ||
|
|
8c652af1a7 | ||
|
|
18641b8411 | ||
|
|
dc63b8df76 | ||
|
|
7c7fc19162 | ||
|
|
c11d040f68 | ||
|
|
4cd2e0fd19 | ||
|
|
61d5c40cd2 | ||
|
|
75f8ddd340 | ||
|
|
8136d54172 | ||
|
|
50e4d2d32a | ||
|
|
c45b123bdb | ||
|
|
4fe3a1c636 | ||
|
|
d9ba866ed0 | ||
|
|
f7e19d3d44 | ||
|
|
fb625665d2 | ||
|
|
ef5da14068 | ||
|
|
f3c6c4c644 | ||
|
|
64cb0bb426 | ||
|
|
4735454c40 | ||
|
|
0e4e1b0fba | ||
|
|
d9961e9efb | ||
|
|
be85922612 | ||
|
|
1e9bed13e5 | ||
|
|
28bd8e959d | ||
|
|
860e2984fd | ||
|
|
13df4bbf12 | ||
|
|
9a7ffd09ac | ||
|
|
21e3023bfb | ||
|
|
2903f5b7f1 | ||
|
|
6e65134b53 | ||
|
|
4bb7087b60 | ||
|
|
de9ad2d469 | ||
|
|
988b2ed138 | ||
|
|
50af9fe70d | ||
|
|
bf78b1beef | ||
|
|
fbee2fe578 | ||
|
|
080e286b1c | ||
|
|
32e4a933b9 | ||
|
|
15645ec096 | ||
|
|
776094e4b2 | ||
|
|
8e6affa627 | ||
|
|
27b1d6a426 | ||
|
|
bb5f153651 | ||
|
|
a2e01a7966 | ||
|
|
b4392a5c7a | ||
|
|
5091040c1d | ||
|
|
755b318e7a | ||
|
|
a41b5f572a | ||
|
|
ba2d02d4e6 | ||
|
|
a14c98c05f | ||
|
|
529658b710 | ||
|
|
11129059e7 | ||
|
|
1f03bb3d41 | ||
|
|
b0a0e4ae6c | ||
|
|
c10be79075 | ||
|
|
6b38a0acba | ||
|
|
84255df928 | ||
|
|
9954268b22 | ||
|
|
6597bccd01 | ||
|
|
a6c7859e22 | ||
|
|
1c7fd9022e | ||
|
|
5120448104 | ||
|
|
8e41790680 | ||
|
|
08317c7744 | ||
|
|
9918af8a12 | ||
|
|
8102a16c3c | ||
|
|
ed47f478f8 | ||
|
|
7cdfa6929d | ||
|
|
16b4f2b138 | ||
|
|
7ccefbab86 | ||
|
|
5abe0f9234 | ||
|
|
29eb6a05c3 | ||
|
|
2c95fae0ab | ||
|
|
545379c99d | ||
|
|
533a0bd328 | ||
|
|
b81ce94c39 | ||
|
|
48c7618752 | ||
|
|
5c63d629a7 | ||
|
|
36e8cd1e00 | ||
|
|
c90b63d476 | ||
|
|
41593cbc54 | ||
|
|
0bba7d2e10 | ||
|
|
a5f0a35f80 | ||
|
|
5bd0c6ea4a | ||
|
|
1929d9374e | ||
|
|
c9900e509a | ||
|
|
029bf8eb22 | ||
|
|
8060efb864 | ||
|
|
3f62f79d12 | ||
|
|
fdc3664187 | ||
|
|
69697d7222 | ||
|
|
419ccc4edf | ||
|
|
b67911c65d | ||
|
|
e9e132b3e6 | ||
|
|
32cbb4fc13 | ||
|
|
9e404bfb06 | ||
|
|
0ea7ced5e3 | ||
|
|
de0a8c6e17 | ||
|
|
f59e4dd7d1 | ||
|
|
85bf744892 | ||
|
|
891e764a23 | ||
|
|
20b3bfb41b | ||
|
|
8a8adce98e | ||
|
|
051b4182f1 | ||
|
|
3685973be8 | ||
|
|
b656e2890b | ||
|
|
f50a47246a | ||
|
|
c104c6e67d | ||
|
|
c96015bbad | ||
|
|
fe372f0efa | ||
|
|
61b2095bf8 | ||
|
|
329c639c1a | ||
|
|
f8962066f0 | ||
|
|
1c499c6b34 | ||
|
|
225e0d5eeb | ||
|
|
f960a13953 | ||
|
|
c8da959dbb | ||
|
|
78db345b82 | ||
|
|
fda12e53c3 | ||
|
|
40d96126e7 | ||
|
|
959217a81c | ||
|
|
91347dd60e | ||
|
|
3be3800dc7 | ||
|
|
0bc9ef0b00 | ||
|
|
5694dddd9f | ||
|
|
b47d55d61f | ||
|
|
14489d80e9 | ||
|
|
de6bd8f29c | ||
|
|
b6309838f1 | ||
|
|
25a276d19b | ||
|
|
f1e2601c27 | ||
|
|
c17d99dc2b | ||
|
|
b3684f6403 | ||
|
|
1afb05d18a | ||
|
|
db98ad86d2 | ||
|
|
1493e3e779 | ||
|
|
3015a0c6de | ||
|
|
beca7f7ec8 | ||
|
|
7e82a94595 | ||
|
|
86866b26a7 | ||
|
|
098b5982b2 | ||
|
|
2a0d20f4b2 | ||
|
|
b117df0bc9 | ||
|
|
316b998f86 | ||
|
|
e873c4ef07 | ||
|
|
dd38d30198 | ||
|
|
3ecd76f185 | ||
|
|
f2ebee9703 | ||
|
|
6eb25882ba | ||
|
|
de0e513eb0 | ||
|
|
496be499fb | ||
|
|
a2c574150f | ||
|
|
48f5a19d30 | ||
|
|
bbf7601a09 | ||
|
|
38291789bf | ||
|
|
7756d5c412 | ||
|
|
3080c176c2 | ||
|
|
01e9796a47 | ||
|
|
45af6006a1 | ||
|
|
c69bccf68b | ||
|
|
40be1e7cd8 | ||
|
|
4ab330986f | ||
|
|
2be2c3c6ad | ||
|
|
a87b40a4be |
Binary file not shown.
@@ -0,0 +1,15 @@
|
||||
## NOTE: Do not edit this file.
|
||||
##
|
||||
vlib work
|
||||
vcom -explicit -93 "../../../PCK_FIO-1.16/PCK_FIO.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_types.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_instr.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_muldiv.vhd"
|
||||
vcom -explicit -93 "../src/tb_mips_muldiv.vhd"
|
||||
vsim -t 1ps -lib work tb_mips_muldiv
|
||||
do {tb_mips_muldiv.wdo}
|
||||
view wave
|
||||
|
||||
view structure
|
||||
view signals
|
||||
run 8ms
|
||||
@@ -0,0 +1,78 @@
|
||||
onerror {resume}
|
||||
quietly WaveActivateNextPane {} 0
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/rst
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/clk
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/mul_divn
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/start
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/busy
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/s_un
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/ref_hi
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/din_hi
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/din_lo
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/hilo_sel
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/hilo_we
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/dout
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/ref_result
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/md_result
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/check
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/uut/pre_sum_vld
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/uut/mul_en
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/uut/sum_en
|
||||
add wave -noupdate -divider FSM
|
||||
add wave -noupdate -format Literal /tb_mips_muldiv/uut/cycle_cnt
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/uut/cycle_cnt_load
|
||||
add wave -noupdate -format Literal /tb_mips_muldiv/uut/cycle_cnt_preset
|
||||
add wave -noupdate -format Literal /tb_mips_muldiv/uut/s
|
||||
add wave -noupdate -format Literal /tb_mips_muldiv/uut/sn
|
||||
add wave -noupdate -divider {Multiplier internals}
|
||||
add wave -noupdate -format Literal -radix hexadecimal -expand /tb_mips_muldiv/uut/pprod
|
||||
add wave -noupdate -format Literal /tb_mips_muldiv/uut/ppadd_cyi
|
||||
add wave -noupdate -format Literal /tb_mips_muldiv/uut/ppadd_cyo
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/ppadd_op1
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/ppadd_op2
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/ppadd_res
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/pp_op2
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/pp_op2_r
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/add_op1
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/add_op2
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/add_res
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/pp_reg
|
||||
add wave -noupdate -divider {Divider internals}
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/busy
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/s_un
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/uut/div_start
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/din_hi
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/din_lo
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/result
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/uut/div_add_cyi
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/div_add_op1
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/div_add_op2
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/div_add_res
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/div_m
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/div_m_n
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/div_a
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_muldiv/uut/div_q
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/uut/div_qbit
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/uut/div_en
|
||||
add wave -noupdate -divider FSM
|
||||
add wave -noupdate -format Literal /tb_mips_muldiv/uut/cycle_cnt
|
||||
add wave -noupdate -format Logic /tb_mips_muldiv/uut/cycle_cnt_load
|
||||
add wave -noupdate -format Literal /tb_mips_muldiv/uut/cycle_cnt_preset
|
||||
add wave -noupdate -format Literal /tb_mips_muldiv/uut/s
|
||||
add wave -noupdate -format Literal /tb_mips_muldiv/uut/sn
|
||||
TreeUpdate [SetDefaultTree]
|
||||
WaveRestoreCursors {{Cursor 1} {7735999838 ps} 0} {{Cursor 2} {512321 ps} 0}
|
||||
configure wave -namecolwidth 149
|
||||
configure wave -valuecolwidth 171
|
||||
configure wave -justifyvalue left
|
||||
configure wave -signalnamewidth 1
|
||||
configure wave -snapdistance 10
|
||||
configure wave -datasetprefix 0
|
||||
configure wave -rowmargin 4
|
||||
configure wave -childrowmargin 2
|
||||
configure wave -gridoffset 0
|
||||
configure wave -gridperiod 100
|
||||
configure wave -griddelta 40
|
||||
configure wave -timeline 1
|
||||
update
|
||||
WaveRestoreZoom {0 ps} {8400 us}
|
||||
@@ -0,0 +1,57 @@
|
||||
## NOTE: Do not edit this file.
|
||||
##
|
||||
vlib work
|
||||
|
||||
# RAMS
|
||||
vcom -explicit -93 "../../../misc/dpram_2w2r.vhd"
|
||||
vcom -explicit -93 "../../../misc/dpram_1w1r.vhd"
|
||||
vcom -explicit -93 "../../../misc/dpram_1w1r_dist.vhd"
|
||||
|
||||
# FIFOS
|
||||
vcom -explicit -93 "../../../FIFO/src/fifo_ctrl_pkg.vhd"
|
||||
vcom -explicit -93 "../../../FIFO/src/sync_fifo_ctrl.vhd"
|
||||
vcom -explicit -93 "../../../FIFO/src/fifo_sync_dist.vhd"
|
||||
|
||||
# UART
|
||||
vcom -explicit -93 "../../../uart/bbfifo_16x8.vhd"
|
||||
vcom -explicit -93 "../../../uart/kcuart_rx.vhd"
|
||||
vcom -explicit -93 "../../../uart/kcuart_tx.vhd"
|
||||
vcom -explicit -93 "../../../uart/uart_rx.vhd"
|
||||
vcom -explicit -93 "../../../uart/uart_tx.vhd"
|
||||
vcom -explicit -93 "../../../uart/uart_wb.vhd"
|
||||
|
||||
# GPIO
|
||||
vcom -explicit -93 "../../../misc/gpio_wb.vhd"
|
||||
|
||||
# Async port
|
||||
vcom -explicit -93 "../../../misc/async_types.vhd"
|
||||
vcom -explicit -93 "../../../misc/async_port_wb.vhd"
|
||||
vcom -explicit -93 "../src/async_defs.vhd"
|
||||
|
||||
# ROM
|
||||
vcom -explicit -93 "../src/bootloader.ROM.vhd"
|
||||
vcom -explicit -93 "../../../misc/rom_wb.vhd"
|
||||
|
||||
# MIPS
|
||||
vcom -explicit -93 "../src/core/mips_types.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_instr.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_idecode_rom.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_reg.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_shifter.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_alu.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_muldiv.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_cop.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_icache.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_dcache.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_biu.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_bcu.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_pipeline.vhd"
|
||||
vcom -explicit -93 "../src/core/mips_top.vhd"
|
||||
|
||||
vcom -explicit -93 "../src/tb_mips_top.vhd"
|
||||
vsim -t 1ps -lib work tb_mips_top
|
||||
do {tb_mips_top.wdo}
|
||||
view wave
|
||||
view structure
|
||||
view signals
|
||||
run 1600us
|
||||
@@ -0,0 +1,67 @@
|
||||
onerror {resume}
|
||||
quietly WaveActivateNextPane {} 0
|
||||
add wave -noupdate -divider {TOP interface}
|
||||
add wave -noupdate -format Logic /tb_mips_top/clk
|
||||
add wave -noupdate -format Literal /tb_mips_top/debug
|
||||
add wave -noupdate -format Logic /tb_mips_top/stb_o
|
||||
add wave -noupdate -format Logic /tb_mips_top/ack_i
|
||||
add wave -noupdate -format Logic /tb_mips_top/srdy_i
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/addr_o
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/dat_i
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/dat_o
|
||||
add wave -noupdate -format Logic /tb_mips_top/we_o
|
||||
add wave -noupdate -format Literal /tb_mips_top/sel_o
|
||||
add wave -noupdate -format Logic /tb_mips_top/cyc_o
|
||||
add wave -noupdate -format Logic /tb_mips_top/mrdy_o
|
||||
add wave -noupdate -format Literal /tb_mips_top/int
|
||||
add wave -noupdate -divider {External components}
|
||||
add wave -noupdate -format Logic /tb_mips_top/clk
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/gpo0
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/gpo1
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/gpi0
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/gpi1
|
||||
add wave -noupdate -format Logic /tb_mips_top/clk
|
||||
add wave -noupdate -format Logic /tb_mips_top/rx
|
||||
add wave -noupdate -format Logic /tb_mips_top/tx
|
||||
add wave -noupdate -format Logic /tb_mips_top/clk
|
||||
add wave -noupdate -format Literal /tb_mips_top/mem_area
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/sram_a
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/sram_d
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/flash_a
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/flash_d
|
||||
add wave -noupdate -format Logic /tb_mips_top/flash_cs_n
|
||||
add wave -noupdate -format Logic /tb_mips_top/flash_oe_n
|
||||
add wave -noupdate -format Logic /tb_mips_top/sram_cs_n
|
||||
add wave -noupdate -format Literal /tb_mips_top/sram_wr_n
|
||||
add wave -noupdate -format Logic /tb_mips_top/sram_oe_n
|
||||
add wave -noupdate -divider ALU
|
||||
add wave -noupdate -format Logic /tb_mips_top/clk
|
||||
add wave -noupdate -format Literal /tb_mips_top/uut/inst_pipeline/hdu
|
||||
add wave -noupdate -divider PC
|
||||
add wave -noupdate -format Logic /tb_mips_top/clk
|
||||
add wave -noupdate -format Literal -radix hexadecimal /tb_mips_top/uut/inst_pipeline/pc
|
||||
add wave -noupdate -divider PC
|
||||
add wave -noupdate -format Logic /tb_mips_top/clk
|
||||
add wave -noupdate -format Literal -radix hexadecimal -expand /tb_mips_top/uut/inst_pipeline/id_stage
|
||||
add wave -noupdate -format Logic /tb_mips_top/clk
|
||||
add wave -noupdate -format Literal -radix hexadecimal -expand /tb_mips_top/uut/inst_pipeline/ex_stage
|
||||
add wave -noupdate -format Logic /tb_mips_top/clk
|
||||
add wave -noupdate -format Literal -radix hexadecimal -expand /tb_mips_top/uut/inst_pipeline/mem_stage
|
||||
add wave -noupdate -format Logic /tb_mips_top/clk
|
||||
add wave -noupdate -format Literal -radix hexadecimal -expand /tb_mips_top/uut/inst_pipeline/wb_stage
|
||||
TreeUpdate [SetDefaultTree]
|
||||
WaveRestoreCursors {{Cursor 1} {1199854590 ps} 0}
|
||||
configure wave -namecolwidth 188
|
||||
configure wave -valuecolwidth 100
|
||||
configure wave -justifyvalue left
|
||||
configure wave -signalnamewidth 1
|
||||
configure wave -snapdistance 10
|
||||
configure wave -datasetprefix 0
|
||||
configure wave -rowmargin 4
|
||||
configure wave -childrowmargin 2
|
||||
configure wave -gridoffset 0
|
||||
configure wave -gridperiod 100
|
||||
configure wave -griddelta 40
|
||||
configure wave -timeline 1
|
||||
update
|
||||
WaveRestoreZoom {0 ps} {1260 us}
|
||||
@@ -0,0 +1,60 @@
|
||||
-------------------------------------------------------------------------
|
||||
-- Project: MIPS System controller
|
||||
-- This file:
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
USE IEEE.STD_LOGIC_1164.ALL;
|
||||
USE IEEE.NUMERIC_STD.ALL;
|
||||
|
||||
use work.async_types.all;
|
||||
|
||||
package async_defs is
|
||||
|
||||
constant ts_flash : async_timespec_t :=
|
||||
(
|
||||
ncyc_access => 1,
|
||||
ncyc_pulse_rd => 12,
|
||||
ncyc_pulse_wr => 7,
|
||||
ncyc_cs_hold => 1,
|
||||
ncyc_release => 1,
|
||||
ncyc_pulse_rst => 8,
|
||||
pol_cs => '0',
|
||||
pol_oe => '0',
|
||||
pol_we => '0',
|
||||
pol_rst => '0'
|
||||
);
|
||||
|
||||
constant ts_sram : async_timespec_t :=
|
||||
(
|
||||
ncyc_access => 1,
|
||||
ncyc_pulse_rd => 12,
|
||||
ncyc_pulse_wr => 7,
|
||||
ncyc_cs_hold => 1,
|
||||
ncyc_release => 1,
|
||||
ncyc_pulse_rst => 8,
|
||||
pol_cs => '0',
|
||||
pol_oe => '0',
|
||||
pol_we => '0',
|
||||
pol_rst => '0'
|
||||
);
|
||||
|
||||
end async_defs;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,431 @@
|
||||
LIBRARY IEEE;
|
||||
USE IEEE.STD_LOGIC_1164.ALL;
|
||||
USE IEEE.NUMERIC_STD.ALL;
|
||||
use IEEE.MATH_REAL.ALL;
|
||||
|
||||
library work;
|
||||
use work.mips_types.all;
|
||||
|
||||
ENTITY dcache IS
|
||||
Generic
|
||||
(
|
||||
cache_size : natural := 2048; -- words
|
||||
line_size : natural := 8 -- words
|
||||
);
|
||||
Port
|
||||
(
|
||||
RST_I : in STD_LOGIC;
|
||||
CLK_I : in STD_LOGIC;
|
||||
ACK_I : in STD_LOGIC;
|
||||
SRDY_I : in STD_LOGIC;
|
||||
ADDR_O : out word_t;
|
||||
DAT_I : in word_t;
|
||||
STB_O : out STD_LOGIC;
|
||||
CYC_O : out STD_LOGIC;
|
||||
en : in STD_LOGIC;
|
||||
cpu_en : in STD_LOGIC;
|
||||
cpu_we : in STD_LOGIC;
|
||||
cpu_be : in unsigned(3 downto 0);
|
||||
cpu_addr : in word_t;
|
||||
cpu_din : in word_t;
|
||||
cpu_dout : out word_t;
|
||||
cpu_busy : out STD_LOGIC
|
||||
);
|
||||
END dcache;
|
||||
|
||||
ARCHITECTURE behavior OF dcache IS
|
||||
|
||||
COMPONENT dpram_1w1r
|
||||
GENERIC
|
||||
(
|
||||
addr_width : integer := 3;
|
||||
data_width : integer := 8
|
||||
);
|
||||
PORT (
|
||||
clka : in STD_LOGIC;
|
||||
clkb : in STD_LOGIC;
|
||||
en_a : in STD_LOGIC;
|
||||
en_b : in STD_LOGIC;
|
||||
we_a : in STD_LOGIC;
|
||||
addr_a : in unsigned (addr_width-1 downto 0);
|
||||
addr_b : in unsigned (addr_width-1 downto 0);
|
||||
din_a : in unsigned (data_width-1 downto 0);
|
||||
dout_b : out unsigned (data_width-1 downto 0)
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
COMPONENT dpram_2w2r is
|
||||
GENERIC
|
||||
(
|
||||
addr_width : integer := 3;
|
||||
data_width : integer := 8
|
||||
);
|
||||
PORT
|
||||
(
|
||||
clk_a : in STD_LOGIC;
|
||||
clk_b : in STD_LOGIC;
|
||||
en_a : in STD_LOGIC;
|
||||
en_b : in STD_LOGIC;
|
||||
we_a : in STD_LOGIC;
|
||||
we_b : in STD_LOGIC;
|
||||
addr_a : in unsigned (addr_width-1 downto 0);
|
||||
addr_b : in unsigned (addr_width-1 downto 0);
|
||||
din_a : in unsigned (data_width-1 downto 0);
|
||||
din_b : in unsigned (data_width-1 downto 0);
|
||||
dout_a : out unsigned (data_width-1 downto 0);
|
||||
dout_b : out unsigned (data_width-1 downto 0)
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
function lg2(x : natural) return natural is
|
||||
begin
|
||||
return natural(ceil(log2(real(x))));
|
||||
end lg2;
|
||||
|
||||
function po2(x : natural) return natural is
|
||||
begin
|
||||
|
||||
return 2**lg2(x);
|
||||
end po2;
|
||||
|
||||
constant word_index_width : natural := lg2(line_size);
|
||||
constant cache_index_width : natural := lg2(cache_size) - word_index_width;
|
||||
constant tag_width : natural := 32 - word_index_width - cache_index_width - 2;
|
||||
constant tag_parity_width : natural := 3;
|
||||
constant tram_data_width : natural := 1 + tag_parity_width + tag_width;
|
||||
constant tram_addr_width : natural := cache_index_width;
|
||||
|
||||
subtype tram_data_t is unsigned (tram_data_width-1 downto 0);
|
||||
|
||||
type dcache_entry_t is record
|
||||
valid : std_logic;
|
||||
tv_p : unsigned(tag_parity_width-1 downto 0);
|
||||
tag : unsigned(tag_width-1 downto 0);
|
||||
end record;
|
||||
|
||||
alias cpu_word_index is cpu_addr(word_index_width+1 downto 2);
|
||||
alias cpu_cache_index is cpu_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
|
||||
alias cpu_tag is cpu_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
|
||||
|
||||
function to_dcache_entry(x : tram_data_t) return dcache_entry_t is
|
||||
variable result : dcache_entry_t;
|
||||
begin
|
||||
result.valid := x(0);
|
||||
result.tv_p := x(3 downto 1);
|
||||
result.tag := x(tag_width+3 downto 4);
|
||||
|
||||
return result;
|
||||
end to_dcache_entry;
|
||||
|
||||
function to_tram_data(x : dcache_entry_t) return tram_data_t is
|
||||
variable result : tram_data_t;
|
||||
begin
|
||||
result(0) := x.valid;
|
||||
result(3 downto 1) := x.tv_p;
|
||||
result(tag_width+3 downto 4) := x.tag;
|
||||
|
||||
return result;
|
||||
end to_tram_data;
|
||||
|
||||
type cache_state_t is (init, ready, flush, mem_request, mem_access, mem_wait, mem_data, upd_cache, rd_cache);
|
||||
signal s, sn : cache_state_t;
|
||||
|
||||
signal cache_busy : std_logic;
|
||||
signal cache_hit : std_logic;
|
||||
signal tag_match : std_logic;
|
||||
signal word_index_reg : unsigned(word_index_width-1 downto 0);
|
||||
signal cache_index_reg : unsigned(cache_index_width-1 downto 0);
|
||||
signal tag_index_reg : unsigned(tag_width-1 downto 0);
|
||||
|
||||
signal cache_entry_in : dcache_entry_t;
|
||||
signal cache_entry_out : dcache_entry_t;
|
||||
signal cpu_dram_addr : unsigned(lg2(cache_size)-1 downto 0);
|
||||
signal cpu_dram_dout : word_t;
|
||||
signal cpu_dram_din : word_t;
|
||||
signal cpu_data_reg : word_t;
|
||||
signal cpu_be_reg : unsigned(3 downto 0);
|
||||
signal cpu_we_reg : std_logic;
|
||||
signal ctrl_dram_en : std_logic;
|
||||
signal ctrl_dram_addr : unsigned(lg2(cache_size)-1 downto 0);
|
||||
signal ctrl_dram_din : word_t;
|
||||
signal ctrl_dram_we : unsigned(3 downto 0);
|
||||
signal cpu_dram_we : unsigned(3 downto 0);
|
||||
signal cpu_dram_en : std_logic;
|
||||
signal cpu_en2 : std_logic;
|
||||
signal cpu_we2 : std_logic;
|
||||
|
||||
signal tram_addr_rd : unsigned(cache_index_width-1 downto 0);
|
||||
signal tram_dout : tram_data_t;
|
||||
signal tram_addr_wr : unsigned(cache_index_width-1 downto 0);
|
||||
signal tram_din : tram_data_t;
|
||||
signal tram_re : std_logic;
|
||||
signal tram_we : std_logic;
|
||||
|
||||
signal ram_index_count : natural range 0 to 2**word_index_width-1;
|
||||
signal ram_index_count_rst : std_logic;
|
||||
signal cache_index_count : natural range 0 to 2**cache_index_width-1;
|
||||
signal cache_index_count_en : std_logic;
|
||||
signal mem_index_count : natural range 0 to 2**word_index_width-1;
|
||||
signal mem_index_count_en : std_logic;
|
||||
signal mem_index_count_rst : std_logic;
|
||||
signal cpu_reg_en : std_logic;
|
||||
signal was_miss : std_logic;
|
||||
signal data_write : std_logic;
|
||||
signal cpu_hit_we : std_logic;
|
||||
signal instant_raw : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
cpu_hit_we <= cpu_we2 and cache_hit;
|
||||
|
||||
cpu_index_register:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if RST_I = '1' then
|
||||
cache_index_reg <= (others => '0');
|
||||
tag_index_reg <= (others => '0');
|
||||
elsif cpu_reg_en = '1' and en = '1' and instant_raw = '0' then
|
||||
word_index_reg <= cpu_word_index;
|
||||
cache_index_reg <= cpu_cache_index;
|
||||
tag_index_reg <= cpu_tag;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cpu_data_register:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if RST_I = '1' then
|
||||
cpu_we_reg <= '0';
|
||||
elsif cpu_reg_en = '1' and en = '1' then
|
||||
cpu_data_reg <= cpu_din;
|
||||
cpu_be_reg <= cpu_be;
|
||||
cpu_we_reg <= cpu_we;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cpu_was_wr_register:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
cpu_en2 <= '0';
|
||||
cpu_we2 <= '0';
|
||||
if cpu_en = '1' and en = '1' then
|
||||
cpu_we2 <= cpu_we;
|
||||
cpu_en2 <= '1';
|
||||
cpu_dram_din <= cpu_din;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
instant_raw_logic:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
instant_raw <= cpu_hit_we and cpu_en and en and not cpu_we;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
inst_tag_ram : dpram_1w1r
|
||||
GENERIC MAP (
|
||||
addr_width => tram_addr_width,
|
||||
data_width => tram_data_width
|
||||
)
|
||||
PORT MAP (
|
||||
clka => CLK_I,
|
||||
clkb => CLK_I,
|
||||
en_a => '1',
|
||||
en_b => tram_re,
|
||||
we_a => tram_we,
|
||||
addr_a => tram_addr_wr,
|
||||
addr_b => tram_addr_rd,
|
||||
din_a => tram_din,
|
||||
dout_b => tram_dout
|
||||
);
|
||||
|
||||
gen_data_ram:
|
||||
for i in 0 to 3 generate
|
||||
begin
|
||||
|
||||
inst_data_ram : dpram_2w2r
|
||||
GENERIC MAP (
|
||||
addr_width => lg2(cache_size),
|
||||
data_width => word_t'length/4
|
||||
)
|
||||
PORT MAP (
|
||||
clk_a => CLK_I,
|
||||
clk_b => CLK_I,
|
||||
en_a => ctrl_dram_en,
|
||||
en_b => '1',
|
||||
we_a => ctrl_dram_we(i),
|
||||
we_b => cpu_dram_we(i),
|
||||
addr_a => ctrl_dram_addr,
|
||||
addr_b => cpu_dram_addr,
|
||||
din_a => ctrl_dram_din(8*(i+1)-1 downto 8*i),
|
||||
din_b => cpu_dram_din(8*(i+1)-1 downto 8*i),
|
||||
dout_a => open,
|
||||
dout_b => cpu_dram_dout(8*(i+1)-1 downto 8*i)
|
||||
);
|
||||
end generate;
|
||||
|
||||
cache_state_next:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if RST_I = '1' then
|
||||
s <= init;
|
||||
else
|
||||
s <= sn;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cpu_busy <= cache_busy or instant_raw;
|
||||
cpu_dout <= cpu_dram_dout;
|
||||
|
||||
tag_match <= '1' when tag_index_reg = cache_entry_out.tag else '0';
|
||||
cache_hit <= tag_match and cache_entry_out.valid;
|
||||
tram_din <= to_tram_data(cache_entry_in);
|
||||
tram_addr_rd <= cpu_cache_index when was_miss = '0' else cache_index_reg;
|
||||
cache_entry_out <= to_dcache_entry(tram_dout);
|
||||
cpu_dram_addr <= (cpu_cache_index & cpu_word_index) when (was_miss = '0' and cpu_hit_we = '0' and instant_raw = '0') else (cache_index_reg & word_index_reg);
|
||||
ADDR_O <= tag_index_reg & cache_index_reg & to_unsigned(mem_index_count, word_index_width) & "00";
|
||||
ctrl_dram_addr <= cache_index_reg & to_unsigned(ram_index_count, word_index_width);
|
||||
ctrl_dram_din <= DAT_I;
|
||||
ctrl_dram_we <= (others => '1');
|
||||
ctrl_dram_en <= data_write and ACK_I;
|
||||
cpu_dram_we <= cpu_be_reg when (cpu_hit_we = '1') else (others => '0');
|
||||
|
||||
cache_state:
|
||||
process(s, instant_raw, cache_hit, cache_index_count, ram_index_count, mem_index_count, cache_index_reg, ACK_I, tag_index_reg, cpu_en, SRDY_I, cpu_en2, cpu_we_reg)
|
||||
begin
|
||||
cpu_reg_en <= '0';
|
||||
cache_busy <= '1';
|
||||
tram_we <= '0';
|
||||
cache_index_count_en <= '0';
|
||||
ram_index_count_rst <= '0';
|
||||
mem_index_count_en <= '0';
|
||||
mem_index_count_rst <= '0';
|
||||
CYC_O <= '0';
|
||||
STB_O <= '0';
|
||||
tram_re <= '0';
|
||||
was_miss <= '0';
|
||||
data_write <= '0';
|
||||
tram_addr_wr <= to_unsigned(cache_index_count, cache_index_width);
|
||||
cache_entry_in.tv_p <= (others => '0');
|
||||
cache_entry_in.tag <= tag_index_reg;
|
||||
cache_entry_in.valid <= '0';
|
||||
sn <= s;
|
||||
|
||||
case s is
|
||||
when init =>
|
||||
sn <= flush;
|
||||
when ready =>
|
||||
cache_busy <= '0';
|
||||
cpu_reg_en <= '1';
|
||||
tram_re <= cpu_en;
|
||||
if cpu_en2 = '1' then
|
||||
if cache_hit = '0' and cpu_we_reg = '0' then
|
||||
sn <= mem_request;
|
||||
cpu_reg_en <= '0';
|
||||
cache_busy <= '1';
|
||||
CYC_O <= '1';
|
||||
end if;
|
||||
end if;
|
||||
when flush =>
|
||||
cache_index_count_en <= '1';
|
||||
tram_addr_wr <= to_unsigned(cache_index_count, cache_index_width);
|
||||
tram_we <= '1';
|
||||
cache_entry_in.valid <= '0';
|
||||
cache_entry_in.tag <= (others => '0');
|
||||
if cache_index_count = 0 then
|
||||
sn <= ready;
|
||||
if cpu_en = '1' then
|
||||
cpu_reg_en <= '1';
|
||||
tram_re <= '1';
|
||||
end if;
|
||||
end if;
|
||||
when mem_request =>
|
||||
ram_index_count_rst <= '1';
|
||||
mem_index_count_rst <= '1';
|
||||
CYC_O <= '1';
|
||||
if SRDY_I = '1' then
|
||||
sn <= mem_access;
|
||||
end if;
|
||||
when mem_access =>
|
||||
data_write <= '1';
|
||||
mem_index_count_en <= '1';
|
||||
CYC_O <= '1';
|
||||
STB_O <= '1';
|
||||
if mem_index_count = 2**word_index_width-1 then
|
||||
if SRDY_I = '1' then
|
||||
sn <= mem_data;
|
||||
end if;
|
||||
end if;
|
||||
when mem_data =>
|
||||
CYC_O <= '1';
|
||||
data_write <= '1';
|
||||
if ram_index_count = 2**word_index_width-1 then
|
||||
if ACK_I = '1' then
|
||||
sn <= upd_cache;
|
||||
end if;
|
||||
end if;
|
||||
when upd_cache =>
|
||||
tram_addr_wr <= cache_index_reg;
|
||||
tram_we <= '1';
|
||||
cache_entry_in.valid <= '1';
|
||||
sn <= rd_cache;
|
||||
when rd_cache =>
|
||||
tram_re <= '1';
|
||||
was_miss <= '1';
|
||||
sn <= ready;
|
||||
|
||||
when others =>
|
||||
sn <= ready;
|
||||
end case;
|
||||
end process;
|
||||
|
||||
cache_index_counter:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if cache_index_count_en = '0' then
|
||||
cache_index_count <= 2**cache_index_width-1;
|
||||
elsif cache_index_count /= 0 then
|
||||
cache_index_count <= cache_index_count - 1;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
ram_index_counter:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if ram_index_count_rst = '1' then
|
||||
ram_index_count <= 0;
|
||||
elsif data_write = '1' and ACK_I = '1' then
|
||||
if ram_index_count /= 2**word_index_width-1 then
|
||||
ram_index_count <= ram_index_count + 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
mem_index_counter:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if mem_index_count_rst = '1' then
|
||||
mem_index_count <= 0;
|
||||
elsif mem_index_count_en = '1' and SRDY_I = '1' then
|
||||
if mem_index_count /= 2**word_index_width-1 then
|
||||
mem_index_count <= mem_index_count + 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end behavior;
|
||||
@@ -0,0 +1,354 @@
|
||||
LIBRARY IEEE;
|
||||
USE IEEE.STD_LOGIC_1164.ALL;
|
||||
USE IEEE.NUMERIC_STD.ALL;
|
||||
use IEEE.MATH_REAL.ALL;
|
||||
|
||||
library work;
|
||||
use work.mips_types.all;
|
||||
|
||||
ENTITY icache IS
|
||||
Generic
|
||||
(
|
||||
cache_size : natural := 2048; -- words
|
||||
line_size : natural := 8 -- words
|
||||
);
|
||||
Port
|
||||
(
|
||||
RST_I : in STD_LOGIC;
|
||||
CLK_I : in STD_LOGIC;
|
||||
ACK_I : in STD_LOGIC;
|
||||
SRDY_I : in STD_LOGIC;
|
||||
ADDR_O : out word_t;
|
||||
DAT_I : in word_t;
|
||||
STB_O : out STD_LOGIC;
|
||||
CYC_O : out STD_LOGIC;
|
||||
en : in STD_LOGIC;
|
||||
cpu_en : in STD_LOGIC;
|
||||
cpu_addr : in word_t;
|
||||
cpu_dout : out word_t;
|
||||
cpu_busy : out STD_LOGIC
|
||||
);
|
||||
END icache;
|
||||
|
||||
ARCHITECTURE behavior OF icache IS
|
||||
|
||||
COMPONENT dpram_1w1r
|
||||
GENERIC
|
||||
(
|
||||
addr_width : integer := 3;
|
||||
data_width : integer := 8
|
||||
);
|
||||
PORT (
|
||||
clka : in STD_LOGIC;
|
||||
clkb : in STD_LOGIC;
|
||||
en_a : in STD_LOGIC;
|
||||
en_b : in STD_LOGIC;
|
||||
we_a : in STD_LOGIC;
|
||||
addr_a : in unsigned (addr_width-1 downto 0);
|
||||
addr_b : in unsigned (addr_width-1 downto 0);
|
||||
din_a : in unsigned (data_width-1 downto 0);
|
||||
dout_b : out unsigned (data_width-1 downto 0)
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
function lg2(x : natural) return natural is
|
||||
begin
|
||||
return natural(ceil(log2(real(x))));
|
||||
end lg2;
|
||||
|
||||
function po2(x : natural) return natural is
|
||||
begin
|
||||
|
||||
return 2**lg2(x);
|
||||
end po2;
|
||||
|
||||
constant word_index_width : natural := lg2(line_size);
|
||||
constant cache_index_width : natural := lg2(cache_size) - word_index_width;
|
||||
constant tag_width : natural := 32 - word_index_width - cache_index_width - 2;
|
||||
constant tag_parity_width : natural := 3;
|
||||
constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
|
||||
constant tag_ram_addr_width : natural := cache_index_width;
|
||||
|
||||
subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
|
||||
|
||||
type icache_entry_t is record
|
||||
valid : std_logic;
|
||||
tv_p : unsigned(tag_parity_width-1 downto 0);
|
||||
tag : unsigned(tag_width-1 downto 0);
|
||||
end record;
|
||||
|
||||
alias cpu_word_index is cpu_addr(word_index_width+1 downto 2);
|
||||
alias cpu_cache_index is cpu_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
|
||||
alias cpu_tag is cpu_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
|
||||
|
||||
function to_icache_entry(x : tag_ram_data_t) return icache_entry_t is
|
||||
variable result : icache_entry_t;
|
||||
begin
|
||||
result.valid := x(0);
|
||||
result.tv_p := x(3 downto 1);
|
||||
result.tag := x(tag_width+3 downto 4);
|
||||
|
||||
return result;
|
||||
end to_icache_entry;
|
||||
|
||||
function to_tag_ram_data(x : icache_entry_t) return tag_ram_data_t is
|
||||
variable result : tag_ram_data_t;
|
||||
begin
|
||||
result(0) := x.valid;
|
||||
result(3 downto 1) := x.tv_p;
|
||||
result(tag_width+3 downto 4) := x.tag;
|
||||
|
||||
return result;
|
||||
end to_tag_ram_data;
|
||||
|
||||
type cache_state_t is (init, ready, flush, mem_request, mem_access, mem_wait, mem_data, upd_cache, rd_cache);
|
||||
signal s, sn : cache_state_t;
|
||||
|
||||
signal cache_busy : std_logic;
|
||||
signal cache_miss : std_logic;
|
||||
signal tag_match : std_logic;
|
||||
signal word_index_reg : unsigned(word_index_width-1 downto 0);
|
||||
signal cache_index_reg : unsigned(cache_index_width-1 downto 0);
|
||||
signal tag_index_reg : unsigned(tag_width-1 downto 0);
|
||||
|
||||
signal cache_entry_in : icache_entry_t;
|
||||
signal cache_entry_out : icache_entry_t;
|
||||
signal data_ram_addr_rd : unsigned(lg2(cache_size)-1 downto 0);
|
||||
signal data_ram_data_rd : word_t;
|
||||
signal data_ram_addr_wr : unsigned(lg2(cache_size)-1 downto 0);
|
||||
signal data_ram_data_wr : word_t;
|
||||
signal data_ram_we : std_logic;
|
||||
signal data_ram_re : std_logic;
|
||||
|
||||
signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
|
||||
signal tag_ram_data_rd : tag_ram_data_t;
|
||||
signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
|
||||
signal tag_ram_data_wr : tag_ram_data_t;
|
||||
signal tag_ram_re : std_logic;
|
||||
signal tag_ram_we : std_logic;
|
||||
|
||||
signal ram_index_count : natural range 0 to 2**word_index_width-1;
|
||||
signal ram_index_count_rst : std_logic;
|
||||
signal cache_index_count : natural range 0 to 2**cache_index_width-1;
|
||||
signal cache_index_count_en : std_logic;
|
||||
signal mem_index_count : natural range 0 to 2**word_index_width-1;
|
||||
signal mem_index_count_en : std_logic;
|
||||
signal mem_index_count_rst : std_logic;
|
||||
signal cpu_reg_en : std_logic;
|
||||
signal was_miss : std_logic;
|
||||
signal data_write : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
|
||||
cpu_index_reg:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if RST_I = '1' then
|
||||
cache_index_reg <= (others => '0');
|
||||
tag_index_reg <= (others => '0');
|
||||
elsif cpu_reg_en = '1' then
|
||||
word_index_reg <= cpu_word_index;
|
||||
cache_index_reg <= cpu_cache_index;
|
||||
tag_index_reg <= cpu_tag;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
inst_tag_ram : dpram_1w1r
|
||||
GENERIC MAP (
|
||||
addr_width => tag_ram_addr_width,
|
||||
data_width => tag_ram_data_width
|
||||
)
|
||||
PORT MAP (
|
||||
clka => CLK_I,
|
||||
clkb => CLK_I,
|
||||
en_a => '1',
|
||||
en_b => tag_ram_re,
|
||||
we_a => tag_ram_we,
|
||||
addr_a => tag_ram_addr_wr,
|
||||
addr_b => tag_ram_addr_rd,
|
||||
din_a => tag_ram_data_wr,
|
||||
dout_b => tag_ram_data_rd
|
||||
);
|
||||
|
||||
inst_data_ram : dpram_1w1r
|
||||
GENERIC MAP (
|
||||
addr_width => lg2(cache_size),
|
||||
data_width => word_t'length
|
||||
)
|
||||
PORT MAP (
|
||||
clka => CLK_I,
|
||||
clkb => CLK_I,
|
||||
en_a => '1',
|
||||
en_b => data_ram_re,
|
||||
we_a => data_ram_we,
|
||||
addr_a => data_ram_addr_wr,
|
||||
addr_b => data_ram_addr_rd,
|
||||
din_a => data_ram_data_wr,
|
||||
dout_b => data_ram_data_rd
|
||||
);
|
||||
|
||||
|
||||
cache_state_next:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if RST_I = '1' then
|
||||
s <= init;
|
||||
else
|
||||
s <= sn;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cpu_busy <= cache_busy;
|
||||
cpu_dout <= data_ram_data_rd;
|
||||
|
||||
tag_match <= '1' when tag_index_reg = cache_entry_out.tag else '0';
|
||||
cache_miss <= not (tag_match and cache_entry_out.valid);
|
||||
tag_ram_data_wr <= to_tag_ram_data(cache_entry_in);
|
||||
tag_ram_addr_rd <= cpu_cache_index when was_miss = '0' else cache_index_reg;
|
||||
cache_entry_out <= to_icache_entry(tag_ram_data_rd);
|
||||
data_ram_addr_rd <= (cpu_cache_index & cpu_word_index) when was_miss = '0' else (cache_index_reg & word_index_reg);
|
||||
ADDR_O <= tag_index_reg & cache_index_reg & to_unsigned(mem_index_count, word_index_width) & "00";
|
||||
data_ram_addr_wr <= cache_index_reg & to_unsigned(ram_index_count, word_index_width);
|
||||
data_ram_data_wr <= DAT_I;
|
||||
data_ram_we <= data_write and ACK_I;
|
||||
|
||||
cache_state:
|
||||
process(s, cache_miss, cache_index_count, ram_index_count, mem_index_count, cache_index_reg, ACK_I, tag_index_reg, cpu_en, SRDY_I, en)
|
||||
begin
|
||||
cpu_reg_en <= '0';
|
||||
cache_busy <= '1';
|
||||
tag_ram_we <= '0';
|
||||
cache_index_count_en <= '0';
|
||||
ram_index_count_rst <= '0';
|
||||
mem_index_count_en <= '0';
|
||||
mem_index_count_rst <= '0';
|
||||
CYC_O <= '0';
|
||||
STB_O <= '0';
|
||||
data_ram_re <= '0';
|
||||
tag_ram_re <= '0';
|
||||
was_miss <= '0';
|
||||
data_write <= '0';
|
||||
tag_ram_addr_wr <= to_unsigned(cache_index_count, cache_index_width);
|
||||
cache_entry_in.tv_p <= (others => '0');
|
||||
cache_entry_in.tag <= tag_index_reg;
|
||||
cache_entry_in.valid <= '0';
|
||||
sn <= s;
|
||||
|
||||
case s is
|
||||
when init =>
|
||||
sn <= flush;
|
||||
when ready =>
|
||||
if en = '1' then
|
||||
cache_busy <= '0';
|
||||
if cache_miss = '1' then
|
||||
sn <= mem_request;
|
||||
cpu_reg_en <= '0';
|
||||
cache_busy <= '1';
|
||||
CYC_O <= '1';
|
||||
elsif cpu_en = '1' then
|
||||
cpu_reg_en <= '1';
|
||||
data_ram_re <= '1';
|
||||
tag_ram_re <= '1';
|
||||
end if;
|
||||
end if;
|
||||
when flush =>
|
||||
cache_index_count_en <= '1';
|
||||
tag_ram_addr_wr <= to_unsigned(cache_index_count, cache_index_width);
|
||||
tag_ram_we <= '1';
|
||||
cache_entry_in.valid <= '0';
|
||||
cache_entry_in.tag <= (others => '0');
|
||||
if cache_index_count = 0 then
|
||||
sn <= ready;
|
||||
if cpu_en = '1' then
|
||||
cpu_reg_en <= '1';
|
||||
data_ram_re <= '1';
|
||||
tag_ram_re <= '1';
|
||||
end if;
|
||||
end if;
|
||||
when mem_request =>
|
||||
ram_index_count_rst <= '1';
|
||||
mem_index_count_rst <= '1';
|
||||
CYC_O <= '1';
|
||||
if SRDY_I = '1' then
|
||||
sn <= mem_access;
|
||||
end if;
|
||||
when mem_access =>
|
||||
mem_index_count_en <= '1';
|
||||
data_write <= '1';
|
||||
CYC_O <= '1';
|
||||
STB_O <= '1';
|
||||
if mem_index_count = 2**word_index_width-1 then
|
||||
if SRDY_I = '1' then
|
||||
sn <= mem_data;
|
||||
end if;
|
||||
end if;
|
||||
when mem_data =>
|
||||
CYC_O <= '1';
|
||||
data_write <= '1';
|
||||
if ram_index_count = 2**word_index_width-1 then
|
||||
if ACK_I = '1' then
|
||||
sn <= upd_cache;
|
||||
end if;
|
||||
end if;
|
||||
when upd_cache =>
|
||||
tag_ram_addr_wr <= cache_index_reg;
|
||||
tag_ram_we <= '1';
|
||||
cache_entry_in.valid <= '1';
|
||||
sn <= rd_cache;
|
||||
|
||||
when rd_cache =>
|
||||
tag_ram_re <= '1';
|
||||
data_ram_re <= '1';
|
||||
was_miss <= '1';
|
||||
sn <= ready;
|
||||
when others =>
|
||||
sn <= ready;
|
||||
end case;
|
||||
end process;
|
||||
|
||||
cache_index_counter:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if cache_index_count_en = '0' then
|
||||
cache_index_count <= 2**cache_index_width-1;
|
||||
elsif cache_index_count /= 0 then
|
||||
cache_index_count <= cache_index_count - 1;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
ram_index_counter:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if ram_index_count_rst = '1' then
|
||||
ram_index_count <= 0;
|
||||
elsif data_write = '1' and ACK_I = '1' then
|
||||
if ram_index_count /= 2**word_index_width-1 then
|
||||
ram_index_count <= ram_index_count + 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
mem_index_counter:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if mem_index_count_rst = '1' then
|
||||
mem_index_count <= 0;
|
||||
elsif mem_index_count_en = '1' and SRDY_I = '1' then
|
||||
if mem_index_count /= 2**word_index_width-1 then
|
||||
mem_index_count <= mem_index_count + 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end behavior;
|
||||
@@ -0,0 +1,184 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: The arithmetic logic unit
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
use work.mips_types.all;
|
||||
|
||||
entity alu is
|
||||
Generic
|
||||
(
|
||||
data_width : integer := 8
|
||||
);
|
||||
Port
|
||||
(
|
||||
op1_in : in unsigned (data_width-1 downto 0);
|
||||
op2_in : in unsigned (data_width-1 downto 0);
|
||||
op2_shifted : in unsigned (data_width-1 downto 0);
|
||||
ctrl : in alu_ctrl_t;
|
||||
result : out unsigned (data_width-1 downto 0);
|
||||
flags : out alu_flags_t
|
||||
);
|
||||
end alu;
|
||||
|
||||
architecture Behavioral of alu is
|
||||
|
||||
signal sum_res : unsigned (data_width-1 downto 0);
|
||||
signal and_res : unsigned (data_width-1 downto 0);
|
||||
signal xor_res : unsigned (data_width-1 downto 0);
|
||||
signal nor_res : unsigned (data_width-1 downto 0);
|
||||
signal or_res : unsigned (data_width-1 downto 0);
|
||||
signal eq, sa, sb, sr, c, z : STD_LOGIC;
|
||||
signal lts, ltu : STD_LOGIC;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
begin
|
||||
|
||||
eq <= '1' when op1_in = op2_in else '0' after 3 ns;
|
||||
sa <= op1_in(op1_in'left);
|
||||
sb <= op2_in(op2_in'left);
|
||||
sr <= sum_res(sum_res'left);
|
||||
z <= '1' when op1_in = (data_width-1 downto 0 => '0') else '0' after 2 ns;
|
||||
|
||||
flags.uvf <= (not ctrl.add) and ((sa and (not sb) and (not sr)) or ((not sa) and sb and sr));
|
||||
flags.ovf <= ctrl.add and ((sa and sb and (not sr)) or ((not sa) and (not sb) and sr));
|
||||
-- lts <= (not eq) and (((not c) and sa and sb) or (((not sr) and sa) or (sa and (not sb)) or (sr and (not sb))));
|
||||
lts <= not eq and ((not c and sa) or (not sb and sa) or (not sb and sr));
|
||||
|
||||
ltu <= (not eq) and (not c);
|
||||
flags.lts <= lts;
|
||||
flags.ltu <= ltu;
|
||||
flags.c <= c;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
proc_op_and:
|
||||
process(op1_in, op2_in)
|
||||
variable x1, x2 : unsigned (data_width-1 downto 0);
|
||||
begin
|
||||
x1 := op1_in;
|
||||
x2 := op2_in;
|
||||
|
||||
and_res <= (x1 and x2) after 1 ns;
|
||||
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
proc_proc_xor:
|
||||
process(op1_in, op2_in)
|
||||
variable x1, x2 : unsigned (data_width-1 downto 0);
|
||||
begin
|
||||
x1 := op1_in;
|
||||
x2 := op2_in;
|
||||
|
||||
xor_res <= (x1 xor x2) after 2 ns;
|
||||
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
proc_proc_nor:
|
||||
process(op1_in, op2_in)
|
||||
variable x1, x2 : unsigned (data_width-1 downto 0);
|
||||
begin
|
||||
x1 := op1_in;
|
||||
x2 := op2_in;
|
||||
|
||||
nor_res <= (x1 nor x2) after 1 ns;
|
||||
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
proc_proc_or:
|
||||
process(op1_in, op2_in)
|
||||
variable x1, x2 : unsigned (data_width-1 downto 0);
|
||||
begin
|
||||
x1 := op1_in;
|
||||
x2 := op2_in;
|
||||
|
||||
or_res <= (x1 or x2) after 1 ns;
|
||||
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
proc_alu_out:
|
||||
process(ctrl, sum_res, and_res, xor_res, nor_res, or_res, op2_shifted, lts, ltu)
|
||||
begin
|
||||
|
||||
result <= sum_res;
|
||||
|
||||
case ctrl.outsel is
|
||||
|
||||
when alu_adder =>
|
||||
result <= sum_res;
|
||||
|
||||
when alu_and =>
|
||||
result <= and_res;
|
||||
|
||||
when alu_xor =>
|
||||
result <= xor_res;
|
||||
|
||||
when alu_nor =>
|
||||
result <= nor_res;
|
||||
|
||||
when alu_or =>
|
||||
result <= or_res;
|
||||
|
||||
when alu_shift2 =>
|
||||
result <= op2_shifted;
|
||||
|
||||
when alu_ltu =>
|
||||
result <= (data_width-1 downto 1 => '0') & ltu;
|
||||
|
||||
when alu_lts =>
|
||||
result <= (data_width-1 downto 1 => '0') & lts;
|
||||
|
||||
when others => null;
|
||||
|
||||
end case;
|
||||
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
alu_addsub:
|
||||
process(op1_in, op2_in, ctrl)
|
||||
variable sum : unsigned(data_width+1 downto 0);
|
||||
variable op1, op2 : unsigned(data_width+1 downto 0);
|
||||
begin
|
||||
|
||||
op1 := '0' & op1_in & not ctrl.add;
|
||||
if (ctrl.add = '1') then
|
||||
op2 := '0' & op2_in & '0';
|
||||
else
|
||||
op2 := '0' & not op2_in & '1';
|
||||
end if;
|
||||
sum := op1 + op2;
|
||||
|
||||
-- Form sum + carry
|
||||
sum_res <= unsigned(sum(data_width downto 1)) after 4 ns;
|
||||
c <= sum(sum'left) after 4 ns;
|
||||
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
end Behavioral;
|
||||
@@ -0,0 +1,52 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: The arithmetic logic unit
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
use work.mips_types.all;
|
||||
|
||||
entity bcu is
|
||||
Generic
|
||||
(
|
||||
data_width : integer := 8
|
||||
);
|
||||
Port
|
||||
(
|
||||
op1_in : in unsigned (data_width-1 downto 0);
|
||||
op2_in : in unsigned (data_width-1 downto 0);
|
||||
flags : out bcu_flags_t
|
||||
);
|
||||
end bcu;
|
||||
|
||||
architecture Behavioral of bcu is
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
begin
|
||||
|
||||
flags.eq <= '1' when op1_in = op2_in else '0' after 3 ns;
|
||||
flags.ltz <= op1_in(op1_in'left) after 1 ns;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
end Behavioral;
|
||||
@@ -0,0 +1,496 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: JIPS top file
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
library work;
|
||||
use work.mips_types.all;
|
||||
|
||||
entity biu is
|
||||
Generic
|
||||
(
|
||||
icache_size : natural := 2048; -- words
|
||||
dcache_size : natural := 2048 -- words
|
||||
);
|
||||
Port
|
||||
(
|
||||
RST_I : in STD_LOGIC;
|
||||
CLK_I : in STD_LOGIC;
|
||||
ACK_I : in STD_LOGIC;
|
||||
SRDY_I : in STD_LOGIC;
|
||||
ADDR_O : out word_t;
|
||||
DAT_I : in word_t;
|
||||
DAT_O : out word_t;
|
||||
WE_O : out STD_LOGIC;
|
||||
SEL_O : out unsigned(3 downto 0);
|
||||
CYC_O : out STD_LOGIC;
|
||||
STB_O : out STD_LOGIC;
|
||||
MRDY_O : out STD_LOGIC;
|
||||
cpu_imem_err : out STD_LOGIC;
|
||||
cpu_imem_rdy : out STD_LOGIC;
|
||||
cpu_imem_en : in STD_LOGIC;
|
||||
cpu_imem_addr : in word_t;
|
||||
cpu_imem_din : out word_t;
|
||||
cpu_dmem_err : out STD_LOGIC;
|
||||
cpu_dmem_rdy : out STD_LOGIC;
|
||||
cpu_dmem_en : in STD_LOGIC;
|
||||
cpu_dmem_we : in STD_LOGIC;
|
||||
cpu_dmem_be : in unsigned(3 downto 0);
|
||||
cpu_dmem_dout : in word_t;
|
||||
cpu_dmem_din : out word_t;
|
||||
cpu_dmem_addr : in word_t
|
||||
);
|
||||
end biu;
|
||||
|
||||
architecture behavior of biu is
|
||||
|
||||
COMPONENT icache
|
||||
GENERIC
|
||||
(
|
||||
cache_size : natural; -- words
|
||||
line_size : natural -- words
|
||||
);
|
||||
PORT
|
||||
(
|
||||
RST_I : in STD_LOGIC;
|
||||
CLK_I : in STD_LOGIC;
|
||||
ACK_I : in STD_LOGIC;
|
||||
SRDY_I : in STD_LOGIC;
|
||||
ADDR_O : out word_t;
|
||||
DAT_I : in word_t;
|
||||
STB_O : out STD_LOGIC;
|
||||
CYC_O : out STD_LOGIC;
|
||||
en : in STD_LOGIC;
|
||||
cpu_en : in STD_LOGIC;
|
||||
cpu_addr : in word_t;
|
||||
cpu_dout : out word_t;
|
||||
cpu_busy : out STD_LOGIC
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
COMPONENT dcache
|
||||
GENERIC
|
||||
(
|
||||
cache_size : natural; -- words
|
||||
line_size : natural -- words
|
||||
);
|
||||
PORT
|
||||
(
|
||||
RST_I : in STD_LOGIC;
|
||||
CLK_I : in STD_LOGIC;
|
||||
ACK_I : in STD_LOGIC;
|
||||
SRDY_I : in STD_LOGIC;
|
||||
ADDR_O : out word_t;
|
||||
DAT_I : in word_t;
|
||||
STB_O : out STD_LOGIC;
|
||||
CYC_O : out STD_LOGIC;
|
||||
en : in STD_LOGIC;
|
||||
cpu_en : in STD_LOGIC;
|
||||
cpu_we : in STD_LOGIC;
|
||||
cpu_be : in unsigned(3 downto 0);
|
||||
cpu_addr : in word_t;
|
||||
cpu_din : in word_t;
|
||||
cpu_dout : out word_t;
|
||||
cpu_busy : out STD_LOGIC
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
type bus_state_t is (init, ready, icache_bus_access, dcache_bus_access, write_bus, read_bus, read_finish);
|
||||
|
||||
signal s, sn : bus_state_t;
|
||||
signal bus_idle : std_logic;
|
||||
signal busy : std_logic;
|
||||
signal dmem_be : unsigned(3 downto 0);
|
||||
signal dcache_dout : word_t;
|
||||
signal dcache_mem_gnt : std_logic;
|
||||
signal icache_mem_gnt : std_logic;
|
||||
signal dmem_mem_wr_gnt : std_logic;
|
||||
signal dmem_mem_rd_gnt : std_logic;
|
||||
signal dcache_busy : std_logic;
|
||||
signal icache_busy : std_logic;
|
||||
signal CYC_O_icache : std_logic;
|
||||
signal CYC_O_dcache : std_logic;
|
||||
signal CYC_O_dmem_rd : std_logic;
|
||||
signal CYC_O_dmem_wr : std_logic;
|
||||
signal SRDY_I_icache : std_logic;
|
||||
signal SRDY_I_dcache : std_logic;
|
||||
signal ADDR_O_icache : word_t;
|
||||
signal ADDR_O_dcache : word_t;
|
||||
signal ADDR_O_dmem_rd : word_t;
|
||||
signal ADDR_O_dmem_wr : word_t;
|
||||
signal STB_O_icache : std_logic;
|
||||
signal STB_O_dcache : std_logic;
|
||||
signal STB_O_dmem_rd : std_logic;
|
||||
signal STB_O_dmem_wr : std_logic;
|
||||
signal DAT_I_dmem_rd : word_t;
|
||||
signal DAT_O_dmem_wr : word_t;
|
||||
signal SEL_O_dmem_wr : unsigned(3 downto 0);
|
||||
signal dcached : std_logic;
|
||||
signal dcache_en : std_logic;
|
||||
signal uncached_access : std_logic;
|
||||
|
||||
type timeout_cnt_t is range 0 to 1E5-1;
|
||||
signal bus_timeout_cnt : timeout_cnt_t;
|
||||
signal bus_timeout : std_logic;
|
||||
|
||||
signal bout_fifo_din : unsigned(68 downto 0);
|
||||
signal bout_fifo_dout : unsigned(68 downto 0);
|
||||
signal bout_fifo_re : std_logic;
|
||||
signal bout_fifo_we : std_logic;
|
||||
signal bout_fifo_full : std_logic;
|
||||
signal bout_fifo_empty : std_logic;
|
||||
signal bout_rdy : std_logic;
|
||||
|
||||
alias bout_fifo_addr_in is bout_fifo_din(31 downto 0);
|
||||
alias bout_fifo_data_in is bout_fifo_din(63 downto 32);
|
||||
alias bout_fifo_sel_in is bout_fifo_din(67 downto 64);
|
||||
alias bout_fifo_we_in is bout_fifo_din(68);
|
||||
alias bout_fifo_addr_out is bout_fifo_dout(31 downto 0);
|
||||
alias bout_fifo_data_out is bout_fifo_dout(63 downto 32);
|
||||
alias bout_fifo_sel_out is bout_fifo_dout(67 downto 64);
|
||||
alias bout_fifo_we_out is bout_fifo_dout(68);
|
||||
|
||||
signal write_fifo_din : unsigned(67 downto 0);
|
||||
signal write_fifo_dout : unsigned(67 downto 0);
|
||||
signal write_fifo_re : std_logic;
|
||||
signal write_fifo_we : std_logic;
|
||||
signal write_fifo_full : std_logic;
|
||||
signal write_fifo_empty : std_logic;
|
||||
signal write_busy : std_logic;
|
||||
|
||||
alias write_fifo_addr_in is write_fifo_din(31 downto 0);
|
||||
alias write_fifo_data_in is write_fifo_din(63 downto 32);
|
||||
alias write_fifo_sel_in is write_fifo_din(67 downto 64);
|
||||
alias write_fifo_addr_out is write_fifo_dout(31 downto 0);
|
||||
alias write_fifo_data_out is write_fifo_dout(63 downto 32);
|
||||
alias write_fifo_sel_out is write_fifo_dout(67 downto 64);
|
||||
|
||||
signal read_cycle : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
|
||||
MRDY_O <= '1';
|
||||
|
||||
read_cyc_register:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if RST_I = '1' then
|
||||
read_cycle <= '0';
|
||||
else
|
||||
read_cycle <= (dmem_mem_rd_gnt and CYC_O_dmem_rd)
|
||||
or (dcache_mem_gnt and CYC_O_dcache)
|
||||
or (icache_mem_gnt and CYC_O_icache);
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
CYC_O <= not bout_fifo_empty or read_cycle;
|
||||
STB_O <= not bout_fifo_empty;
|
||||
ADDR_O <= bout_fifo_addr_out;
|
||||
DAT_O <= bout_fifo_data_out;
|
||||
SEL_O <= bout_fifo_sel_out;
|
||||
WE_O <= bout_fifo_we_out;
|
||||
|
||||
cpu_imem_rdy <= not icache_busy after 4.5 ns;
|
||||
busy <= CYC_O_dmem_rd or dcache_busy or (write_busy);
|
||||
cpu_dmem_rdy <= not busy after 4.5 ns;
|
||||
|
||||
inst_icache : icache
|
||||
GENERIC MAP
|
||||
(
|
||||
cache_size => icache_size, -- words
|
||||
line_size => 8
|
||||
)
|
||||
PORT MAP
|
||||
(
|
||||
CLK_I => CLK_I,
|
||||
RST_I => RST_I,
|
||||
STB_O => STB_O_icache,
|
||||
CYC_O => CYC_O_icache,
|
||||
ADDR_O => ADDR_O_icache,
|
||||
DAT_I => DAT_I,
|
||||
ACK_I => ACK_I,
|
||||
SRDY_I => SRDY_I_icache,
|
||||
en => '1',
|
||||
cpu_en => cpu_imem_en,
|
||||
cpu_addr => cpu_imem_addr,
|
||||
cpu_dout => cpu_imem_din,
|
||||
cpu_busy => icache_busy
|
||||
);
|
||||
|
||||
SRDY_I_icache <= bout_rdy and icache_mem_gnt;
|
||||
|
||||
inst_dcache : dcache
|
||||
GENERIC MAP
|
||||
(
|
||||
cache_size => dcache_size, -- words
|
||||
line_size => 8
|
||||
)
|
||||
PORT MAP
|
||||
(
|
||||
CLK_I => CLK_I,
|
||||
RST_I => RST_I,
|
||||
CYC_O => CYC_O_dcache,
|
||||
STB_O => STB_O_dcache,
|
||||
ADDR_O => ADDR_O_dcache,
|
||||
DAT_I => DAT_I,
|
||||
ACK_I => ACK_I,
|
||||
SRDY_I => SRDY_I_dcache,
|
||||
en => dcached,
|
||||
cpu_en => dcache_en,
|
||||
cpu_we => cpu_dmem_we,
|
||||
cpu_be => cpu_dmem_be,
|
||||
cpu_addr => cpu_dmem_addr,
|
||||
cpu_din => cpu_dmem_dout,
|
||||
cpu_dout => dcache_dout,
|
||||
cpu_busy => dcache_busy
|
||||
);
|
||||
|
||||
SRDY_I_dcache <= bout_rdy and dcache_mem_gnt;
|
||||
|
||||
dcached <= '1' when cpu_dmem_addr(31 downto 28) /= X"A" else '0';
|
||||
cpu_dmem_din <= dcache_dout when uncached_access = '0' else DAT_I_dmem_rd;
|
||||
dcache_en <= cpu_dmem_en and not busy;
|
||||
|
||||
-- Instantiate synchronous FIFO
|
||||
inst_bout_fifo: entity work.fifo_sync_dist
|
||||
GENERIC MAP
|
||||
(
|
||||
addr_width => 4,
|
||||
data_width => 69
|
||||
)
|
||||
PORT MAP
|
||||
(
|
||||
rst => RST_I,
|
||||
clk => CLK_I,
|
||||
we => bout_fifo_we,
|
||||
re => bout_fifo_re,
|
||||
fifo_full => bout_fifo_full,
|
||||
fifo_empty => bout_fifo_empty,
|
||||
fifo_afull => open,
|
||||
fifo_aempty => open,
|
||||
data_w => bout_fifo_din,
|
||||
data_r => bout_fifo_dout
|
||||
);
|
||||
bout_rdy <= not bout_fifo_full;
|
||||
bout_fifo_re <= not bout_fifo_empty and SRDY_I;
|
||||
|
||||
bout_fifo_we <= STB_O_dmem_wr or STB_O_dmem_rd or STB_O_dcache or STB_O_icache;
|
||||
|
||||
bout_fifo_data_in <= DAT_O_dmem_wr when dmem_mem_wr_gnt = '1' else (others => '-');
|
||||
|
||||
bout_fifo_addr_in <= ADDR_O_dmem_wr when dmem_mem_wr_gnt = '1' else
|
||||
ADDR_O_dmem_rd when dmem_mem_rd_gnt = '1' else
|
||||
ADDR_O_dcache when dcache_mem_gnt = '1' else
|
||||
ADDR_O_icache when icache_mem_gnt = '1' else (others => '-');
|
||||
|
||||
bout_fifo_sel_in <= SEL_O_dmem_wr when dmem_mem_wr_gnt = '1' else (others => '0');
|
||||
bout_fifo_we_in <= '1' when dmem_mem_wr_gnt = '1' else '0';
|
||||
|
||||
-- Instantiate synchronous FIFO
|
||||
inst_write_fifo: entity work.fifo_sync_dist
|
||||
GENERIC MAP
|
||||
(
|
||||
addr_width => 4,
|
||||
data_width => 68
|
||||
)
|
||||
PORT MAP
|
||||
(
|
||||
rst => RST_I,
|
||||
clk => CLK_I,
|
||||
we => write_fifo_we,
|
||||
re => write_fifo_re,
|
||||
fifo_full => write_busy,
|
||||
fifo_empty => write_fifo_empty,
|
||||
fifo_afull => open,
|
||||
fifo_aempty => open,
|
||||
data_w => write_fifo_din,
|
||||
data_r => write_fifo_dout
|
||||
);
|
||||
|
||||
CYC_O_dmem_wr <= not write_fifo_empty;
|
||||
DAT_O_dmem_wr <= write_fifo_data_out;
|
||||
ADDR_O_dmem_wr <= write_fifo_addr_out;
|
||||
SEL_O_dmem_wr <= write_fifo_sel_out;
|
||||
|
||||
write_fifo_data_in <= cpu_dmem_dout;
|
||||
write_fifo_addr_in <= cpu_dmem_addr;
|
||||
write_fifo_sel_in <= cpu_dmem_be;
|
||||
write_fifo_re <= STB_O_dmem_wr;
|
||||
write_fifo_we <= cpu_dmem_en and not busy and cpu_dmem_we;
|
||||
|
||||
dmem_rd_flags:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
uncached_access <= '0';
|
||||
if RST_I = '1' then
|
||||
CYC_O_dmem_rd <= '0';
|
||||
else
|
||||
if ACK_I = '1' and dmem_mem_rd_gnt = '1' then
|
||||
uncached_access <= '1';
|
||||
CYC_O_dmem_rd <= '0';
|
||||
end if;
|
||||
if cpu_dmem_en = '1' and busy = '0' and cpu_dmem_we = '0' then
|
||||
if dcached = '0' then
|
||||
CYC_O_dmem_rd <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
dmem_rd_data:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if RST_I = '1' then
|
||||
DAT_I_dmem_rd <= (others => '0');
|
||||
elsif ACK_I = '1' and CYC_O_dmem_rd = '1' then
|
||||
DAT_I_dmem_rd <= DAT_I;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
dmem_rd_regs:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if cpu_dmem_en = '1' and busy = '0' then
|
||||
ADDR_O_dmem_rd <= cpu_dmem_addr;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
bus_state_next:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if RST_I = '1' then
|
||||
s <= init;
|
||||
else
|
||||
s <= sn;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
bus_state:
|
||||
process(s, CYC_O_icache, CYC_O_dcache, CYC_O_dmem_wr, CYC_O_dmem_rd, bout_rdy, ACK_I)
|
||||
begin
|
||||
|
||||
icache_mem_gnt <= '0';
|
||||
dcache_mem_gnt <= '0';
|
||||
dmem_mem_rd_gnt <= '0';
|
||||
dmem_mem_wr_gnt <= '0';
|
||||
STB_O_dmem_rd <= '0';
|
||||
STB_O_dmem_wr <= '0';
|
||||
bus_idle <= '0';
|
||||
sn <= s;
|
||||
case s is
|
||||
when init =>
|
||||
sn <= ready;
|
||||
when ready =>
|
||||
bus_idle <= '1';
|
||||
if CYC_O_dmem_wr = '1' then
|
||||
sn <= write_bus;
|
||||
elsif CYC_O_dmem_rd = '1' then
|
||||
sn <= read_bus;
|
||||
elsif CYC_O_icache = '1' then
|
||||
sn <= icache_bus_access;
|
||||
elsif CYC_O_dcache = '1' then
|
||||
sn <= dcache_bus_access;
|
||||
end if;
|
||||
when icache_bus_access =>
|
||||
icache_mem_gnt <= '1';
|
||||
if CYC_O_icache = '0' then
|
||||
sn <= ready;
|
||||
end if;
|
||||
when dcache_bus_access =>
|
||||
dcache_mem_gnt <= '1';
|
||||
if CYC_O_dcache = '0' then
|
||||
sn <= ready;
|
||||
end if;
|
||||
when write_bus =>
|
||||
dmem_mem_wr_gnt <= '1';
|
||||
if CYC_O_dmem_wr = '1' then
|
||||
if bout_rdy = '1' then
|
||||
STB_O_dmem_wr <= '1';
|
||||
end if;
|
||||
else
|
||||
sn <= ready;
|
||||
end if;
|
||||
when read_bus =>
|
||||
dmem_mem_rd_gnt <= '1';
|
||||
if bout_rdy = '1' then
|
||||
STB_O_dmem_rd <= '1';
|
||||
sn <= read_finish;
|
||||
end if;
|
||||
when read_finish =>
|
||||
dmem_mem_rd_gnt <= '1';
|
||||
if ACK_I = '1' then
|
||||
sn <= ready;
|
||||
end if;
|
||||
when others =>
|
||||
sn <= ready;
|
||||
end case;
|
||||
|
||||
end process;
|
||||
|
||||
bus_timeout_counter:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if bus_idle = '0' then
|
||||
if bus_timeout_cnt /= 0 then
|
||||
bus_timeout_cnt <= bus_timeout_cnt - 1;
|
||||
else
|
||||
bus_timeout <= '1';
|
||||
end if;
|
||||
else
|
||||
bus_timeout_cnt <= timeout_cnt_t'high;
|
||||
bus_timeout <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
bus_err:
|
||||
process(CLK_I)
|
||||
begin
|
||||
if rising_edge(CLK_I) then
|
||||
if RST_I = '1' then
|
||||
cpu_imem_err <= '0';
|
||||
cpu_dmem_err <= '0';
|
||||
elsif bus_timeout = '1' then
|
||||
cpu_imem_err <= icache_mem_gnt;
|
||||
cpu_dmem_err <= dcache_mem_gnt or dmem_mem_wr_gnt or dmem_mem_rd_gnt;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
end behavior;
|
||||
@@ -0,0 +1,415 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: The arithmetic logic unit
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
use work.mips_types.all;
|
||||
use work.mips_instr.all;
|
||||
|
||||
entity cop is
|
||||
Port
|
||||
(
|
||||
rst : in STD_LOGIC;
|
||||
clk : in STD_LOGIC;
|
||||
sdu : in sdu_t;
|
||||
IR_valid : in STD_LOGIC;
|
||||
IR : in word_t;
|
||||
events : in event_t;
|
||||
ctrl_in : in cop_ctrl_in_t;
|
||||
ctrl_out : out cop_ctrl_out_t;
|
||||
din : in word_t;
|
||||
dout : out word_t
|
||||
);
|
||||
end cop;
|
||||
|
||||
architecture Behavioral of cop is
|
||||
|
||||
signal epc : word_t;
|
||||
signal cause : word_t;
|
||||
signal status : word_t;
|
||||
signal BadVAddr : word_t;
|
||||
signal exc_code : unsigned(4 downto 0);
|
||||
signal test_reg : word_t;
|
||||
signal test_reg_we : STD_LOGIC;
|
||||
signal stat_reg_we : STD_LOGIC;
|
||||
signal eflags_reg_we : STD_LOGIC;
|
||||
signal epc_reg_we : STD_LOGIC;
|
||||
signal code_reg_we : STD_LOGIC;
|
||||
signal ip_reg_we : STD_LOGIC;
|
||||
signal bd : STD_LOGIC;
|
||||
signal ip : unsigned(7 downto 0);
|
||||
signal im : unsigned(7 downto 0);
|
||||
signal status_save : STD_LOGIC;
|
||||
signal status_rest : STD_LOGIC;
|
||||
signal exception : STD_LOGIC;
|
||||
signal exception_end : STD_LOGIC;
|
||||
signal eflags : exc_flags_t;
|
||||
signal exc_enable : STD_LOGIC;
|
||||
signal cop_EX_en : STD_LOGIC;
|
||||
|
||||
type cop_pipe_t is record
|
||||
din : word_t;
|
||||
rs : reg_ptr_t;
|
||||
rd : reg_ptr_t;
|
||||
func : func_t;
|
||||
we : std_logic;
|
||||
re : std_logic;
|
||||
cs : std_logic;
|
||||
end record;
|
||||
|
||||
signal cop_pipe_ID : cop_pipe_t;
|
||||
signal cop_pipe_EX : cop_pipe_t;
|
||||
|
||||
function eval_int(ip : unsigned) return STD_LOGIC is
|
||||
variable result : STD_LOGIC;
|
||||
begin
|
||||
result := '0';
|
||||
for i in ip'range loop
|
||||
result := result or ip(i);
|
||||
end loop;
|
||||
|
||||
return result;
|
||||
end eval_int;
|
||||
|
||||
type exc_state_t is (exc_init, exc_idle, exc_commit_ID, exc_commit_EX, exc_commit_MEM);
|
||||
signal exc_state, exc_staten : exc_state_t;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
begin
|
||||
|
||||
cop_pipe_ID.din <= din;
|
||||
cop_pipe_ID.cs <= IR_valid;
|
||||
cop_pipe_ID.rs <= extract_rs(IR);
|
||||
cop_pipe_ID.rd <= extract_rd(IR);
|
||||
cop_pipe_ID.func <= extract_func(IR);
|
||||
cop_pipe_ID.re <= cop_pipe_ID.cs when cop_pipe_ID.rs = "00000" else '0';
|
||||
cop_pipe_ID.we <= cop_pipe_ID.cs when cop_pipe_ID.rs = "00100" else '0';
|
||||
cop_EX_en <= exc_enable and not status_save;
|
||||
|
||||
ctrl_out.ee <= exc_enable;
|
||||
ctrl_out.ec <= status_save;
|
||||
ctrl_out.RE <= status(25);
|
||||
ctrl_out.user_mode <= status(1);
|
||||
ctrl_out.int <= eflags.Int;
|
||||
|
||||
ctrl_out.cop_read <= cop_pipe_EX.cs and cop_pipe_EX.re after 1 ns;
|
||||
ctrl_out.reg_write <= cop_pipe_ID.re after 1 ns;
|
||||
|
||||
im <= status(15 downto 8);
|
||||
cause <= bd & (30 downto 16 => '0') & ip & '0' & exc_code & "00";
|
||||
|
||||
eflags.Ov <= events.alu_ovf or events.alu_uvf;
|
||||
eflags.DAdEL <= events.data_load_err;
|
||||
eflags.DAdES <= events.data_store_err;
|
||||
eflags.IAdEL <= events.inst_load_err;
|
||||
eflags.IAdEK <= events.inst_priv_addr and status(1);
|
||||
eflags.Sys <= events.syscall;
|
||||
eflags.Bp <= events.break;
|
||||
eflags.RI <= events.illegal;
|
||||
eflags.Int <= eval_int(ip) and status(0);
|
||||
|
||||
exception <= eflags.Ov or eflags.Sys or eflags.Bp or eflags.RI or eflags.IAdEL or eflags.IAdEK or eflags.DAdEL or eflags.DAdES or eflags.Int after 1 ns;
|
||||
|
||||
exception_state:
|
||||
process(exc_state, ctrl_in, exception, sdu)
|
||||
begin
|
||||
|
||||
exc_enable <= '0';
|
||||
ctrl_out.exc_commit <= '0';
|
||||
ctrl_out.exc_pending <= '0';
|
||||
epc_reg_we <= '0';
|
||||
code_reg_we <= '0';
|
||||
status_save <= '0';
|
||||
eflags_reg_we <= '0';
|
||||
|
||||
exc_staten <= exc_state;
|
||||
|
||||
case exc_state is
|
||||
|
||||
when exc_init =>
|
||||
exc_staten <= exc_idle;
|
||||
|
||||
when exc_idle =>
|
||||
exc_enable <= '1';
|
||||
if exception = '1' then
|
||||
status_save <= '1';
|
||||
eflags_reg_we <= '1';
|
||||
code_reg_we <= '1';
|
||||
exc_staten <= exc_commit_ID;
|
||||
end if;
|
||||
|
||||
when exc_commit_ID =>
|
||||
ctrl_out.exc_pending <= '1';
|
||||
ctrl_out.exc_commit <= '1';
|
||||
if sdu.ID_stall = '0' then
|
||||
exc_staten <= exc_commit_EX;
|
||||
end if;
|
||||
|
||||
when exc_commit_EX =>
|
||||
ctrl_out.exc_pending <= '1';
|
||||
ctrl_out.exc_commit <= '1';
|
||||
if sdu.EX_stall = '0' then
|
||||
exc_staten <= exc_commit_MEM;
|
||||
end if;
|
||||
|
||||
when exc_commit_MEM =>
|
||||
ctrl_out.exc_pending <= '1';
|
||||
if sdu.MEM_stall = '0' then
|
||||
epc_reg_we <= '1';
|
||||
exc_staten <= exc_idle;
|
||||
end if;
|
||||
|
||||
when others =>
|
||||
exc_staten <= exc_idle;
|
||||
|
||||
end case;
|
||||
end process;
|
||||
|
||||
exception_state_next:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
exc_state <= exc_init;
|
||||
else
|
||||
exc_state <= exc_staten;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cop_exception_epc_write:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
bd <= '0';
|
||||
epc <= (others => '0');
|
||||
elsif epc_reg_we = '1' then
|
||||
bd <= '0';
|
||||
epc <= ctrl_in.epc_mem;
|
||||
if ctrl_in.bd_wb = '1' then
|
||||
bd <= '1';
|
||||
epc <= ctrl_in.epc_wb;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cop_exception_map:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
exc_code <= (others => '0');
|
||||
BadVAddr <= (others => '0');
|
||||
elsif code_reg_we = '1' then
|
||||
if eflags.Ov = '1' then
|
||||
exc_code <= "01100";
|
||||
elsif eflags.Sys = '1' then
|
||||
exc_code <= "01000";
|
||||
elsif eflags.Bp = '1' then
|
||||
exc_code <= "01001";
|
||||
elsif eflags.RI = '1' then
|
||||
exc_code <= "01010";
|
||||
elsif eflags.IAdEL = '1' then
|
||||
exc_code <= "00100";
|
||||
BadVAddr <= ctrl_in.imem_addr;
|
||||
elsif eflags.IAdEK = '1' then
|
||||
exc_code <= "00100";
|
||||
BadVAddr <= ctrl_in.imem_addr;
|
||||
elsif eflags.DAdEL = '1' then
|
||||
exc_code <= "00100";
|
||||
BadVAddr <= ctrl_in.dmem_addr;
|
||||
elsif eflags.DAdES = '1' then
|
||||
exc_code <= "00101";
|
||||
BadVAddr <= ctrl_in.dmem_addr;
|
||||
elsif eflags.Int = '1' then
|
||||
exc_code <= "00000";
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
status_rest <= exception_end and ctrl_in.exc_left;
|
||||
|
||||
cop_status_restore:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
exception_end <= '0';
|
||||
ctrl_out.exc_exit <= '0';
|
||||
else
|
||||
if cop_pipe_ID.func = "10000" and exception_end = '0' then -- RFE
|
||||
exception_end <= cop_pipe_ID.cs;
|
||||
ctrl_out.exc_exit <= cop_pipe_ID.cs;
|
||||
elsif exception_end = '1' and ctrl_in.exc_left = '1' then
|
||||
exception_end <= '0';
|
||||
ctrl_out.exc_exit <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cop_ip_reg_write:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
ip(1 downto 0) <= (others => '0');
|
||||
elsif ip_reg_we = '1' then
|
||||
ip(1 downto 0) <= cop_pipe_EX.din(9 downto 8) and im(1 downto 0);
|
||||
end if;
|
||||
ip(7 downto 2) <= events.Int and im(7 downto 2);
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cop_exc_vector:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
ctrl_out.exc_vec <= X"80000180";
|
||||
if status(22) = '1' then
|
||||
ctrl_out.exc_vec <= X"BFC00180";
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cop_pipe:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
cop_pipe_EX.cs <= '0';
|
||||
cop_pipe_EX.we <= '0';
|
||||
cop_pipe_EX.re <= '0';
|
||||
else
|
||||
if sdu.EX_stall = '0' then
|
||||
cop_pipe_EX <= cop_pipe_ID;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cop_register_read:
|
||||
process(clk)
|
||||
variable reg : word_t;
|
||||
begin
|
||||
if rising_edge(clk) and cop_pipe_ID.re = '1' and sdu.ID_stall = '0' then
|
||||
case cop_pipe_ID.rd is
|
||||
when "01000" => -- BadVAddr
|
||||
reg := BadVAddr;
|
||||
|
||||
when "01100" => -- Status
|
||||
reg := status;
|
||||
|
||||
when "01101" => -- Cause
|
||||
reg := cause;
|
||||
|
||||
when "01110" => -- EPC (Exception Program Counter)
|
||||
reg := epc;
|
||||
|
||||
when "01111" => -- PRId (Processor Revision Register)
|
||||
reg := X"000002" & to_unsigned(REVISION ,8);
|
||||
|
||||
when "11111" => -- test_reg
|
||||
reg := test_reg;
|
||||
|
||||
when others =>
|
||||
reg := (others => '-');
|
||||
|
||||
end case;
|
||||
dout <= reg after 1 ns;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cop_we_gen:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
test_reg_we <= '0';
|
||||
stat_reg_we <= '0';
|
||||
ip_reg_we <= '0';
|
||||
else
|
||||
test_reg_we <= '0';
|
||||
stat_reg_we <= '0';
|
||||
ip_reg_we <= '0';
|
||||
if (cop_EX_en and cop_pipe_EX.we) = '1' then
|
||||
|
||||
case cop_pipe_EX.rd is
|
||||
|
||||
when "01100" =>
|
||||
stat_reg_we <= not status(1) or status(28);
|
||||
when "01101" =>
|
||||
ip_reg_we <= not status(1) or status(28);
|
||||
when "11111" =>
|
||||
test_reg_we <= not status(1) or status(28);
|
||||
when others => null;
|
||||
|
||||
end case;
|
||||
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cop_test_reg_write:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
test_reg <= (others => '0');
|
||||
else --if ce = '1' then
|
||||
if test_reg_we = '1' then
|
||||
test_reg <= cop_pipe_EX.din;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cop_status_reg_write:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
status <= X"00400000";
|
||||
else
|
||||
if status_save = '1' then
|
||||
status(5 downto 4) <= status(3 downto 2);
|
||||
status(3 downto 2) <= status(1 downto 0);
|
||||
status(1 downto 0) <= "00";
|
||||
elsif status_rest = '1' then
|
||||
status(1 downto 0) <= status(3 downto 2);
|
||||
status(3 downto 2) <= status(5 downto 4);
|
||||
elsif stat_reg_we = '1' then
|
||||
status <= cop_pipe_EX.din;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
end Behavioral;
|
||||
@@ -0,0 +1,101 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: The datapath controller
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
library work;
|
||||
use work.mips_types.all;
|
||||
use work.mips_instr.all;
|
||||
|
||||
entity idecode_rom is
|
||||
Port
|
||||
(
|
||||
nop : in std_logic;
|
||||
inst_in : in word_t;
|
||||
ctrl_out : out ctrl_lines_t
|
||||
);
|
||||
end idecode_rom;
|
||||
|
||||
architecture Behavioral of idecode_rom is
|
||||
|
||||
signal ctrl_special : ctrl_lines_t;
|
||||
signal ctrl_regimm : ctrl_lines_t;
|
||||
signal ctrl_opcode : ctrl_lines_t;
|
||||
|
||||
signal rom_special : rom_special_t := gen_rom_special;
|
||||
signal rom_regimm : rom_regimm_t := gen_rom_regimm;
|
||||
signal rom_opcode : rom_opcode_t := gen_rom_opcode;
|
||||
|
||||
attribute rom_style : string;
|
||||
|
||||
attribute rom_style of rom_special: signal is "distributed";
|
||||
attribute rom_style of rom_regimm: signal is "distributed";
|
||||
attribute rom_style of rom_opcode: signal is "distributed";
|
||||
|
||||
begin
|
||||
|
||||
i_dec_special:
|
||||
process(inst_in, rom_special)
|
||||
variable func : func_t;
|
||||
begin
|
||||
func := extract_func(inst_in);
|
||||
ctrl_special <= rom_special(to_integer(func));
|
||||
end process;
|
||||
|
||||
i_dec_regimm:
|
||||
process(inst_in, rom_regimm)
|
||||
variable rt : reg_ptr_t;
|
||||
begin
|
||||
rt := extract_rt(inst_in);
|
||||
ctrl_regimm <= rom_regimm(to_integer(rt));
|
||||
end process;
|
||||
|
||||
i_dec_opcode:
|
||||
process(inst_in, rom_opcode)
|
||||
variable opc : opcode_t;
|
||||
begin
|
||||
opc := extract_opc(inst_in);
|
||||
ctrl_opcode <= rom_opcode(to_integer(opc));
|
||||
end process;
|
||||
|
||||
proc_decode:
|
||||
process(inst_in, ctrl_special, ctrl_regimm, ctrl_opcode, nop)
|
||||
variable opclass : opcode_t;
|
||||
begin
|
||||
opclass := extract_opc(inst_in);
|
||||
ctrl_out <= ctrl_lines_default after 2 ns;
|
||||
if nop = '0' then
|
||||
case opclass is
|
||||
when "000000" =>
|
||||
ctrl_out <= ctrl_special after 2 ns;
|
||||
when "000001" =>
|
||||
ctrl_out <= ctrl_regimm after 2 ns;
|
||||
when others =>
|
||||
ctrl_out <= ctrl_opcode after 2 ns;
|
||||
end case;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end Behavioral;
|
||||
@@ -0,0 +1,997 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: Types, constants and functions for JCPU
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
library work;
|
||||
use work.mips_types.all;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
package mips_instr is
|
||||
|
||||
function extract_opc(instr : word_t) return opcode_t;
|
||||
function extract_rs(instr : word_t) return reg_ptr_t;
|
||||
function extract_rt(instr : word_t) return reg_ptr_t;
|
||||
function extract_rd(instr : word_t) return reg_ptr_t;
|
||||
function extract_shamt(instr : word_t) return shamt_t;
|
||||
function extract_func(instr : word_t) return func_t;
|
||||
function extract_simm32(instr : word_t) return word_t;
|
||||
function extract_uimm16(instr : word_t) return word_t;
|
||||
function extract_jimm32(instr, pc : word_t) return word_t;
|
||||
function extract_bimm18(instr, pc : word_t) return word_t;
|
||||
function decode_op(instr : word_t) return op_t;
|
||||
function ctrl_lines_default return ctrl_lines_t;
|
||||
function special_ctrl_lines(func : func_t) return ctrl_lines_t;
|
||||
function regimm_ctrl_lines(rt : reg_ptr_t) return ctrl_lines_t;
|
||||
function opcode_ctrl_lines(opc : opcode_t) return ctrl_lines_t;
|
||||
function gen_rom_opcode return rom_opcode_t;
|
||||
function gen_rom_regimm return rom_regimm_t;
|
||||
function gen_rom_special return rom_special_t;
|
||||
|
||||
end mips_instr;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
library work;
|
||||
use work.mips_types.all;
|
||||
|
||||
package body mips_instr is
|
||||
|
||||
function extract_opc(instr : word_t) return opcode_t is
|
||||
variable result : opcode_t;
|
||||
begin
|
||||
result := instr(31 downto 26);
|
||||
|
||||
return result;
|
||||
|
||||
end extract_opc;
|
||||
|
||||
function extract_rs(instr : word_t) return reg_ptr_t is
|
||||
variable result : reg_ptr_t;
|
||||
begin
|
||||
result := instr(25 downto 21);
|
||||
|
||||
return result;
|
||||
|
||||
end extract_rs;
|
||||
|
||||
function extract_rt(instr : word_t) return reg_ptr_t is
|
||||
variable result : reg_ptr_t;
|
||||
begin
|
||||
result := instr(20 downto 16);
|
||||
|
||||
return result;
|
||||
|
||||
end extract_rt;
|
||||
|
||||
function extract_rd(instr : word_t) return reg_ptr_t is
|
||||
variable result : reg_ptr_t;
|
||||
begin
|
||||
result := instr(15 downto 11);
|
||||
|
||||
return result;
|
||||
|
||||
end extract_rd;
|
||||
|
||||
function extract_shamt(instr : word_t) return shamt_t is
|
||||
variable result : shamt_t;
|
||||
begin
|
||||
result := instr(10 downto 6);
|
||||
|
||||
return result;
|
||||
|
||||
end extract_shamt;
|
||||
|
||||
function extract_func(instr : word_t) return func_t is
|
||||
variable result : func_t;
|
||||
begin
|
||||
result := instr(5 downto 0);
|
||||
|
||||
return result;
|
||||
|
||||
end extract_func;
|
||||
|
||||
function extract_simm32(instr : word_t) return word_t is
|
||||
variable result : word_t;
|
||||
begin
|
||||
result := (31 downto 16 => instr(15)) & instr(15 downto 0);
|
||||
|
||||
return result;
|
||||
|
||||
end extract_simm32;
|
||||
|
||||
function extract_uimm16(instr : word_t) return word_t is
|
||||
variable result : word_t;
|
||||
begin
|
||||
result := (31 downto 16 => '0') & instr(15 downto 0);
|
||||
|
||||
return result;
|
||||
|
||||
end extract_uimm16;
|
||||
|
||||
function extract_jimm32(instr, pc : word_t) return word_t is
|
||||
variable result : word_t;
|
||||
begin
|
||||
result := pc(31 downto 28) & instr(25 downto 0) & "00";
|
||||
|
||||
return result;
|
||||
|
||||
end extract_jimm32;
|
||||
|
||||
function extract_bimm18(instr, pc : word_t) return word_t is
|
||||
variable result : word_t;
|
||||
begin
|
||||
result := (31 downto 18 => instr(15)) & instr(15 downto 0) & "00";
|
||||
|
||||
return result;
|
||||
|
||||
end extract_bimm18;
|
||||
|
||||
function decode_op(instr : word_t) return op_t is
|
||||
variable result : op_t;
|
||||
variable opc : natural range 0 to 63;
|
||||
variable func : natural range 0 to 63;
|
||||
variable rt : natural range 0 to 31;
|
||||
|
||||
begin
|
||||
|
||||
opc := to_integer(extract_opc(instr));
|
||||
func := to_integer(extract_func(instr));
|
||||
rt := to_integer(extract_rt(instr));
|
||||
|
||||
result := op_sll;
|
||||
|
||||
case opc is
|
||||
|
||||
when 0 =>
|
||||
case func is
|
||||
|
||||
when 0 =>
|
||||
result := op_sll;
|
||||
|
||||
when 2 =>
|
||||
result := op_srl;
|
||||
|
||||
when 3 =>
|
||||
result := op_sra;
|
||||
|
||||
when 4 =>
|
||||
result := op_sllv;
|
||||
|
||||
when 6 =>
|
||||
result := op_srlv;
|
||||
|
||||
when 7 =>
|
||||
result := op_srav;
|
||||
|
||||
when 8 =>
|
||||
result := op_jr;
|
||||
|
||||
when 9 =>
|
||||
result := op_jalr;
|
||||
|
||||
when 12 =>
|
||||
result := op_syscall;
|
||||
|
||||
when 13 =>
|
||||
result := op_break;
|
||||
|
||||
when 16 =>
|
||||
result := op_mfhi;
|
||||
|
||||
when 17 =>
|
||||
result := op_mthi;
|
||||
|
||||
when 18 =>
|
||||
result := op_mflo;
|
||||
|
||||
when 19 =>
|
||||
result := op_mtlo;
|
||||
|
||||
when 24 =>
|
||||
result := op_mult;
|
||||
|
||||
when 25 =>
|
||||
result := op_multu;
|
||||
|
||||
when 26 =>
|
||||
result := op_div;
|
||||
|
||||
when 27 =>
|
||||
result := op_divu;
|
||||
|
||||
when 32 =>
|
||||
result := op_add;
|
||||
|
||||
when 33 =>
|
||||
result := op_addu;
|
||||
|
||||
when 34 =>
|
||||
result := op_sub;
|
||||
|
||||
when 35 =>
|
||||
result := op_subu;
|
||||
|
||||
when 36 =>
|
||||
result := op_and;
|
||||
|
||||
when 37 =>
|
||||
result := op_or;
|
||||
|
||||
when 38 =>
|
||||
result := op_xor;
|
||||
|
||||
when 39 =>
|
||||
result := op_nor;
|
||||
|
||||
when 42 =>
|
||||
result := op_slt;
|
||||
|
||||
when 43 =>
|
||||
result := op_sltu;
|
||||
|
||||
when others => null; -- undef
|
||||
|
||||
end case;
|
||||
|
||||
when 1 =>
|
||||
case rt is
|
||||
|
||||
when 0 =>
|
||||
result := op_bltz;
|
||||
|
||||
when 1 =>
|
||||
result := op_bgez;
|
||||
|
||||
when 16 =>
|
||||
result := op_bltzal;
|
||||
|
||||
when 17 =>
|
||||
result := op_bgezal;
|
||||
|
||||
when others => null; -- undef
|
||||
|
||||
end case;
|
||||
|
||||
when 2 =>
|
||||
result := op_j;
|
||||
|
||||
when 3 =>
|
||||
result := op_jal;
|
||||
|
||||
when 4 =>
|
||||
result := op_beq;
|
||||
|
||||
when 5 =>
|
||||
result := op_bne;
|
||||
|
||||
when 6 =>
|
||||
result := op_blez;
|
||||
|
||||
when 7 =>
|
||||
result := op_bgtz;
|
||||
|
||||
when 8 =>
|
||||
result := op_addi;
|
||||
|
||||
when 9 =>
|
||||
result := op_addiu;
|
||||
|
||||
when 10 =>
|
||||
result := op_slti;
|
||||
|
||||
when 11 =>
|
||||
result := op_sltiu;
|
||||
|
||||
when 12 =>
|
||||
result := op_andi;
|
||||
|
||||
when 13 =>
|
||||
result := op_ori;
|
||||
|
||||
when 14 =>
|
||||
result := op_xori;
|
||||
|
||||
when 15 =>
|
||||
result := op_lui;
|
||||
|
||||
when 16 =>
|
||||
result := op_cop0;
|
||||
|
||||
when 17 =>
|
||||
result := op_cop1;
|
||||
|
||||
when 18 =>
|
||||
result := op_cop2;
|
||||
|
||||
when 19 =>
|
||||
result := op_cop3;
|
||||
|
||||
when 32 =>
|
||||
result := op_lb;
|
||||
|
||||
when 33 =>
|
||||
result := op_lh;
|
||||
|
||||
when 34 =>
|
||||
result := op_lwl;
|
||||
|
||||
when 35 =>
|
||||
result := op_lw;
|
||||
|
||||
when 36 =>
|
||||
result := op_lbu;
|
||||
|
||||
when 37 =>
|
||||
result := op_lhu;
|
||||
|
||||
when 38 =>
|
||||
result := op_lwr;
|
||||
|
||||
when 40 =>
|
||||
result := op_sb;
|
||||
|
||||
when 41 =>
|
||||
result := op_sh;
|
||||
|
||||
when 42 =>
|
||||
result := op_swl;
|
||||
|
||||
when 43 =>
|
||||
result := op_sw;
|
||||
|
||||
when 46 =>
|
||||
result := op_swr;
|
||||
|
||||
when 49 =>
|
||||
result := op_lwc1;
|
||||
|
||||
when 50 =>
|
||||
result := op_lwc2;
|
||||
|
||||
when 51 =>
|
||||
result := op_lwc3;
|
||||
|
||||
when 57 =>
|
||||
result := op_swc1;
|
||||
|
||||
when 58 =>
|
||||
result := op_swc2;
|
||||
|
||||
when 59 =>
|
||||
result := op_swc3;
|
||||
|
||||
when others => null; -- undef
|
||||
|
||||
end case;
|
||||
|
||||
return result;
|
||||
|
||||
end decode_op;
|
||||
|
||||
function ctrl_lines_default return ctrl_lines_t is
|
||||
variable result : ctrl_lines_t;
|
||||
begin
|
||||
result.cop_instr_en := '0';
|
||||
result.jump := '0';
|
||||
result.jump_long := '0';
|
||||
result.branch := '0';
|
||||
result.bc_src := bc_eq_ne;
|
||||
result.bc_not := '0';
|
||||
result.alu.outsel := alu_adder;
|
||||
result.alu.add := '1';
|
||||
result.alu.shift_right := '0';
|
||||
result.alu.shift_arith := '0';
|
||||
result.shamt2_srcsel := sa_src_imm;
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.imm_src := src_imm16;
|
||||
result.reg_write := '0';
|
||||
result.dmem_we := '0';
|
||||
result.dmem_en := '0';
|
||||
result.wptr_srcsel := wptr_src_imm;
|
||||
result.reg_link := '0';
|
||||
result.shift_offset := "00";
|
||||
result.shift_byp := '1';
|
||||
result.byte_en_byp := '1';
|
||||
result.sign_ext_byp := '1';
|
||||
result.word4_en := '0';
|
||||
result.word2_en := '0';
|
||||
result.align_left := '0';
|
||||
result.load_signed := '0';
|
||||
result.mul_access := '0';
|
||||
result.mul_hilo_we := '0';
|
||||
result.mul_start := '0';
|
||||
result.mul_s_un := '0';
|
||||
result.mul_mul_divn := '0';
|
||||
result.mul_hilo_sel := '1';
|
||||
result.exc_break := '0';
|
||||
result.exc_syscall := '0';
|
||||
result.exc_illegal := '0';
|
||||
result.except_en := '0';
|
||||
result.alu_exc_en := '0';
|
||||
|
||||
return result;
|
||||
|
||||
end ctrl_lines_default;
|
||||
|
||||
|
||||
function special_ctrl_lines(func : func_t) return ctrl_lines_t is
|
||||
variable result : ctrl_lines_t;
|
||||
variable op : integer range 0 to 2**func_t'length-1;
|
||||
begin
|
||||
|
||||
result := ctrl_lines_default;
|
||||
|
||||
op := to_integer(func);
|
||||
case op is
|
||||
|
||||
-- when op_add =>
|
||||
when 32 =>
|
||||
result.alu.outsel := alu_adder;
|
||||
result.alu.add := '1';
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.reg_write := '1';
|
||||
result.alu_exc_en := '1';
|
||||
|
||||
-- when op_addu =>
|
||||
when 33 =>
|
||||
result.alu.outsel := alu_adder;
|
||||
result.alu.add := '1';
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_and =>
|
||||
when 36 =>
|
||||
result.alu.outsel := alu_and;
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_break =>
|
||||
when 13 =>
|
||||
result.exc_break := '1';
|
||||
result.except_en := '1';
|
||||
|
||||
-- when op_div =>
|
||||
when 26 =>
|
||||
result.mul_access := '1';
|
||||
result.mul_start := '1';
|
||||
result.mul_s_un := '1';
|
||||
result.mul_mul_divn := '0';
|
||||
|
||||
-- when op_divu =>
|
||||
when 27 =>
|
||||
result.mul_access := '1';
|
||||
result.mul_start := '1';
|
||||
result.mul_s_un := '0';
|
||||
result.mul_mul_divn := '0';
|
||||
|
||||
-- when op_jalr =>
|
||||
when 9 =>
|
||||
result.jump_long := '1';
|
||||
result.wptr_srcsel := wptr_src_imm;
|
||||
result.reg_write := '1';
|
||||
result.reg_link := '1';
|
||||
|
||||
-- when op_jr =>
|
||||
when 8 =>
|
||||
result.jump_long := '1';
|
||||
|
||||
-- when op_mfhi =>
|
||||
when 16 =>
|
||||
result.reg_write := '1';
|
||||
result.mul_access := '1';
|
||||
result.mul_hilo_sel := '1';
|
||||
|
||||
-- when op_mflo =>
|
||||
when 18 =>
|
||||
result.reg_write := '1';
|
||||
result.mul_access := '1';
|
||||
result.mul_hilo_sel := '0';
|
||||
|
||||
-- when op_mthi =>
|
||||
when 17 =>
|
||||
result.mul_hilo_we := '1';
|
||||
result.mul_hilo_sel := '1';
|
||||
|
||||
-- when op_mtlo =>
|
||||
when 19 =>
|
||||
result.mul_hilo_we := '1';
|
||||
result.mul_hilo_sel := '0';
|
||||
|
||||
-- when op_mult =>
|
||||
when 24 =>
|
||||
result.mul_access := '1';
|
||||
result.mul_start := '1';
|
||||
result.mul_s_un := '1';
|
||||
result.mul_mul_divn := '1';
|
||||
|
||||
-- when op_multu =>
|
||||
when 25 =>
|
||||
result.mul_access := '1';
|
||||
result.mul_start := '1';
|
||||
result.mul_s_un := '0';
|
||||
result.mul_mul_divn := '1';
|
||||
|
||||
-- when op_or =>
|
||||
when 37 =>
|
||||
result.alu.outsel := alu_or;
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_nor =>
|
||||
when 39 =>
|
||||
result.alu.outsel := alu_nor;
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_sll =>
|
||||
when 0 =>
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.alu.outsel := alu_shift2;
|
||||
result.alu.shift_right := '0';
|
||||
result.shamt2_srcsel := sa_src_imm;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_sllv =>
|
||||
when 4 =>
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.alu.outsel := alu_shift2;
|
||||
result.alu.shift_right := '0';
|
||||
result.shamt2_srcsel := sa_src_reg;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_slt =>
|
||||
when 42 =>
|
||||
result.alu.outsel := alu_lts;
|
||||
result.alu.add := '0';
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_sltu =>
|
||||
when 43 =>
|
||||
result.alu.outsel := alu_ltu;
|
||||
result.alu.add := '0';
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_sra =>
|
||||
when 3 =>
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.alu.outsel := alu_shift2;
|
||||
result.alu.shift_right := '1';
|
||||
result.alu.shift_arith := '1';
|
||||
result.shamt2_srcsel := sa_src_imm;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_srav =>
|
||||
when 7 =>
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.alu.outsel := alu_shift2;
|
||||
result.alu.shift_right := '1';
|
||||
result.alu.shift_arith := '1';
|
||||
result.shamt2_srcsel := sa_src_reg;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_srl =>
|
||||
when 2 =>
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.alu.outsel := alu_shift2;
|
||||
result.alu.shift_right := '1';
|
||||
result.alu.shift_arith := '0';
|
||||
result.shamt2_srcsel := sa_src_imm;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_srlv =>
|
||||
when 6 =>
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.alu.outsel := alu_shift2;
|
||||
result.alu.shift_right := '1';
|
||||
result.alu.shift_arith := '0';
|
||||
result.shamt2_srcsel := sa_src_reg;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_sub =>
|
||||
when 34 =>
|
||||
result.alu.outsel := alu_adder;
|
||||
result.alu.add := '0';
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.reg_write := '1';
|
||||
result.alu_exc_en := '1';
|
||||
|
||||
-- when op_subu =>
|
||||
when 35 =>
|
||||
result.alu.outsel := alu_adder;
|
||||
result.alu.add := '0';
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_syscall =>
|
||||
when 12 =>
|
||||
result.exc_syscall := '1';
|
||||
result.except_en := '1';
|
||||
|
||||
-- when op_xor =>
|
||||
when 38 =>
|
||||
result.alu.outsel := alu_xor;
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_reg;
|
||||
result.reg_write := '1';
|
||||
|
||||
when others =>
|
||||
result.exc_illegal := '1';
|
||||
|
||||
end case;
|
||||
|
||||
return result;
|
||||
|
||||
end special_ctrl_lines;
|
||||
|
||||
function gen_rom_special return rom_special_t is
|
||||
variable result : rom_special_t;
|
||||
variable func : func_t;
|
||||
begin
|
||||
|
||||
for i in 0 to 2**func_t'length-1 loop
|
||||
func := to_unsigned(i, func_t'length);
|
||||
result(i) := special_ctrl_lines(func);
|
||||
end loop;
|
||||
|
||||
return result;
|
||||
end gen_rom_special;
|
||||
|
||||
function regimm_ctrl_lines(rt : reg_ptr_t) return ctrl_lines_t is
|
||||
variable result : ctrl_lines_t;
|
||||
variable op : integer range 0 to 2**reg_ptr_t'length-1;
|
||||
begin
|
||||
|
||||
result := ctrl_lines_default;
|
||||
|
||||
op := to_integer(rt);
|
||||
case op is
|
||||
|
||||
-- when op_bgez =>
|
||||
when 1 =>
|
||||
result.branch := '1';
|
||||
result.bc_src := bc_ltz_gez;
|
||||
result.bc_not := '1';
|
||||
|
||||
-- when op_bgezal =>
|
||||
when 17 =>
|
||||
result.branch := '1';
|
||||
result.bc_src := bc_ltz_gez;
|
||||
result.bc_not := '1';
|
||||
result.wptr_srcsel := wptr_src_const;
|
||||
result.reg_write := '1';
|
||||
result.reg_link := '1';
|
||||
|
||||
-- when op_bltz =>
|
||||
when 0 =>
|
||||
result.branch := '1';
|
||||
result.bc_src := bc_ltz_gez;
|
||||
result.bc_not := '0';
|
||||
|
||||
-- when op_bltzal =>
|
||||
when 16 =>
|
||||
result.branch := '1';
|
||||
result.bc_src := bc_ltz_gez;
|
||||
result.bc_not := '0';
|
||||
result.wptr_srcsel := wptr_src_const;
|
||||
result.reg_write := '1';
|
||||
result.reg_link := '1';
|
||||
|
||||
when others =>
|
||||
result.exc_illegal := '1';
|
||||
|
||||
end case;
|
||||
|
||||
return result;
|
||||
|
||||
end regimm_ctrl_lines;
|
||||
|
||||
function gen_rom_regimm return rom_regimm_t is
|
||||
variable result : rom_regimm_t;
|
||||
variable rt : reg_ptr_t;
|
||||
begin
|
||||
|
||||
for i in 0 to 2**reg_ptr_t'length-1 loop
|
||||
rt := to_unsigned(i, reg_ptr_t'length);
|
||||
result(i) := regimm_ctrl_lines(rt);
|
||||
end loop;
|
||||
|
||||
return result;
|
||||
end gen_rom_regimm;
|
||||
|
||||
function opcode_ctrl_lines(opc : opcode_t) return ctrl_lines_t is
|
||||
variable result : ctrl_lines_t;
|
||||
variable op : integer range 0 to 2**opcode_t'length-1;
|
||||
begin
|
||||
|
||||
result := ctrl_lines_default;
|
||||
|
||||
op := to_integer(opc);
|
||||
case op is
|
||||
|
||||
-- when op_addi =>
|
||||
when 8 =>
|
||||
result.imm_src := src_imm32;
|
||||
result.alu.outsel := alu_adder;
|
||||
result.alu.add := '1';
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_imm;
|
||||
result.reg_write := '1';
|
||||
result.alu_exc_en := '1';
|
||||
|
||||
-- when op_addiu =>
|
||||
when 9 =>
|
||||
result.imm_src := src_imm32;
|
||||
result.alu.outsel := alu_adder;
|
||||
result.alu.add := '1';
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_imm;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_andi =>
|
||||
when 12 =>
|
||||
result.imm_src := src_imm16;
|
||||
result.alu.outsel := alu_and;
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_imm;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_beq =>
|
||||
when 4 =>
|
||||
result.branch := '1';
|
||||
result.bc_src := bc_eq_ne;
|
||||
result.bc_not := '0';
|
||||
|
||||
-- when op_bgtz =>
|
||||
when 7 =>
|
||||
result.branch := '1';
|
||||
result.bc_src := bc_lez_gtz;
|
||||
result.bc_not := '1';
|
||||
|
||||
-- when op_blez =>
|
||||
when 6 =>
|
||||
result.branch := '1';
|
||||
result.bc_src := bc_lez_gtz;
|
||||
result.bc_not := '0';
|
||||
|
||||
-- when op_bne =>
|
||||
when 5 =>
|
||||
result.branch := '1';
|
||||
result.bc_src := bc_eq_ne;
|
||||
result.bc_not := '1';
|
||||
|
||||
-- when op_cop =>
|
||||
when 16 | 17 | 18 | 19 =>
|
||||
result.cop_instr_en := '1';
|
||||
|
||||
-- when op_j =>
|
||||
when 2 =>
|
||||
result.jump := '1';
|
||||
|
||||
-- when op_jal =>
|
||||
when 3 =>
|
||||
result.jump := '1';
|
||||
result.wptr_srcsel := wptr_src_const;
|
||||
result.reg_write := '1';
|
||||
result.reg_link := '1';
|
||||
|
||||
-- when op_lb =>
|
||||
when 32 =>
|
||||
result.imm_src := src_imm32;
|
||||
result.dmem_en := '1';
|
||||
result.reg_write := '1';
|
||||
result.shift_byp := '0';
|
||||
result.byte_en_byp := '1';
|
||||
result.sign_ext_byp := '0';
|
||||
result.load_signed := '1';
|
||||
result.word4_en := '1';
|
||||
|
||||
-- when op_lbu =>
|
||||
when 36 =>
|
||||
result.imm_src := src_imm32;
|
||||
result.dmem_en := '1';
|
||||
result.reg_write := '1';
|
||||
result.shift_byp := '0';
|
||||
result.byte_en_byp := '1';
|
||||
result.sign_ext_byp := '0';
|
||||
result.load_signed := '0';
|
||||
result.word4_en := '1';
|
||||
|
||||
-- when op_lh =>
|
||||
when 33 =>
|
||||
result.imm_src := src_imm32;
|
||||
result.dmem_en := '1';
|
||||
result.reg_write := '1';
|
||||
result.shift_byp := '0';
|
||||
result.sign_ext_byp := '0';
|
||||
result.byte_en_byp := '1';
|
||||
result.load_signed := '1';
|
||||
result.word2_en := '1';
|
||||
result.except_en := '1';
|
||||
|
||||
-- when op_lhu =>
|
||||
when 37 =>
|
||||
result.imm_src := src_imm32;
|
||||
result.dmem_en := '1';
|
||||
result.reg_write := '1';
|
||||
result.shift_byp := '0';
|
||||
result.sign_ext_byp := '0';
|
||||
result.byte_en_byp := '1';
|
||||
result.load_signed := '0';
|
||||
result.word2_en := '1';
|
||||
result.except_en := '1';
|
||||
|
||||
-- when op_lui =>
|
||||
when 15 =>
|
||||
result.imm_src := src_imm16_high;
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_imm;
|
||||
result.alu.outsel := alu_adder;
|
||||
result.reg_write := '1';
|
||||
result.alu.add := '1';
|
||||
|
||||
-- when op_lw =>
|
||||
when 35 =>
|
||||
-- result.imm_src := src_imm32;
|
||||
result.dmem_en := '1';
|
||||
result.reg_write := '1';
|
||||
result.except_en := '1';
|
||||
|
||||
-- when op_lwl =>
|
||||
when 34 =>
|
||||
-- result.imm_src := src_imm32;
|
||||
result.dmem_en := '1';
|
||||
result.reg_write := '1';
|
||||
result.shift_byp := '0';
|
||||
result.byte_en_byp := '0';
|
||||
result.shift_offset := "01";
|
||||
result.align_left := '1';
|
||||
|
||||
-- when op_lwr =>
|
||||
when 38 =>
|
||||
-- result.imm_src := src_imm32;
|
||||
result.dmem_en := '1';
|
||||
result.reg_write := '1';
|
||||
result.shift_byp := '0';
|
||||
result.byte_en_byp := '0';
|
||||
result.shift_offset := "00";
|
||||
result.align_left := '0';
|
||||
|
||||
-- when op_ori =>
|
||||
when 13 =>
|
||||
result.imm_src := src_imm16;
|
||||
result.alu.outsel := alu_or;
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_imm;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_sb =>
|
||||
when 40 =>
|
||||
result.dmem_en := '1';
|
||||
result.dmem_we := '1';
|
||||
-- result.imm_src := src_imm32;
|
||||
result.shift_byp := '0';
|
||||
result.byte_en_byp := '0';
|
||||
result.word4_en := '1';
|
||||
|
||||
-- when op_sh =>
|
||||
when 41 =>
|
||||
result.dmem_en := '1';
|
||||
result.dmem_we := '1';
|
||||
-- result.imm_src := src_imm32;
|
||||
result.shift_byp := '0';
|
||||
result.byte_en_byp := '0';
|
||||
result.word2_en := '1';
|
||||
result.except_en := '1';
|
||||
|
||||
-- when op_slti =>
|
||||
when 10 =>
|
||||
result.alu.outsel := alu_lts;
|
||||
result.alu.add := '0';
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_imm;
|
||||
result.imm_src := src_imm32;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_sltiu =>
|
||||
when 11 =>
|
||||
result.alu.outsel := alu_ltu;
|
||||
result.alu.add := '0';
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_imm;
|
||||
result.imm_src := src_imm32;
|
||||
result.reg_write := '1';
|
||||
|
||||
-- when op_sw =>
|
||||
when 43 =>
|
||||
result.dmem_en := '1';
|
||||
result.dmem_we := '1';
|
||||
-- result.imm_src := src_imm32;
|
||||
result.except_en := '1';
|
||||
|
||||
-- when op_swl =>
|
||||
when 42 =>
|
||||
result.dmem_en := '1';
|
||||
result.dmem_we := '1';
|
||||
-- result.imm_src := src_imm32;
|
||||
result.shift_byp := '0';
|
||||
result.byte_en_byp := '0';
|
||||
result.shift_offset := "01";
|
||||
|
||||
-- when op_swr =>
|
||||
when 46 =>
|
||||
result.dmem_en := '1';
|
||||
result.dmem_we := '1';
|
||||
-- result.imm_src := src_imm32;
|
||||
result.shift_byp := '0';
|
||||
result.byte_en_byp := '0';
|
||||
result.align_left := '1';
|
||||
|
||||
-- when op_xori =>
|
||||
when 14 =>
|
||||
result.imm_src := src_imm16;
|
||||
result.alu.outsel := alu_xor;
|
||||
result.alu.op1_src := alu_src_reg;
|
||||
result.alu.op2_src := alu_src_imm;
|
||||
result.reg_write := '1';
|
||||
|
||||
when others =>
|
||||
result.exc_illegal := '1';
|
||||
|
||||
end case;
|
||||
|
||||
return result;
|
||||
|
||||
end opcode_ctrl_lines;
|
||||
|
||||
function gen_rom_opcode return rom_opcode_t is
|
||||
variable result : rom_opcode_t;
|
||||
variable opc : opcode_t;
|
||||
begin
|
||||
|
||||
for i in 0 to 2**opcode_t'length-1 loop
|
||||
opc := to_unsigned(i, opcode_t'length);
|
||||
result(i) := opcode_ctrl_lines(opc);
|
||||
end loop;
|
||||
|
||||
return result;
|
||||
end gen_rom_opcode;
|
||||
|
||||
end mips_instr;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,454 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: The arithmetic logic unit
|
||||
--
|
||||
-- Copyright (C) 2007 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
use work.mips_types.all;
|
||||
|
||||
entity muldiv is
|
||||
Port
|
||||
(
|
||||
rst : in std_logic;
|
||||
clk : in std_logic;
|
||||
hilo_we : in std_logic;
|
||||
din_hi : in word_t;
|
||||
din_lo : in word_t;
|
||||
mul_divn : in std_logic;
|
||||
start : in std_logic;
|
||||
s_un : in std_logic;
|
||||
hilo_sel : in std_logic;
|
||||
busy : out std_logic;
|
||||
dout : out word_t
|
||||
);
|
||||
end muldiv;
|
||||
|
||||
architecture Behavioral of muldiv is
|
||||
|
||||
subtype pprod_t is unsigned (39 downto 0);
|
||||
subtype prod_t is unsigned (63 downto 0);
|
||||
subtype byte_t is unsigned (7 downto 0);
|
||||
|
||||
type pprod_array_t is array (natural range <>) of pprod_t;
|
||||
type word_array_t is array (natural range <>) of word_t;
|
||||
type byte_array_t is array (natural range <>) of byte_t;
|
||||
|
||||
signal pprod : pprod_array_t(0 to 3);
|
||||
signal sign1 : std_logic;
|
||||
signal sign2 : std_logic;
|
||||
signal s1_r : std_logic;
|
||||
signal s2_r : std_logic;
|
||||
signal sr_r : std_logic;
|
||||
signal cy : unsigned (3 downto 0);
|
||||
signal mul_start : std_logic;
|
||||
signal mul_en : std_logic;
|
||||
signal sum_en : std_logic;
|
||||
signal pre_sum_vld : std_logic;
|
||||
signal pp_reg : unsigned (63 downto 8);
|
||||
signal pre_const : word_array_t(0 to 1);
|
||||
signal result : prod_t;
|
||||
signal add_op1 : unsigned (39 downto 0);
|
||||
signal add_op2 : unsigned (39 downto 0);
|
||||
signal add_res : unsigned (39 downto 0);
|
||||
signal ppadd_op1 : word_array_t(0 to 3);
|
||||
signal ppadd_op2 : word_array_t(0 to 3);
|
||||
signal ppadd_res : word_array_t(0 to 3);
|
||||
signal ppadd_cyi : unsigned (3 downto 0);
|
||||
signal ppadd_cyo : unsigned (3 downto 0);
|
||||
|
||||
signal pp_op1_r : word_t;
|
||||
signal pp_op1 : word_t;
|
||||
signal pp_op2 : word_t;
|
||||
signal pp_op2_r : byte_array_t(0 to 3);
|
||||
signal bsy : std_logic;
|
||||
|
||||
signal div_add_res : unsigned (32 downto 0);
|
||||
signal div_add_op1 : unsigned (32 downto 0);
|
||||
signal div_add_op2 : unsigned (32 downto 0);
|
||||
signal div_add_cyi : std_logic;
|
||||
signal div_qbit : std_logic;
|
||||
signal div_start : std_logic;
|
||||
signal div_en : std_logic;
|
||||
|
||||
signal div_A : unsigned (32 downto 0);
|
||||
signal div_M : unsigned (32 downto 0);
|
||||
signal div_M_n : unsigned (32 downto 0);
|
||||
signal div_Q : word_t;
|
||||
|
||||
type md_state_t is (md_rdy, mul_pre1, mul_pre2, mul_pp, mul_sum, div_process, div_post1, div_post2, div_post3);
|
||||
signal s, sn : md_state_t;
|
||||
signal cycle_cnt : natural range 0 to 31;
|
||||
signal cycle_cnt_preset : natural range 0 to 31;
|
||||
signal cycle_cnt_load : std_logic;
|
||||
signal div_fin_en : unsigned (2 downto 0);
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
begin
|
||||
-- 9A0CD0570B88D78
|
||||
|
||||
busy <= bsy;
|
||||
|
||||
sign1 <= din_hi(din_hi'left) and s_un;
|
||||
sign2 <= din_lo(din_lo'left) and s_un;
|
||||
pp_op1 <= not din_hi when sign1 = '1' else din_hi;
|
||||
pp_op2 <= not din_lo when sign2 = '1' else din_lo;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
md_state:
|
||||
process(s, start, mul_divn, cycle_cnt)
|
||||
begin
|
||||
|
||||
bsy <= '1';
|
||||
cycle_cnt_load <= '0';
|
||||
cycle_cnt_preset <= 7;
|
||||
|
||||
mul_en <= '0';
|
||||
div_en <= '0';
|
||||
sum_en <= '0';
|
||||
pre_sum_vld <= '0';
|
||||
mul_start <= '0';
|
||||
div_start <= '0';
|
||||
div_fin_en <= "000";
|
||||
sn <= s;
|
||||
case s is
|
||||
when md_rdy =>
|
||||
bsy <= '0';
|
||||
if start = '1' then
|
||||
if mul_divn = '1' then
|
||||
sn <= mul_pre1;
|
||||
cycle_cnt_load <= '1';
|
||||
cycle_cnt_preset <= 7;
|
||||
mul_start <= '1';
|
||||
else
|
||||
sn <= div_process;
|
||||
cycle_cnt_load <= '1';
|
||||
cycle_cnt_preset <= 31;
|
||||
div_start <= '1';
|
||||
end if;
|
||||
end if;
|
||||
when mul_pre1 =>
|
||||
pre_sum_vld <= '1';
|
||||
mul_en <= '1';
|
||||
sn <= mul_pre2;
|
||||
when mul_pre2 =>
|
||||
pre_sum_vld <= '1';
|
||||
mul_en <= '1';
|
||||
sn <= mul_pp;
|
||||
when mul_pp =>
|
||||
mul_en <= '1';
|
||||
if cycle_cnt = 0 then
|
||||
cycle_cnt_load <= '1';
|
||||
cycle_cnt_preset <= 3;
|
||||
sn <= mul_sum;
|
||||
end if;
|
||||
when mul_sum =>
|
||||
sum_en <= '1';
|
||||
if cycle_cnt = 0 then
|
||||
bsy <= '0';
|
||||
sn <= md_rdy;
|
||||
end if;
|
||||
when div_process =>
|
||||
div_en <= '1';
|
||||
if cycle_cnt = 0 then
|
||||
sn <= div_post1;
|
||||
end if;
|
||||
when div_post1 =>
|
||||
div_fin_en <= "001";
|
||||
sn <= div_post2;
|
||||
when div_post2 =>
|
||||
div_fin_en <= "010";
|
||||
sn <= div_post3;
|
||||
when div_post3 =>
|
||||
div_fin_en <= "100";
|
||||
sn <= md_rdy;
|
||||
bsy <= '0';
|
||||
when others =>
|
||||
sn <= md_rdy;
|
||||
end case;
|
||||
|
||||
end process;
|
||||
|
||||
md_state_next:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
s <= md_rdy;
|
||||
else
|
||||
s <= sn;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
md_cycle_cnt:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
cycle_cnt <= 0;
|
||||
elsif cycle_cnt_load = '1' then
|
||||
cycle_cnt <= cycle_cnt_preset;
|
||||
elsif cycle_cnt /= 0 then
|
||||
cycle_cnt <= cycle_cnt - 1;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
proc_out_reg:
|
||||
process(hilo_sel, result)
|
||||
begin
|
||||
if hilo_sel = '1' then
|
||||
dout <= result(63 downto 32);
|
||||
else
|
||||
dout <= result(31 downto 0);
|
||||
end if;
|
||||
end process;
|
||||
|
||||
proc_in_reg:
|
||||
process(clk)
|
||||
variable pre_cond : unsigned(1 downto 0);
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if mul_start = '1' or div_start = '1' then
|
||||
pp_op1_r <= pp_op1;
|
||||
pre_const(0) <= (others => '0');
|
||||
pre_const(1) <= (others => '0');
|
||||
pre_cond := (din_hi(din_hi'left) and s_un) & (din_lo(din_lo'left) and s_un);
|
||||
s1_r <= pre_cond(1);
|
||||
s2_r <= pre_cond(0);
|
||||
sr_r <= pre_cond(0) xor pre_cond(1);
|
||||
case pre_cond is
|
||||
when "01" =>
|
||||
pre_const(0) <= din_hi;
|
||||
pre_const(1) <= X"FFFF_FFFF";
|
||||
when "10" =>
|
||||
pre_const(0) <= X"0000_0000";
|
||||
pre_const(1) <= X"FFFF_FFFF";
|
||||
when "11" =>
|
||||
pre_const(0) <= not din_hi;
|
||||
pre_const(1) <= X"0000_0001";
|
||||
when others => null;
|
||||
end case;
|
||||
elsif pre_sum_vld = '1' then
|
||||
pre_const(0) <= pre_const(1);
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
proc_mul_sr:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if mul_start = '1' then
|
||||
for i in 0 to 3 loop
|
||||
cy(i) <= '0';
|
||||
pprod(i) <= ppadd_res(i) & X"00";
|
||||
end loop;
|
||||
elsif mul_en = '1' then
|
||||
for i in 0 to 3 loop
|
||||
cy(i) <= ppadd_cyo(i);
|
||||
pprod(i) <= ppadd_res(i) & pprod(i)(8 downto 1);
|
||||
end loop;
|
||||
elsif sum_en = '1' then
|
||||
for i in 1 to 3 loop
|
||||
pprod(i-1) <= pprod(i);
|
||||
end loop;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
gen_mul32x8pp:
|
||||
for i in 0 to 3 generate
|
||||
begin
|
||||
|
||||
pp_adder_mux:
|
||||
process(mul_start, pp_op1, pp_op2, pp_op1_r, pp_op2_r(i), s1_r, sign1, pprod(i), cy(i))
|
||||
variable v2 : unsigned(7 downto 0);
|
||||
begin
|
||||
ppadd_cyi(i) <= '0';
|
||||
ppadd_op1(i) <= (others => '0');
|
||||
if mul_start = '1' then
|
||||
ppadd_op2(i) <= (others => '0');
|
||||
v2 := pp_op2(8*(i+1)-1 downto 8*i);
|
||||
if v2(0) = '1' then
|
||||
ppadd_cyi(i) <= sign1;
|
||||
ppadd_op1(i) <= pp_op1;
|
||||
end if;
|
||||
else
|
||||
ppadd_op2(i) <= cy(i) & pprod(i)(39 downto 9);
|
||||
v2 := pp_op2_r(i);
|
||||
if v2(0) = '1' then
|
||||
ppadd_cyi(i) <= s1_r;
|
||||
ppadd_op1(i) <= pp_op1_r;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
pp_adder:
|
||||
process(ppadd_op1(i), ppadd_op2(i), ppadd_cyi(i))
|
||||
variable sum_pp : unsigned(33 downto 0);
|
||||
begin
|
||||
sum_pp := ('0' & ppadd_op1(i) & ppadd_cyi(i)) + ('0' & ppadd_op2(i) & ppadd_cyi(i));
|
||||
ppadd_res(i) <= sum_pp(sum_pp'left-1 downto 1);
|
||||
ppadd_cyo(i) <= sum_pp(sum_pp'left);
|
||||
end process;
|
||||
|
||||
proc_mul_ctrl:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if mul_start = '1' then
|
||||
pp_op2_r(i) <= '0' & pp_op2(8*(i+1)-1 downto 8*i+1);
|
||||
elsif mul_en = '1' then
|
||||
pp_op2_r(i) <= '0' & pp_op2_r(i)(7 downto 1);
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end generate;
|
||||
|
||||
comb_mul_adder:
|
||||
process(add_op1, add_op2)
|
||||
variable sum_mul : unsigned(39 downto 0);
|
||||
begin
|
||||
sum_mul := (add_op1) + (add_op2);
|
||||
add_res <= sum_mul(sum_mul'left downto 0);
|
||||
end process;
|
||||
|
||||
comb_mul_adder_mux:
|
||||
process(pre_const, pre_sum_vld, pp_reg, pprod, sr_r)
|
||||
variable s_ext : std_logic;
|
||||
begin
|
||||
if pre_sum_vld = '1' then
|
||||
add_op1 <= pp_reg(63 downto 24);
|
||||
add_op2 <= pre_const(0) & X"00";
|
||||
else
|
||||
s_ext := pp_reg(63) and sr_r;
|
||||
add_op1 <= (7 downto 0 => s_ext) & pp_reg(63 downto 32);
|
||||
add_op2 <= pprod(0);
|
||||
end if;
|
||||
end process;
|
||||
|
||||
comb_mul:
|
||||
process(clk)
|
||||
variable tmp : prod_t;
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if mul_start = '1' then
|
||||
pp_reg <= (others => '0');
|
||||
elsif pre_sum_vld = '1' then
|
||||
pp_reg <= add_res & X"0000";
|
||||
elsif sum_en = '1' then
|
||||
tmp := add_res & pp_reg(31 downto 8);
|
||||
pp_reg <= tmp(63 downto 8);
|
||||
result <= tmp;
|
||||
if sr_r = '1' then
|
||||
result <= not tmp;
|
||||
end if;
|
||||
elsif div_fin_en(1) = '1' then
|
||||
result(63 downto 32) <= div_A(31 downto 0);
|
||||
if s1_r = '1' then
|
||||
result(63 downto 32) <= div_add_res(31 downto 0);
|
||||
end if;
|
||||
elsif div_fin_en(2) = '1' then
|
||||
result(31 downto 0) <= div_Q;
|
||||
if sr_r = '1' then
|
||||
result(31 downto 0) <= div_add_res(31 downto 0);
|
||||
end if;
|
||||
elsif hilo_we = '1' then
|
||||
if hilo_sel = '1' then
|
||||
result(63 downto 32) <= din_hi;
|
||||
else
|
||||
result(31 downto 0) <= din_hi;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
div_adder:
|
||||
process(div_add_op1, div_add_op2, div_add_cyi)
|
||||
variable sum_div : unsigned(33 downto 0);
|
||||
begin
|
||||
sum_div := (div_add_op1 & div_add_cyi) + (div_add_op2 & div_add_cyi);
|
||||
div_add_res <= sum_div(sum_div'left downto 1);
|
||||
end process;
|
||||
|
||||
div_adder_mux:
|
||||
process(div_start, div_en, div_fin_en, div_A, div_Q, pp_op1, sign1, s1_r, s2_r, sr_r, div_qbit, div_M, div_M_n)
|
||||
begin
|
||||
|
||||
div_add_cyi <= s2_r xor div_qbit;
|
||||
div_add_op1 <= div_A(31 downto 0) & div_Q(31);
|
||||
div_add_op2 <= (others => '0');
|
||||
if div_start = '1' then
|
||||
div_add_op1 <= '0' & pp_op1;
|
||||
div_add_cyi <= sign1;
|
||||
elsif div_en = '1' then
|
||||
div_add_op2 <= div_M;
|
||||
if div_qbit = '1' then
|
||||
div_add_op2 <= div_M_n;
|
||||
end if;
|
||||
elsif div_fin_en(0) = '1' then
|
||||
div_add_op2 <= div_M;
|
||||
div_add_cyi <= s2_r;
|
||||
div_add_op1 <= '0' & div_A(31 downto 0);
|
||||
elsif div_fin_en(1) = '1' then
|
||||
div_add_cyi <= s1_r;
|
||||
div_add_op1 <= '0' & not div_A(31 downto 0);
|
||||
elsif div_fin_en(2) = '1' then
|
||||
div_add_cyi <= sr_r;
|
||||
div_add_op1 <= '0' & not div_Q;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
divide:
|
||||
process(clk)
|
||||
variable quo : std_logic;
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if div_start = '1' then
|
||||
div_qbit <= '1';
|
||||
div_Q <= div_add_res(31 downto 0);
|
||||
div_A <= (others => '0');
|
||||
if sign2 = '1' then
|
||||
div_M_n <= '1' & din_lo;
|
||||
div_M <= '0' & not din_lo;
|
||||
else
|
||||
div_M_n <= '1' & not din_lo;
|
||||
div_M <= '0' & din_lo;
|
||||
end if;
|
||||
elsif div_en = '1' then
|
||||
div_qbit <= not div_add_res(32);
|
||||
div_A <= div_add_res(32 downto 0);
|
||||
div_Q <= div_Q(30 downto 0) & not div_add_res(32);
|
||||
elsif div_fin_en(0) = '1' then
|
||||
if div_A(32) = '1' then
|
||||
div_A <= '0' & div_add_res(31 downto 0);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
end Behavioral;
|
||||
@@ -0,0 +1,889 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: The pipeline
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
library work;
|
||||
use work.mips_types.all;
|
||||
use work.mips_instr.all;
|
||||
|
||||
entity pipeline is
|
||||
Port
|
||||
(
|
||||
rst : in STD_LOGIC;
|
||||
clk : in STD_LOGIC;
|
||||
halt : in STD_LOGIC;
|
||||
int : in unsigned(5 downto 0);
|
||||
imem_err : in STD_LOGIC;
|
||||
imem_rdy : in STD_LOGIC;
|
||||
imem_en : out STD_LOGIC;
|
||||
imem_addr : out word_t;
|
||||
imem_data : in word_t;
|
||||
dmem_err : in STD_LOGIC;
|
||||
dmem_rdy : in STD_LOGIC;
|
||||
dmem_en : out STD_LOGIC;
|
||||
dmem_we : out STD_LOGIC;
|
||||
dmem_be : out unsigned(3 downto 0);
|
||||
dmem_addr : out word_t;
|
||||
dmem_din : in word_t;
|
||||
dmem_dout : out word_t
|
||||
);
|
||||
end pipeline;
|
||||
|
||||
architecture Behavioral of pipeline is
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
COMPONENT reg_dual is
|
||||
Generic
|
||||
(
|
||||
addr_width : integer := 3;
|
||||
data_width : integer := 8
|
||||
);
|
||||
Port
|
||||
(
|
||||
clk_w : in STD_LOGIC;
|
||||
en : in STD_LOGIC;
|
||||
we : in STD_LOGIC;
|
||||
wptr : in unsigned (addr_width-1 downto 0);
|
||||
din : in unsigned (data_width-1 downto 0);
|
||||
rptr_a : in unsigned (addr_width-1 downto 0);
|
||||
rptr_b : in unsigned (addr_width-1 downto 0);
|
||||
dout_a : out unsigned (data_width-1 downto 0);
|
||||
dout_b : out unsigned (data_width-1 downto 0)
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
COMPONENT idecode_rom is
|
||||
Port
|
||||
(
|
||||
nop : in std_logic;
|
||||
inst_in : in word_t;
|
||||
ctrl_out : out ctrl_lines_t
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
COMPONENT shifter is
|
||||
Generic
|
||||
(
|
||||
data_width : integer
|
||||
);
|
||||
Port
|
||||
(
|
||||
shift_ctrl : in shift_ctrl_t;
|
||||
din : in unsigned (data_width-1 downto 0);
|
||||
dout : out unsigned (data_width-1 downto 0)
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
COMPONENT alu is
|
||||
Generic
|
||||
(
|
||||
data_width : integer
|
||||
);
|
||||
Port
|
||||
(
|
||||
op1_in : in unsigned (data_width-1 downto 0);
|
||||
op2_in : in unsigned (data_width-1 downto 0);
|
||||
op2_shifted : in unsigned (data_width-1 downto 0);
|
||||
ctrl : in alu_ctrl_t;
|
||||
result : out unsigned (data_width-1 downto 0);
|
||||
flags : out alu_flags_t
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
COMPONENT bcu is
|
||||
Generic
|
||||
(
|
||||
data_width : integer
|
||||
);
|
||||
Port
|
||||
(
|
||||
op1_in : in unsigned (data_width-1 downto 0);
|
||||
op2_in : in unsigned (data_width-1 downto 0);
|
||||
flags : out bcu_flags_t
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
COMPONENT cop is
|
||||
Port
|
||||
(
|
||||
rst : in STD_LOGIC;
|
||||
clk : in STD_LOGIC;
|
||||
sdu : in sdu_t;
|
||||
IR_valid : in STD_LOGIC;
|
||||
IR : in word_t;
|
||||
events : in event_t;
|
||||
ctrl_in : in cop_ctrl_in_t;
|
||||
ctrl_out : out cop_ctrl_out_t;
|
||||
din : in word_t;
|
||||
dout : out word_t
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
COMPONENT muldiv is
|
||||
Port
|
||||
(
|
||||
rst : in std_logic;
|
||||
clk : in std_logic;
|
||||
hilo_we : in std_logic;
|
||||
din_hi : in word_t;
|
||||
din_lo : in word_t;
|
||||
mul_divn : in std_logic;
|
||||
start : in std_logic;
|
||||
s_un : in std_logic;
|
||||
hilo_sel : in std_logic;
|
||||
busy : out std_logic;
|
||||
dout : out word_t
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
constant RESET_VECTOR : word_t := X"BFC00000";
|
||||
|
||||
signal ID_stage : ID_t;
|
||||
signal EX_stage : EX_t;
|
||||
signal MEM_stage : MEM_t;
|
||||
signal WB_stage : WB_t;
|
||||
signal clk_2, clk_1 : STD_LOGIC;
|
||||
signal hdu : hdu_t;
|
||||
signal sdu : sdu_t;
|
||||
signal cpu_rst : STD_LOGIC;
|
||||
signal reg_a : word_t;
|
||||
signal reg_b : word_t;
|
||||
signal ctrl_lines : ctrl_lines_t;
|
||||
signal cpu_run : STD_LOGIC;
|
||||
signal branch_ce : STD_LOGIC;
|
||||
signal run_en : STD_LOGIC;
|
||||
signal mul_dep : STD_LOGIC;
|
||||
signal imem_dep : STD_LOGIC;
|
||||
signal dmem_dep : STD_LOGIC;
|
||||
signal cop_ctrl : cop_ctrl_in_t;
|
||||
signal cop_stat : cop_ctrl_out_t;
|
||||
signal cop_din : word_t;
|
||||
signal cop_dout : word_t;
|
||||
signal alu_result : word_t;
|
||||
signal mul_result : word_t;
|
||||
signal mul_busy : STD_LOGIC;
|
||||
signal EX_events_instr : event_t;
|
||||
signal EX_events_alu : event_t;
|
||||
signal EX_events_mem : event_t;
|
||||
signal EX_events : event_t;
|
||||
signal MEM_events : event_t;
|
||||
signal bcu_op_a : word_t;
|
||||
signal bcu_op_b : word_t;
|
||||
signal bcu_flags : bcu_flags_t;
|
||||
signal vaddr : word_t;
|
||||
|
||||
attribute ram_style : string;
|
||||
|
||||
attribute ram_style of reg_a: signal is "distributed";
|
||||
attribute ram_style of reg_b: signal is "distributed";
|
||||
|
||||
signal pc : pc_t;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
begin
|
||||
|
||||
clk_1 <= clk;
|
||||
clk_2 <= not clk;
|
||||
cpu_run <= run_en;
|
||||
|
||||
-- Stall Detection Unit ---------------------------------------------------
|
||||
sdu.ID_nop <= imem_dep or cop_stat.exc_pending or EX_stage.exc or MEM_stage.exc;
|
||||
sdu.EX_nop <= mul_dep or ID_stage.nop or ID_stage.exc;
|
||||
sdu.MEM_nop <= EX_stage.nop or EX_stage.exc;
|
||||
sdu.WB_nop <= dmem_dep or MEM_stage.nop;
|
||||
|
||||
sdu.ID_stall <= dmem_dep or imem_dep or mul_dep or ID_stage.exc;
|
||||
sdu.EX_stall <= dmem_dep;
|
||||
sdu.MEM_stall <= dmem_dep;
|
||||
sdu.WB_stall <= '0';
|
||||
|
||||
mul_dep <= ID_stage.ctrl.mul_access and (EX_stage.ctrl.mul_start or mul_busy);
|
||||
imem_dep <= not imem_rdy;
|
||||
dmem_dep <= not dmem_rdy and MEM_stage.ctrl.dmem_en;
|
||||
---------------------------------------------------------------------------
|
||||
imem_en <= cpu_run and not (mul_dep or dmem_dep or cop_stat.exc_commit);
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- Muldiv
|
||||
--------------------------------------------------------------------------
|
||||
inst_muldiv: muldiv
|
||||
PORT MAP
|
||||
(
|
||||
rst => cpu_rst,
|
||||
clk => clk,
|
||||
hilo_we => EX_stage.ctrl.mul_hilo_we,
|
||||
din_hi => EX_stage.reg_a,
|
||||
din_lo => EX_stage.reg_b,
|
||||
mul_divn => EX_stage.ctrl.mul_mul_divn,
|
||||
start => EX_stage.ctrl.mul_start,
|
||||
s_un => EX_stage.ctrl.mul_s_un,
|
||||
hilo_sel => EX_stage.ctrl.mul_hilo_sel,
|
||||
busy => mul_busy,
|
||||
dout => mul_result
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- Coprocessor
|
||||
--------------------------------------------------------------------------
|
||||
inst_cop: cop
|
||||
PORT MAP
|
||||
(
|
||||
rst => cpu_rst,
|
||||
clk => clk,
|
||||
sdu => sdu,
|
||||
events => MEM_stage.events,
|
||||
IR_valid => ID_stage.ctrl.cop_instr_en,
|
||||
IR => ID_stage.IR,
|
||||
ctrl_in => cop_ctrl,
|
||||
ctrl_out => cop_stat,
|
||||
dout => cop_dout,
|
||||
din => cop_din
|
||||
);
|
||||
|
||||
cop_ctrl.bd_wb <= WB_stage.bd;
|
||||
cop_ctrl.epc_mem <= MEM_stage.pcn;
|
||||
cop_ctrl.epc_wb <= MEM_stage.epc;
|
||||
cop_ctrl.imem_addr <= pc.nxt;
|
||||
cop_ctrl.dmem_addr <= MEM_stage.va;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- IF stage
|
||||
--------------------------------------------------------------------------
|
||||
imem_addr <= pc.curr;
|
||||
|
||||
proc_stage_pc:
|
||||
process(pc, rst, cop_stat)
|
||||
begin
|
||||
if rst = '1' then
|
||||
pc.curr <= RESET_VECTOR after 2 ns;
|
||||
else
|
||||
if pc.is_branch and cop_stat.exc_pending = '0' then
|
||||
pc.curr <= pc.pc_branch after 2 ns;
|
||||
else
|
||||
pc.curr <= pc.nxt after 2 ns;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
proc_stage_pc_branch:
|
||||
process(clk_1)
|
||||
begin
|
||||
if rising_edge(clk_1) then
|
||||
if sdu.ID_stall = '0' then
|
||||
pc.pc_branch <= pc.curr + ID_stage.bimm18;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
proc_stage_pc_next:
|
||||
process(clk_1)
|
||||
begin
|
||||
if rising_edge(clk_1) then
|
||||
branch_ce <= '0';
|
||||
cop_ctrl.exc_left <= '0';
|
||||
if rst = '1' then
|
||||
pc.nxt <= pc.curr;
|
||||
pc.last <= pc.curr;
|
||||
else
|
||||
if cop_stat.exc_commit = '1' then
|
||||
pc.nxt <= cop_stat.exc_vec;
|
||||
elsif sdu.ID_stall = '0' then
|
||||
cop_ctrl.exc_left <= cop_stat.exc_exit;
|
||||
branch_ce <= '1';
|
||||
pc.last <= pc.curr;
|
||||
if ID_stage.ctrl.jump = '1' then
|
||||
pc.nxt <= ID_stage.jimm32;
|
||||
elsif ID_stage.ctrl.jump_long = '1' then
|
||||
pc.nxt <= ID_stage.reg_a;
|
||||
else
|
||||
pc.nxt <= pc.curr + 4;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
proc_stage_branch:
|
||||
process(clk_2)
|
||||
begin
|
||||
if rising_edge(clk_2) and branch_ce = '1' then
|
||||
pc.is_branch <= false;
|
||||
if EX_stage.ctrl.branch = '1' then
|
||||
|
||||
case EX_stage.ctrl.bc_src is
|
||||
|
||||
when bc_eq_ne =>
|
||||
if (EX_stage.ctrl.bc_not xor bcu_flags.eq) = '1' then
|
||||
pc.is_branch <= true;
|
||||
end if;
|
||||
|
||||
when bc_lez_gtz =>
|
||||
if (EX_stage.ctrl.bc_not xor (bcu_flags.eq or bcu_flags.ltz)) = '1' then
|
||||
pc.is_branch <= true;
|
||||
end if;
|
||||
|
||||
when bc_ltz_gez =>
|
||||
if (EX_stage.ctrl.bc_not xor bcu_flags.ltz) = '1' then
|
||||
pc.is_branch <= true;
|
||||
end if;
|
||||
|
||||
when others => null;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
process(rst, clk_1)
|
||||
variable reset_delay : unsigned (5 downto 0);
|
||||
begin
|
||||
if rising_edge(clk_1) then
|
||||
if rst = '1' then
|
||||
reset_delay := (others => '1');
|
||||
cpu_rst <= '1';
|
||||
run_en <= '0';
|
||||
elsif reset_delay /= (5 downto 0 => '0') then
|
||||
reset_delay := reset_delay - 1;
|
||||
else
|
||||
cpu_rst <= '0';
|
||||
end if;
|
||||
if reset_delay(reset_delay'left-1) = '0' then
|
||||
run_en <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- ID stage
|
||||
--------------------------------------------------------------------------
|
||||
ID_stage.IR <= to_01(imem_data);
|
||||
ID_stage.pcn <= pc.curr;
|
||||
ID_stage.op <= decode_op(ID_stage.IR);
|
||||
ID_stage.jimm32 <= extract_jimm32(ID_stage.IR, ID_stage.pcn);
|
||||
ID_stage.bimm18 <= extract_bimm18(ID_stage.IR, ID_stage.pcn);
|
||||
ID_stage.shamt <= extract_shamt(ID_stage.IR);
|
||||
ID_stage.reg_a_rptr <= extract_rs(ID_stage.IR);
|
||||
ID_stage.reg_b_rptr <= extract_rt(ID_stage.IR);
|
||||
ID_stage.ctrl <= ctrl_lines;
|
||||
ID_stage.reg_write <= ID_stage.ctrl.reg_write or cop_stat.reg_write;
|
||||
ID_stage.epc <= pc.last;
|
||||
ID_stage.exc <= event_is_active(ID_stage.events); -- Todo: works
|
||||
ID_stage.nop <= sdu.ID_nop;
|
||||
|
||||
proc_ID_except:
|
||||
process(ID_stage, cop_stat, pc)
|
||||
begin
|
||||
ID_stage.events <= events_clr;
|
||||
ID_stage.events.inst_load_err <= pc.nxt(1) or pc.nxt(0);
|
||||
ID_stage.events.inst_priv_addr <= pc.nxt(word_t'left) and cop_stat.user_mode;
|
||||
end process;
|
||||
|
||||
proc_stage_hdu:
|
||||
process(ID_stage, EX_stage, MEM_stage, WB_stage)
|
||||
variable read_a, read_b : boolean;
|
||||
variable raw_a_EX, raw_a_MEM, raw_a_WB : boolean;
|
||||
variable raw_b_EX, raw_b_MEM, raw_b_WB : boolean;
|
||||
variable reg_ptr_a : reg_ptr_t;
|
||||
variable reg_ptr_b : reg_ptr_t;
|
||||
begin
|
||||
|
||||
reg_ptr_a := ID_stage.reg_a_rptr;
|
||||
reg_ptr_b := ID_stage.reg_b_rptr;
|
||||
raw_a_EX := reg_ptr_a = EX_stage.reg_wptr and EX_stage.wreg_we = '1';
|
||||
raw_a_MEM := reg_ptr_a = MEM_stage.reg_wptr and MEM_stage.wreg_we = '1';
|
||||
raw_a_WB := reg_ptr_a = WB_stage.reg_wptr and WB_stage.wreg_we = '1';
|
||||
raw_b_EX := reg_ptr_b = EX_stage.reg_wptr and EX_stage.wreg_we = '1';
|
||||
raw_b_MEM := reg_ptr_b = MEM_stage.reg_wptr and MEM_stage.wreg_we = '1';
|
||||
raw_b_WB := reg_ptr_b = WB_stage.reg_wptr and WB_stage.wreg_we = '1';
|
||||
|
||||
hdu.alu_fwd_a_ex <= raw_a_EX after 1 ns;
|
||||
hdu.alu_fwd_a_mem <= raw_a_MEM after 1 ns;
|
||||
hdu.alu_fwd_a_wb <= raw_a_WB after 1 ns;
|
||||
hdu.alu_fwd_b_ex <= raw_b_EX after 1 ns;
|
||||
hdu.alu_fwd_b_mem <= raw_b_MEM after 1 ns;
|
||||
hdu.alu_fwd_b_wb <= raw_b_WB after 1 ns;
|
||||
|
||||
end process;
|
||||
|
||||
proc_stage_fwd_a:
|
||||
process(reg_a, hdu, EX_stage, MEM_stage, WB_stage)
|
||||
variable data : word_t;
|
||||
begin
|
||||
data := reg_a;
|
||||
if hdu.alu_fwd_a_ex then
|
||||
data := EX_stage.result;
|
||||
elsif hdu.alu_fwd_a_mem then
|
||||
data := MEM_stage.data;
|
||||
elsif hdu.alu_fwd_a_wb then
|
||||
data := WB_stage.data;
|
||||
end if;
|
||||
ID_stage.reg_a <= to_01(data) after 2 ns;
|
||||
end process;
|
||||
|
||||
proc_stage_fwd_b:
|
||||
process(reg_b, hdu, EX_stage, MEM_stage, WB_stage)
|
||||
variable data : word_t;
|
||||
begin
|
||||
data := reg_b;
|
||||
if hdu.alu_fwd_b_ex then
|
||||
data := EX_stage.result;
|
||||
elsif hdu.alu_fwd_b_mem then
|
||||
data := MEM_stage.data;
|
||||
elsif hdu.alu_fwd_b_wb then
|
||||
data := WB_stage.data;
|
||||
end if;
|
||||
ID_stage.reg_b <= to_01(data) after 2 ns;
|
||||
end process;
|
||||
|
||||
proc_imm_mux:
|
||||
process(ID_stage)
|
||||
variable data : word_t;
|
||||
begin
|
||||
data := extract_uimm16(ID_stage.IR);
|
||||
|
||||
case ID_stage.ctrl.imm_src is
|
||||
|
||||
when src_imm32 =>
|
||||
data := extract_simm32(ID_stage.IR);
|
||||
|
||||
when src_imm16 =>
|
||||
data := extract_uimm16(ID_stage.IR);
|
||||
|
||||
when src_imm16_high =>
|
||||
data := ID_stage.IR(word_t'length/2-1 downto 0) & (word_t'length/2-1 downto 0 => '0');
|
||||
|
||||
when others => null;
|
||||
|
||||
end case;
|
||||
|
||||
ID_stage.imm <= data after 2 ns;
|
||||
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
inst_idecode_rom: idecode_rom
|
||||
PORT MAP
|
||||
(
|
||||
nop => sdu.ID_nop,
|
||||
inst_in => ID_stage.IR,
|
||||
ctrl_out => ctrl_lines
|
||||
);
|
||||
|
||||
inst_reg_dual: reg_dual
|
||||
GENERIC MAP
|
||||
(
|
||||
addr_width => reg_ptr_t'length,
|
||||
data_width => word_t'length
|
||||
)
|
||||
PORT MAP
|
||||
(
|
||||
clk_w => clk_1,
|
||||
we => WB_stage.wreg_we,
|
||||
en => '1',
|
||||
wptr => WB_stage.reg_wptr,
|
||||
din => WB_stage.data,
|
||||
rptr_a => ID_stage.reg_a_rptr,
|
||||
rptr_b => ID_stage.reg_b_rptr,
|
||||
dout_a => reg_a,
|
||||
dout_b => reg_b
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- EX stage
|
||||
--------------------------------------------------------------------------
|
||||
EX_stage.reg_a_rptr <= extract_rs(EX_stage.IR);
|
||||
EX_stage.reg_b_rptr <= extract_rt(EX_stage.IR);
|
||||
EX_stage.result <= alu_result when EX_stage.ctrl.mul_access = '0' else mul_result;
|
||||
|
||||
proc_stage_ID_EX_1:
|
||||
process(clk_1)
|
||||
begin
|
||||
if rising_edge(clk_1) then
|
||||
if rst = '1' then
|
||||
EX_stage.op <= NOP;
|
||||
EX_stage.IR <= (others => '0');
|
||||
EX_stage.ctrl <= ctrl_lines_default;
|
||||
EX_stage.reg_write <= '0';
|
||||
EX_stage.epc <= (others => '0');
|
||||
EX_stage.pcn <= (others => '0');
|
||||
EX_stage.events_in <= events_clr;
|
||||
elsif sdu.EX_stall = '0' then
|
||||
EX_stage.reg_a <= ID_stage.reg_a;
|
||||
EX_stage.reg_b <= ID_stage.reg_b;
|
||||
EX_stage.events_in <= ID_stage.events;
|
||||
EX_stage.op <= ID_stage.op;
|
||||
EX_stage.ctrl <= ID_stage.ctrl;
|
||||
EX_stage.reg_write <= ID_stage.reg_write;
|
||||
EX_stage.nop <= sdu.EX_nop;
|
||||
EX_stage.IR <= ID_stage.IR;
|
||||
EX_stage.pcn <= ID_stage.pcn;
|
||||
if sdu.EX_nop = '1' then
|
||||
EX_stage.op <= NOP;
|
||||
EX_stage.IR <= (others => '0');
|
||||
EX_stage.ctrl <= ctrl_lines_default;
|
||||
EX_stage.reg_write <= '0';
|
||||
else
|
||||
EX_stage.epc <= ID_stage.epc;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
proc_stage_EX_instr_except:
|
||||
process(EX_stage)
|
||||
begin
|
||||
EX_events_instr <= events_clr;
|
||||
EX_events_instr.illegal <= EX_stage.ctrl.exc_illegal;
|
||||
EX_events_instr.break <= EX_stage.ctrl.exc_break;
|
||||
EX_events_instr.syscall <= EX_stage.ctrl.exc_syscall;
|
||||
end process;
|
||||
|
||||
proc_stage_EX_alu_except:
|
||||
process(EX_stage)
|
||||
begin
|
||||
EX_events_alu <= events_clr;
|
||||
if EX_stage.ctrl.alu_exc_en = '1' then
|
||||
if EX_stage.alu_flags.ovf = '1' then
|
||||
EX_events_alu.alu_ovf <= '1';
|
||||
end if;
|
||||
if EX_stage.alu_flags.uvf = '1' then
|
||||
EX_events_alu.alu_uvf <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
vaddr <= ID_stage.reg_a + extract_simm32(ID_stage.IR);
|
||||
|
||||
proc_stage_EX_mem_except:
|
||||
process(clk_1)
|
||||
begin
|
||||
if rising_edge(clk_1) then
|
||||
if rst = '1' then
|
||||
dmem_en <= '0';
|
||||
elsif sdu.EX_stall = '0' then
|
||||
EX_events_mem <= events_clr;
|
||||
dmem_en <= '0';
|
||||
if ID_stage.ctrl.dmem_en = '1' then
|
||||
dmem_en <= '1';
|
||||
if ID_stage.ctrl.except_en = '1' then
|
||||
if ID_stage.ctrl.word2_en = '1' then
|
||||
if vaddr(0) = '1' then
|
||||
EX_events_mem.data_load_err <= not ID_stage.ctrl.dmem_we;
|
||||
EX_events_mem.data_store_err <= ID_stage.ctrl.dmem_we;
|
||||
dmem_en <= '0';
|
||||
end if;
|
||||
elsif vaddr(1 downto 0) /= "00" then
|
||||
EX_events_mem.data_load_err <= not ID_stage.ctrl.dmem_we;
|
||||
EX_events_mem.data_store_err <= ID_stage.ctrl.dmem_we;
|
||||
dmem_en <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
proc_stage_DMEM_ADDR:
|
||||
process(clk_1)
|
||||
begin
|
||||
if rising_edge(clk_1) then
|
||||
if sdu.EX_stall = '0' then
|
||||
EX_stage.va <= vaddr;
|
||||
if cop_stat.RE = '1' then
|
||||
EX_stage.pa_off <= not vaddr(1 downto 0);
|
||||
else
|
||||
EX_stage.pa_off <= vaddr(1 downto 0);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
dmem_be <= store_be(EX_stage.pa_off, EX_stage.ctrl.dmem_we, EX_stage.ctrl.word2_en, EX_stage.ctrl.word4_en, EX_stage.ctrl.align_left, EX_stage.ctrl.byte_en_byp) after 1 ns;
|
||||
dmem_we <= EX_stage.ctrl.dmem_we;
|
||||
dmem_dout <= store_shift(EX_stage.reg_b, EX_stage.pa_off, EX_stage.ctrl.shift_offset, EX_stage.ctrl.shift_byp) after 1ns;
|
||||
dmem_addr <= EX_stage.va;
|
||||
cop_din <= EX_stage.reg_b;
|
||||
EX_stage.events <= EX_events_instr or EX_events_mem or EX_events_alu or EX_stage.events_in;
|
||||
EX_stage.exc <= event_is_active(EX_stage.events);
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
proc_wptr_mux:
|
||||
process(EX_stage)
|
||||
variable opclass : opcode_t;
|
||||
variable reg_wptr : reg_ptr_t;
|
||||
begin
|
||||
|
||||
opclass := extract_opc(EX_stage.IR);
|
||||
case opclass is
|
||||
when "000000" =>
|
||||
reg_wptr := extract_rd(EX_stage.IR);
|
||||
when others =>
|
||||
reg_wptr := extract_rt(EX_stage.IR);
|
||||
end case;
|
||||
|
||||
EX_stage.wreg_we <= EX_stage.reg_write after 1 ns;
|
||||
if reg_wptr = "00000" then
|
||||
EX_stage.wreg_we <= '0' after 1 ns;
|
||||
end if;
|
||||
|
||||
EX_stage.reg_wptr <= reg_wptr after 1 ns;
|
||||
case EX_stage.ctrl.wptr_srcsel is
|
||||
when wptr_src_imm =>
|
||||
EX_stage.reg_wptr <= reg_wptr after 1 ns;
|
||||
|
||||
when wptr_src_const =>
|
||||
EX_stage.reg_wptr <= to_unsigned(31, reg_ptr_t'length) after 1 ns;
|
||||
EX_stage.wreg_we <= '1' after 1 ns;
|
||||
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
proc_stage_bcu_op:
|
||||
process(clk_1)
|
||||
begin
|
||||
if rising_edge(clk_1) and sdu.EX_stall = '0' then
|
||||
bcu_op_a <= ID_stage.reg_a;
|
||||
bcu_op_b <= ID_stage.reg_b;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
EX_stage.alu_op1 <= EX_stage.reg_a;
|
||||
|
||||
alu_op2_mux:
|
||||
process(clk_1)
|
||||
variable data : word_t;
|
||||
begin
|
||||
|
||||
if rising_edge(clk_1) and sdu.EX_stall = '0' then
|
||||
data := ID_stage.reg_b;
|
||||
|
||||
case ID_stage.ctrl.alu.op2_src is
|
||||
|
||||
when alu_src_reg =>
|
||||
data := ID_stage.reg_b;
|
||||
|
||||
when alu_src_imm =>
|
||||
data := ID_stage.imm;
|
||||
|
||||
when others => null;
|
||||
|
||||
end case;
|
||||
|
||||
EX_stage.alu_op2 <= data;
|
||||
end if;
|
||||
|
||||
end process;
|
||||
|
||||
shifter_sa_mux:
|
||||
process(clk_1)
|
||||
variable data : shamt_t;
|
||||
variable data_inv : shamt_t;
|
||||
|
||||
begin
|
||||
if rising_edge(clk_1) and sdu.EX_stall = '0' then
|
||||
data := ID_stage.reg_a(4 downto 0);
|
||||
case ID_stage.ctrl.shamt2_srcsel is
|
||||
|
||||
when sa_src_reg =>
|
||||
data := ID_stage.reg_a(4 downto 0);
|
||||
|
||||
when sa_src_imm =>
|
||||
data := ID_stage.shamt;
|
||||
|
||||
when others => null;
|
||||
|
||||
end case;
|
||||
data_inv := not data + 1;
|
||||
if ID_stage.ctrl.alu.shift_right = '0' then
|
||||
EX_stage.shift_ctrl.shamt_rnd <= data_inv after 2 ns;
|
||||
else
|
||||
EX_stage.shift_ctrl.shamt_rnd <= data after 2 ns;
|
||||
end if;
|
||||
EX_stage.shift_ctrl.shamt_nrm <= data after 1 ns;
|
||||
EX_stage.shift_ctrl.shift_right <= ID_stage.ctrl.alu.shift_right;
|
||||
EX_stage.shift_ctrl.shift_arith <= ID_stage.ctrl.alu.shift_arith;
|
||||
end if;
|
||||
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
inst_shifter: shifter
|
||||
GENERIC MAP
|
||||
(
|
||||
data_width => word_t'length
|
||||
)
|
||||
PORT MAP
|
||||
(
|
||||
shift_ctrl => EX_stage.shift_ctrl,
|
||||
din => EX_stage.reg_b,
|
||||
dout => EX_stage.alu_op2_s
|
||||
);
|
||||
|
||||
inst_alu: alu
|
||||
GENERIC MAP
|
||||
(
|
||||
data_width => word_t'length
|
||||
)
|
||||
PORT MAP
|
||||
(
|
||||
op1_in => EX_stage.alu_op1,
|
||||
op2_in => EX_stage.alu_op2,
|
||||
op2_shifted => EX_stage.alu_op2_s,
|
||||
ctrl => EX_stage.ctrl.alu,
|
||||
result => alu_result,
|
||||
flags => EX_stage.alu_flags
|
||||
);
|
||||
|
||||
inst_bcu: bcu
|
||||
GENERIC MAP
|
||||
(
|
||||
data_width => word_t'length
|
||||
)
|
||||
PORT MAP
|
||||
(
|
||||
op1_in => bcu_op_a,
|
||||
op2_in => bcu_op_b,
|
||||
flags => bcu_flags
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- MEM stage
|
||||
--------------------------------------------------------------------------
|
||||
proc_stage_MEM_n:
|
||||
process(clk_1)
|
||||
begin
|
||||
if rising_edge(clk_1) then
|
||||
if rst = '1' then
|
||||
MEM_stage.op <= NOP;
|
||||
MEM_stage.wreg_we <= '0';
|
||||
MEM_stage.ctrl <= ctrl_lines_default;
|
||||
MEM_stage.pa_off <= (others => '0');
|
||||
MEM_stage.events_in <= events_clr;
|
||||
elsif sdu.MEM_stall = '0' then
|
||||
MEM_stage.events_in <= EX_stage.events;
|
||||
MEM_stage.op <= EX_stage.op;
|
||||
MEM_stage.wreg_we <= EX_stage.wreg_we;
|
||||
MEM_stage.ctrl <= EX_stage.ctrl;
|
||||
MEM_stage.va <= EX_stage.va;
|
||||
MEM_stage.pa_off <= EX_stage.pa_off;
|
||||
MEM_stage.reg_wptr <= EX_stage.reg_wptr;
|
||||
MEM_stage.nop <= sdu.MEM_nop;
|
||||
if EX_stage.ctrl.dmem_en = '1' then
|
||||
MEM_stage.ex_result <= EX_stage.reg_b;
|
||||
else
|
||||
MEM_stage.ex_result <= EX_stage.result;
|
||||
if cop_stat.cop_read = '1' then
|
||||
MEM_stage.ex_result <= cop_dout;
|
||||
end if;
|
||||
end if;
|
||||
if sdu.MEM_nop = '1' then
|
||||
MEM_stage.op <= NOP;
|
||||
MEM_stage.wreg_we <= '0';
|
||||
MEM_stage.ctrl <= ctrl_lines_default;
|
||||
else
|
||||
MEM_stage.pcn <= EX_stage.pcn;
|
||||
MEM_stage.epc <= EX_stage.epc;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
proc_stage_MEM_mux:
|
||||
process(MEM_stage, dmem_din)
|
||||
variable temp1 : word_t;
|
||||
variable temp2 : word_t;
|
||||
variable data : word_t;
|
||||
variable be : unsigned(3 downto 0);
|
||||
begin
|
||||
data := MEM_stage.ex_result;
|
||||
be := load_be(MEM_stage.pa_off, MEM_stage.ctrl.align_left, MEM_stage.ctrl.byte_en_byp);
|
||||
if MEM_stage.ctrl.reg_link = '1' then
|
||||
data := MEM_stage.pcn + 4;
|
||||
elsif MEM_stage.ctrl.dmem_en = '1' then
|
||||
temp1 := load_shift(dmem_din, MEM_stage.pa_off, MEM_stage.ctrl.shift_offset, MEM_stage.ctrl.shift_byp);
|
||||
temp2 := load_sign_ext(temp1, MEM_stage.ctrl.sign_ext_byp, MEM_stage.ctrl.load_signed, MEM_stage.ctrl.word2_en, MEM_stage.ctrl.word4_en);
|
||||
if be(0) = '1' then
|
||||
data(7 downto 0) := temp2(7 downto 0);
|
||||
end if;
|
||||
if be(1) = '1' then
|
||||
data(15 downto 8) := temp2(15 downto 8);
|
||||
end if;
|
||||
if be(2) = '1' then
|
||||
data(23 downto 16) := temp2(23 downto 16);
|
||||
end if;
|
||||
if be(3) = '1' then
|
||||
data(31 downto 24) := temp2(31 downto 24);
|
||||
end if;
|
||||
end if;
|
||||
MEM_stage.data <= data after 1 ns;
|
||||
|
||||
end process;
|
||||
|
||||
proc_stage_MEM_except:
|
||||
process(MEM_stage, int)
|
||||
begin
|
||||
MEM_stage.events <= MEM_stage.events_in;
|
||||
MEM_stage.events.Int <= int;
|
||||
end process;
|
||||
|
||||
MEM_stage.exc <= cop_stat.int or event_is_active(MEM_stage.events_in);
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- WB stage
|
||||
--------------------------------------------------------------------------
|
||||
proc_stage_WB_p:
|
||||
process(clk_1)
|
||||
begin
|
||||
if rising_edge(clk_1) then
|
||||
if rst = '1' then
|
||||
WB_stage.op <= NOP;
|
||||
WB_stage.wreg_we <= '0';
|
||||
elsif sdu.WB_stall = '0' then
|
||||
WB_stage.op <= MEM_stage.op;
|
||||
WB_stage.wreg_we <= MEM_stage.wreg_we;
|
||||
WB_stage.reg_wptr <= MEM_stage.reg_wptr;
|
||||
WB_stage.data <= MEM_stage.data;
|
||||
WB_stage.nop <= sdu.WB_nop;
|
||||
if sdu.WB_nop = '1' then
|
||||
WB_stage.op <= NOP;
|
||||
WB_stage.wreg_we <= '0';
|
||||
else
|
||||
WB_stage.epc <= MEM_stage.epc;
|
||||
WB_stage.bd <= MEM_stage.ctrl.branch or MEM_stage.ctrl.jump or MEM_stage.ctrl.jump_long; -- Todo: works
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
end Behavioral;
|
||||
@@ -0,0 +1,81 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: On-Chip work registers
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
use work.mips_types.all;
|
||||
|
||||
entity reg_dual is
|
||||
Generic
|
||||
(
|
||||
addr_width : integer := 3;
|
||||
data_width : integer := 8
|
||||
);
|
||||
Port (
|
||||
clk_w : in STD_LOGIC;
|
||||
we : in STD_LOGIC;
|
||||
en : in STD_LOGIC;
|
||||
wptr : in unsigned (addr_width-1 downto 0);
|
||||
din : in unsigned (data_width-1 downto 0);
|
||||
rptr_a : in unsigned (addr_width-1 downto 0);
|
||||
rptr_b : in unsigned (addr_width-1 downto 0);
|
||||
dout_a : out unsigned (data_width-1 downto 0);
|
||||
dout_b : out unsigned (data_width-1 downto 0)
|
||||
);
|
||||
end reg_dual;
|
||||
|
||||
architecture Behavioral of reg_dual is
|
||||
|
||||
constant depth : integer := 2**addr_width;
|
||||
type mem_t is array (0 to depth-1) of unsigned (data_width-1 downto 0);
|
||||
|
||||
function mem_clear(depth : natural) return mem_t is
|
||||
variable result : mem_t;
|
||||
begin
|
||||
for i in 0 to depth-1 loop
|
||||
result(i) := (others => '0');
|
||||
end loop;
|
||||
return result;
|
||||
end mem_clear;
|
||||
|
||||
signal reg_mem : mem_t := mem_clear(depth);
|
||||
|
||||
begin
|
||||
|
||||
reg_in:
|
||||
process(clk_w)
|
||||
begin
|
||||
if rising_edge(clk_w) then
|
||||
if we = '1' and en = '1' then
|
||||
reg_mem(to_integer(wptr)) <= din;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
dout_a <= reg_mem(to_integer(rptr_a)) after 2 ns;
|
||||
dout_b <= reg_mem(to_integer(rptr_b)) after 2 ns;
|
||||
|
||||
end Behavioral;
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: The shifter unit
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
use work.mips_types.all;
|
||||
|
||||
entity shifter is
|
||||
Generic
|
||||
(
|
||||
data_width : integer := 8
|
||||
);
|
||||
Port
|
||||
(
|
||||
shift_ctrl : in shift_ctrl_t;
|
||||
din : in unsigned (data_width-1 downto 0);
|
||||
dout : out unsigned (data_width-1 downto 0)
|
||||
);
|
||||
end shifter;
|
||||
|
||||
architecture Behavioral of shifter is
|
||||
|
||||
subtype word_t is unsigned(data_width-1 downto 0);
|
||||
type word_array_t is array (0 to 5) of word_t;
|
||||
|
||||
signal rot_data : word_array_t;
|
||||
signal sa_rnd : unsigned (4 downto 0);
|
||||
signal fill : std_logic;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
function rot_stage(x : unsigned; en : std_logic; stage_num : natural) return unsigned is
|
||||
variable result : unsigned(x'range);
|
||||
constant sa : natural := 2**stage_num;
|
||||
begin
|
||||
if en = '1' then
|
||||
result := x(sa-1 downto 0) & x(x'left downto sa);
|
||||
else
|
||||
result := x;
|
||||
end if;
|
||||
return result;
|
||||
|
||||
end rot_stage;
|
||||
|
||||
function rot_fill(x : unsigned; fill : std_logic; shift_right : std_logic; sa : natural) return unsigned is
|
||||
variable result : unsigned(x'range) := (others => '0');
|
||||
variable j : integer;
|
||||
begin
|
||||
|
||||
if shift_right = '0' then
|
||||
for i in 0 to x'left loop
|
||||
if i >= sa then
|
||||
result(i) := x(i);
|
||||
else
|
||||
result(i) := fill;
|
||||
end if;
|
||||
end loop;
|
||||
else
|
||||
j := x'left;
|
||||
for i in 0 to x'left loop
|
||||
if i < sa then
|
||||
result(j) := fill;
|
||||
else
|
||||
result(j) := x(j);
|
||||
end if;
|
||||
j := j - 1;
|
||||
end loop;
|
||||
end if;
|
||||
return result;
|
||||
|
||||
end rot_fill;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
begin
|
||||
|
||||
rot_data(0) <= din;
|
||||
|
||||
gen_rotate_right:
|
||||
for stage in 0 to 4 generate
|
||||
begin
|
||||
rot_data(stage+1) <= rot_stage(rot_data(stage), sa_rnd(stage), stage);
|
||||
end generate;
|
||||
|
||||
sa_rnd <= shift_ctrl.shamt_rnd;
|
||||
fill <= shift_ctrl.shift_arith and din(data_width-1);
|
||||
dout <= rot_fill(rot_data(5), fill, shift_ctrl.shift_right, to_integer(shift_ctrl.shamt_nrm)) after 5 ns;
|
||||
-- dout <= rot_data(5);
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
end Behavioral;
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: JIPS top file
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
library work;
|
||||
use work.mips_types.all;
|
||||
|
||||
entity mips_top is
|
||||
Port
|
||||
(
|
||||
debug : out unsigned(1 downto 0);
|
||||
RST_I : in STD_LOGIC;
|
||||
CLK_I : in STD_LOGIC;
|
||||
ACK_I : in STD_LOGIC;
|
||||
SRDY_I : in STD_LOGIC;
|
||||
ADDR_O : out word_t;
|
||||
DAT_I : in word_t;
|
||||
DAT_O : out word_t;
|
||||
WE_O : out STD_LOGIC;
|
||||
SEL_O : out unsigned(3 downto 0);
|
||||
CYC_O : out STD_LOGIC;
|
||||
STB_O : out STD_LOGIC;
|
||||
MRDY_O : out STD_LOGIC;
|
||||
INT : in unsigned (5 downto 0)
|
||||
);
|
||||
|
||||
end mips_top;
|
||||
|
||||
architecture rtl of mips_top is
|
||||
|
||||
COMPONENT pipeline is
|
||||
Port
|
||||
(
|
||||
rst : in STD_LOGIC;
|
||||
clk : in STD_LOGIC;
|
||||
halt : in STD_LOGIC;
|
||||
int : in unsigned (5 downto 0);
|
||||
imem_err : in STD_LOGIC;
|
||||
imem_rdy : in STD_LOGIC;
|
||||
imem_en : out STD_LOGIC;
|
||||
imem_addr : out word_t;
|
||||
imem_data : in word_t;
|
||||
dmem_err : in STD_LOGIC;
|
||||
dmem_rdy : in STD_LOGIC;
|
||||
dmem_en : out STD_LOGIC;
|
||||
dmem_we : out STD_LOGIC;
|
||||
dmem_be : out unsigned(3 downto 0);
|
||||
dmem_addr : out word_t;
|
||||
dmem_din : in word_t;
|
||||
dmem_dout : out word_t
|
||||
);
|
||||
END COMPONENT;
|
||||
signal imem_err : std_logic;
|
||||
signal imem_rdy : std_logic;
|
||||
signal imem_en : std_logic;
|
||||
signal imem_addr : word_t;
|
||||
signal imem_din : word_t;
|
||||
signal dmem_err : std_logic;
|
||||
signal dmem_rdy : std_logic;
|
||||
signal dmem_en : std_logic;
|
||||
signal dmem_we : std_logic;
|
||||
signal dmem_addr : word_t;
|
||||
signal dmem_dout : word_t;
|
||||
signal dmem_din : word_t;
|
||||
signal dmem_be : unsigned(3 downto 0);
|
||||
|
||||
|
||||
COMPONENT biu
|
||||
GENERIC
|
||||
(
|
||||
icache_size : natural;
|
||||
dcache_size : natural
|
||||
);
|
||||
PORT
|
||||
(
|
||||
RST_I : in STD_LOGIC;
|
||||
CLK_I : in STD_LOGIC;
|
||||
ACK_I : in STD_LOGIC;
|
||||
SRDY_I : in STD_LOGIC;
|
||||
ADDR_O : out word_t;
|
||||
DAT_I : in word_t;
|
||||
DAT_O : out word_t;
|
||||
WE_O : out STD_LOGIC;
|
||||
SEL_O : out unsigned(3 downto 0);
|
||||
CYC_O : out STD_LOGIC;
|
||||
STB_O : out STD_LOGIC;
|
||||
MRDY_O : out STD_LOGIC;
|
||||
cpu_imem_err : out STD_LOGIC;
|
||||
cpu_imem_rdy : out STD_LOGIC;
|
||||
cpu_imem_en : in STD_LOGIC;
|
||||
cpu_imem_addr : in word_t;
|
||||
cpu_imem_din : out word_t;
|
||||
cpu_dmem_err : out STD_LOGIC;
|
||||
cpu_dmem_rdy : out STD_LOGIC;
|
||||
cpu_dmem_en : in STD_LOGIC;
|
||||
cpu_dmem_we : in STD_LOGIC;
|
||||
cpu_dmem_be : in unsigned(3 downto 0);
|
||||
cpu_dmem_dout : in word_t;
|
||||
cpu_dmem_din : out word_t;
|
||||
cpu_dmem_addr : in word_t
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
begin
|
||||
|
||||
-------------------------------------------------------------------
|
||||
debug(0) <= imem_err;
|
||||
debug(1) <= dmem_err;
|
||||
|
||||
inst_pipeline: pipeline
|
||||
PORT MAP
|
||||
(
|
||||
rst => RST_I,
|
||||
clk => CLK_I,
|
||||
halt => '0',
|
||||
int => INT,
|
||||
imem_err => imem_err,
|
||||
imem_rdy => imem_rdy,
|
||||
imem_en => imem_en,
|
||||
imem_addr => imem_addr,
|
||||
imem_data => imem_din,
|
||||
dmem_err => dmem_err,
|
||||
dmem_rdy => dmem_rdy,
|
||||
dmem_en => dmem_en,
|
||||
dmem_we => dmem_we,
|
||||
dmem_be => dmem_be,
|
||||
dmem_addr => dmem_addr,
|
||||
dmem_din => dmem_din,
|
||||
dmem_dout => dmem_dout
|
||||
);
|
||||
|
||||
inst_biu: biu
|
||||
GENERIC MAP
|
||||
(
|
||||
icache_size => 4096, -- words
|
||||
dcache_size => 4096 -- words
|
||||
)
|
||||
PORT MAP
|
||||
(
|
||||
RST_I => RST_I,
|
||||
CLK_I => CLK_I,
|
||||
ACK_I => ACK_I,
|
||||
SRDY_I => SRDY_I,
|
||||
ADDR_O => ADDR_O,
|
||||
DAT_I => DAT_I,
|
||||
DAT_O => DAT_O,
|
||||
WE_O => WE_O,
|
||||
SEL_O => SEL_O,
|
||||
CYC_O => CYC_O,
|
||||
STB_O => STB_O,
|
||||
MRDY_O => MRDY_O,
|
||||
cpu_imem_err => imem_err,
|
||||
cpu_imem_rdy => imem_rdy,
|
||||
cpu_imem_en => imem_en,
|
||||
cpu_imem_addr => imem_addr,
|
||||
cpu_imem_din => imem_din,
|
||||
cpu_dmem_err => dmem_err,
|
||||
cpu_dmem_rdy => dmem_rdy,
|
||||
cpu_dmem_en => dmem_en,
|
||||
cpu_dmem_we => dmem_we,
|
||||
cpu_dmem_be => dmem_be,
|
||||
cpu_dmem_addr => dmem_addr,
|
||||
cpu_dmem_din => dmem_din,
|
||||
cpu_dmem_dout => dmem_dout
|
||||
);
|
||||
|
||||
end rtl;
|
||||
@@ -0,0 +1,619 @@
|
||||
--------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: Types, constants and functions for JIPS
|
||||
--
|
||||
-- Copyright (C) 2008 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
package mips_types is
|
||||
|
||||
-- Revision of the CPU
|
||||
constant REVISION : integer := 9;
|
||||
constant WORD_WIDTH : integer := 32;
|
||||
|
||||
--Types
|
||||
subtype instr_name_t is string(1 to 12);
|
||||
type instr_name_array_t is array (0 to 63) of instr_name_t;
|
||||
subtype opcode_t is unsigned (5 downto 0);
|
||||
subtype word_t is unsigned (WORD_WIDTH-1 downto 0);
|
||||
subtype reg_ptr_t is unsigned (4 downto 0);
|
||||
subtype shamt_t is unsigned(4 downto 0);
|
||||
subtype sa_t is natural range 0 to 63;
|
||||
subtype func_t is unsigned(5 downto 0);
|
||||
|
||||
type opclass_t is (special, regimm, opcode);
|
||||
|
||||
type op_t is
|
||||
(
|
||||
nop,
|
||||
op_sll,
|
||||
op_srl,
|
||||
op_sra,
|
||||
op_sllv,
|
||||
op_srlv,
|
||||
op_srav,
|
||||
op_jr,
|
||||
op_jalr,
|
||||
op_syscall,
|
||||
op_break,
|
||||
op_mfhi,
|
||||
op_mthi,
|
||||
op_mflo,
|
||||
op_mtlo,
|
||||
op_mult,
|
||||
op_multu,
|
||||
op_div,
|
||||
op_divu,
|
||||
op_add,
|
||||
op_addu,
|
||||
op_sub,
|
||||
op_subu,
|
||||
op_and,
|
||||
op_or,
|
||||
op_xor,
|
||||
op_nor,
|
||||
op_slt,
|
||||
op_sltu,
|
||||
op_bltz,
|
||||
op_bgez,
|
||||
op_bltzal,
|
||||
op_bgezal,
|
||||
op_j,
|
||||
op_jal,
|
||||
op_beq,
|
||||
op_bne,
|
||||
op_blez,
|
||||
op_bgtz,
|
||||
op_addi,
|
||||
op_addiu,
|
||||
op_slti,
|
||||
op_sltiu,
|
||||
op_andi,
|
||||
op_ori,
|
||||
op_xori,
|
||||
op_lui,
|
||||
op_lb,
|
||||
op_lh,
|
||||
op_lwl,
|
||||
op_lw,
|
||||
op_lbu,
|
||||
op_lhu,
|
||||
op_lwr,
|
||||
op_sb,
|
||||
op_sh,
|
||||
op_swl,
|
||||
op_sw,
|
||||
op_swr,
|
||||
op_cop0,
|
||||
op_cop1,
|
||||
op_cop2,
|
||||
op_cop3,
|
||||
op_lwc1,
|
||||
op_lwc2,
|
||||
op_lwc3,
|
||||
op_swc1,
|
||||
op_swc2,
|
||||
op_swc3
|
||||
);
|
||||
|
||||
attribute ENUM_ENCODING : string;
|
||||
|
||||
type imm_src_t is (src_imm32, src_imm16, src_imm16_high);
|
||||
type sa_src_t is (sa_src_reg, sa_src_imm);
|
||||
type alu_src1_t is (alu_src_reg);
|
||||
type alu_src2_t is (alu_src_reg, alu_src_imm);
|
||||
type bc_src_t is (bc_eq_ne, bc_lez_gtz, bc_ltz_gez);
|
||||
type shift_opsel_t is (shift_sll, shift_srl, shift_sra);
|
||||
type wptr_src_t is (wptr_src_imm, wptr_src_const);
|
||||
|
||||
-- attribute ENUM_ENCODING of itype_t: type is "ONE-HOT";
|
||||
|
||||
type pc_t is record
|
||||
curr : word_t;
|
||||
last : word_t;
|
||||
nxt : word_t;
|
||||
pc_branch : word_t;
|
||||
is_branch : boolean;
|
||||
end record;
|
||||
|
||||
type alu_outsel_t is
|
||||
(
|
||||
alu_adder,
|
||||
alu_shift2,
|
||||
alu_and,
|
||||
alu_or,
|
||||
alu_xor,
|
||||
alu_nor,
|
||||
alu_ltu,
|
||||
alu_lts
|
||||
);
|
||||
|
||||
type alu_flags_t is record
|
||||
c : STD_LOGIC;
|
||||
uvf : STD_LOGIC;
|
||||
ovf : STD_LOGIC;
|
||||
ltu : STD_LOGIC;
|
||||
lts : STD_LOGIC;
|
||||
end record;
|
||||
|
||||
type bcu_flags_t is record
|
||||
eq : STD_LOGIC;
|
||||
ltz : STD_LOGIC;
|
||||
end record;
|
||||
|
||||
type event_t is record
|
||||
Int : unsigned(5 downto 0);
|
||||
data_load_err : STD_LOGIC;
|
||||
data_store_err : STD_LOGIC;
|
||||
inst_load_err : STD_LOGIC;
|
||||
inst_priv_addr : STD_LOGIC;
|
||||
alu_ovf : STD_LOGIC;
|
||||
alu_uvf : STD_LOGIC;
|
||||
syscall : STD_LOGIC;
|
||||
break : STD_LOGIC;
|
||||
illegal : STD_LOGIC;
|
||||
end record;
|
||||
|
||||
type exc_flags_t is record
|
||||
Int : STD_LOGIC;
|
||||
DAdEL : STD_LOGIC;
|
||||
DAdES : STD_LOGIC;
|
||||
IAdEL : STD_LOGIC;
|
||||
IAdEK : STD_LOGIC;
|
||||
Ov : STD_LOGIC;
|
||||
Sys : STD_LOGIC;
|
||||
Bp : STD_LOGIC;
|
||||
RI : STD_LOGIC;
|
||||
IBE : STD_LOGIC;
|
||||
DBE : STD_LOGIC;
|
||||
end record;
|
||||
|
||||
type except_t is record
|
||||
act : STD_LOGIC;
|
||||
epc : word_t;
|
||||
cause : word_t;
|
||||
end record;
|
||||
|
||||
type cop_ctrl_in_t is record
|
||||
bd_wb : STD_LOGIC;
|
||||
epc_mem : word_t;
|
||||
epc_wb : word_t;
|
||||
imem_addr : word_t;
|
||||
dmem_addr : word_t;
|
||||
exc_left : STD_LOGIC;
|
||||
end record;
|
||||
|
||||
type cop_ctrl_out_t is record
|
||||
RE : STD_LOGIC;
|
||||
ee : STD_LOGIC;
|
||||
ec : STD_LOGIC;
|
||||
exc_commit : STD_LOGIC;
|
||||
exc_pending : STD_LOGIC;
|
||||
exc_exit : STD_LOGIC;
|
||||
reg_write : STD_LOGIC;
|
||||
cop_read : STD_LOGIC;
|
||||
user_mode : STD_LOGIC;
|
||||
int : STD_LOGIC;
|
||||
exc_vec : word_t;
|
||||
end record;
|
||||
|
||||
type sdu_t is record
|
||||
ID_nop : STD_LOGIC;
|
||||
EX_nop : STD_LOGIC;
|
||||
MEM_nop : STD_LOGIC;
|
||||
WB_nop : STD_LOGIC;
|
||||
ID_stall : STD_LOGIC;
|
||||
EX_stall : STD_LOGIC;
|
||||
MEM_stall : STD_LOGIC;
|
||||
WB_stall : STD_LOGIC;
|
||||
end record;
|
||||
|
||||
type hdu_t is record
|
||||
alu_fwd_a_ex : boolean;
|
||||
alu_fwd_a_mem : boolean;
|
||||
alu_fwd_a_wb : boolean;
|
||||
alu_fwd_b_ex : boolean;
|
||||
alu_fwd_b_mem : boolean;
|
||||
alu_fwd_b_wb : boolean;
|
||||
end record;
|
||||
|
||||
type alu_ctrl_t is record
|
||||
outsel : alu_outsel_t;
|
||||
add : STD_LOGIC;
|
||||
shift_right : STD_LOGIC;
|
||||
shift_arith : STD_LOGIC;
|
||||
op1_src : alu_src1_t;
|
||||
op2_src : alu_src2_t;
|
||||
end record;
|
||||
|
||||
type shift_ctrl_t is record
|
||||
shamt_nrm : shamt_t;
|
||||
shamt_rnd : shamt_t;
|
||||
shift_right : STD_LOGIC;
|
||||
shift_arith : STD_LOGIC;
|
||||
end record;
|
||||
|
||||
type ctrl_lines_t is record
|
||||
branch : STD_LOGIC;
|
||||
jump_long : STD_LOGIC;
|
||||
jump : STD_LOGIC;
|
||||
bc_not : STD_LOGIC;
|
||||
bc_src : bc_src_t;
|
||||
imm_src : imm_src_t;
|
||||
alu : alu_ctrl_t;
|
||||
reg_write : STD_LOGIC;
|
||||
reg_link : STD_LOGIC;
|
||||
dmem_we : STD_LOGIC;
|
||||
dmem_en : STD_LOGIC;
|
||||
shamt2_srcsel : sa_src_t;
|
||||
wptr_srcsel : wptr_src_t;
|
||||
cop_instr_en : STD_LOGIC;
|
||||
shift_offset : unsigned(1 downto 0);
|
||||
shift_byp : STD_LOGIC;
|
||||
byte_en_byp : STD_LOGIC;
|
||||
sign_ext_byp : STD_LOGIC;
|
||||
word4_en : STD_LOGIC;
|
||||
word2_en : STD_LOGIC;
|
||||
align_left : STD_LOGIC;
|
||||
load_signed : STD_LOGIC;
|
||||
mul_access : STD_LOGIC;
|
||||
mul_hilo_we : STD_LOGIC;
|
||||
mul_mul_divn : STD_LOGIC;
|
||||
mul_start : STD_LOGIC;
|
||||
mul_s_un : STD_LOGIC;
|
||||
mul_hilo_sel : STD_LOGIC;
|
||||
exc_break : STD_LOGIC;
|
||||
exc_syscall : STD_LOGIC;
|
||||
exc_illegal : STD_LOGIC;
|
||||
except_en : STD_LOGIC;
|
||||
alu_exc_en : STD_LOGIC;
|
||||
end record;
|
||||
|
||||
type ID_t is record
|
||||
nop : STD_LOGIC;
|
||||
exc : std_logic;
|
||||
IR : word_t;
|
||||
op : op_t;
|
||||
pcn : word_t;
|
||||
epc : word_t;
|
||||
jimm32 : word_t;
|
||||
bimm18 : word_t;
|
||||
imm : word_t;
|
||||
shamt : shamt_t;
|
||||
ctrl : ctrl_lines_t;
|
||||
reg_write : STD_LOGIC;
|
||||
reg_a_rptr : reg_ptr_t;
|
||||
reg_b_rptr : reg_ptr_t;
|
||||
reg_a : word_t;
|
||||
reg_b : word_t;
|
||||
events : event_t;
|
||||
end record;
|
||||
|
||||
type EX_t is record
|
||||
nop : STD_LOGIC;
|
||||
exc : std_logic;
|
||||
IR : word_t;
|
||||
op : op_t;
|
||||
pcn : word_t;
|
||||
epc : word_t;
|
||||
reg_a : word_t;
|
||||
reg_b : word_t;
|
||||
ctrl : ctrl_lines_t;
|
||||
shift_ctrl : shift_ctrl_t;
|
||||
alu_op1 : word_t;
|
||||
alu_op2 : word_t;
|
||||
alu_op2_s : word_t;
|
||||
alu_flags : alu_flags_t;
|
||||
result : word_t;
|
||||
reg_write : STD_LOGIC;
|
||||
wreg_we : STD_LOGIC;
|
||||
reg_wptr : reg_ptr_t;
|
||||
reg_a_rptr : reg_ptr_t;
|
||||
reg_b_rptr : reg_ptr_t;
|
||||
va : word_t;
|
||||
pa_off : unsigned(1 downto 0);
|
||||
events_in : event_t;
|
||||
events : event_t;
|
||||
end record;
|
||||
|
||||
type MEM_t is record
|
||||
nop : STD_LOGIC;
|
||||
exc : std_logic;
|
||||
op : op_t;
|
||||
pcn : word_t;
|
||||
epc : word_t;
|
||||
ctrl : ctrl_lines_t;
|
||||
ex_result : word_t;
|
||||
reg_wptr : reg_ptr_t;
|
||||
wreg_we : STD_LOGIC;
|
||||
data : word_t;
|
||||
va : word_t;
|
||||
pa_off : unsigned(1 downto 0);
|
||||
events_in : event_t;
|
||||
events : event_t;
|
||||
end record;
|
||||
|
||||
type WB_t is record
|
||||
nop : STD_LOGIC;
|
||||
op : op_t;
|
||||
epc : word_t;
|
||||
reg_wptr : reg_ptr_t;
|
||||
wreg_we : STD_LOGIC;
|
||||
data : word_t;
|
||||
bd : STD_LOGIC;
|
||||
end record;
|
||||
|
||||
|
||||
type rom_special_t is array (0 to 2**func_t'length-1) of ctrl_lines_t;
|
||||
type rom_regimm_t is array (0 to 2**reg_ptr_t'length-1) of ctrl_lines_t;
|
||||
type rom_opcode_t is array (0 to 2**opcode_t'length-1) of ctrl_lines_t;
|
||||
|
||||
function store_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t;
|
||||
function store_be(va : unsigned(1 downto 0); be_src, word2_en, word4_en, align_left, bypass : std_logic) return unsigned;
|
||||
function load_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t;
|
||||
function load_be(va : unsigned(1 downto 0); align_left, bypass : std_logic) return unsigned;
|
||||
function load_sign_ext(x : word_t; bypass, signed, word2_en, word4_en : std_logic) return word_t;
|
||||
function events_clr return event_t;
|
||||
function event_is_active(e : event_t) return std_logic;
|
||||
function "or" (a, b : event_t) return event_t;
|
||||
|
||||
end mips_types;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
package body mips_types is
|
||||
|
||||
function store_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t is
|
||||
variable stage1 : word_t;
|
||||
variable result : word_t;
|
||||
variable sa : unsigned(1 downto 0);
|
||||
begin
|
||||
|
||||
if bypass = '1' then
|
||||
sa := "00";
|
||||
else
|
||||
sa := va + shift_off;
|
||||
end if;
|
||||
|
||||
stage1 := x;
|
||||
if sa(0) = '1' then
|
||||
stage1 := x(23 downto 0) & x(31 downto 24);
|
||||
end if;
|
||||
result := stage1;
|
||||
if sa(1) = '1' then
|
||||
result := stage1(15 downto 0) & stage1(31 downto 16);
|
||||
end if;
|
||||
|
||||
return result;
|
||||
end store_shift;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
function store_be(va : unsigned(1 downto 0); be_src, word2_en, word4_en, align_left, bypass : std_logic) return unsigned is
|
||||
variable result : unsigned(3 downto 0);
|
||||
begin
|
||||
if bypass = '1' then
|
||||
result := (3 downto 0 => be_src);
|
||||
elsif word2_en = '1' then
|
||||
case va is
|
||||
when "00" | "01" =>
|
||||
result := "00" & be_src & be_src;
|
||||
when "10" | "11" =>
|
||||
result := be_src & be_src & "00";
|
||||
when others =>
|
||||
result := "0000";
|
||||
end case;
|
||||
elsif word4_en = '1' then
|
||||
case va is
|
||||
when "00" =>
|
||||
result := "000" & be_src;
|
||||
when "01" =>
|
||||
result := "00" & be_src & '0';
|
||||
when "10" =>
|
||||
result := '0' & be_src & "00";
|
||||
when "11" =>
|
||||
result := be_src & "000";
|
||||
when others =>
|
||||
result := "0000";
|
||||
end case;
|
||||
elsif align_left = '1' then
|
||||
case va is
|
||||
when "00" =>
|
||||
result := be_src & be_src & be_src & be_src;
|
||||
when "01" =>
|
||||
result := be_src & be_src & be_src & '0';
|
||||
when "10" =>
|
||||
result := be_src & be_src & "00";
|
||||
when "11" =>
|
||||
result := be_src & "000";
|
||||
when others =>
|
||||
result := "0000";
|
||||
end case;
|
||||
else
|
||||
case va is
|
||||
when "00" =>
|
||||
result := "000" & be_src;
|
||||
when "01" =>
|
||||
result := "00" & be_src & be_src;
|
||||
when "10" =>
|
||||
result := '0' & be_src & be_src & be_src;
|
||||
when "11" =>
|
||||
result := be_src & be_src & be_src & be_src;
|
||||
when others =>
|
||||
result := "0000";
|
||||
end case;
|
||||
end if;
|
||||
|
||||
return result;
|
||||
|
||||
end store_be;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
function load_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t is
|
||||
variable stage1 : word_t;
|
||||
variable result : word_t;
|
||||
variable sa : unsigned(1 downto 0);
|
||||
|
||||
begin
|
||||
if bypass = '1' then
|
||||
sa := "00";
|
||||
else
|
||||
sa := va + shift_off;
|
||||
end if;
|
||||
|
||||
stage1 := x;
|
||||
if sa(0) = '1' then
|
||||
stage1 := x(7 downto 0) & x(31 downto 8);
|
||||
end if;
|
||||
result := stage1;
|
||||
if sa(1) = '1' then
|
||||
result := stage1(15 downto 0) & stage1(31 downto 16);
|
||||
end if;
|
||||
|
||||
return result;
|
||||
end load_shift;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
function load_be(va : unsigned(1 downto 0); align_left, bypass : std_logic) return unsigned is
|
||||
variable result : unsigned(3 downto 0);
|
||||
begin
|
||||
if bypass = '1' then
|
||||
result := (3 downto 0 => '1');
|
||||
elsif align_left = '1' then
|
||||
case va is
|
||||
when "00" =>
|
||||
result := "1000";
|
||||
when "01" =>
|
||||
result := "1100";
|
||||
when "10" =>
|
||||
result := "1110";
|
||||
when "11" =>
|
||||
result := "1111";
|
||||
when others =>
|
||||
result := "0000";
|
||||
end case;
|
||||
else
|
||||
case va is
|
||||
when "00" =>
|
||||
result := "1111";
|
||||
when "01" =>
|
||||
result := "0111";
|
||||
when "10" =>
|
||||
result := "0011";
|
||||
when "11" =>
|
||||
result := "0001";
|
||||
when others =>
|
||||
result := "0000";
|
||||
end case;
|
||||
end if;
|
||||
|
||||
return result;
|
||||
|
||||
end load_be;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
function load_sign_ext(x : word_t; bypass, signed, word2_en, word4_en : std_logic) return word_t is
|
||||
variable result : word_t;
|
||||
variable sign : std_logic;
|
||||
|
||||
begin
|
||||
if bypass = '1' then
|
||||
result := x;
|
||||
elsif word2_en = '1' then
|
||||
sign := signed and x(15);
|
||||
result := (31 downto 16 => sign) & x(15 downto 0);
|
||||
else
|
||||
sign := signed and x(7);
|
||||
result := (31 downto 8 => sign) & x(7 downto 0);
|
||||
end if;
|
||||
|
||||
return result;
|
||||
end load_sign_ext;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
function events_clr return event_t is
|
||||
variable result : event_t;
|
||||
begin
|
||||
result.Int := (others => '0');
|
||||
result.data_load_err := '0';
|
||||
result.data_store_err := '0';
|
||||
result.inst_load_err := '0';
|
||||
result.inst_priv_addr := '0';
|
||||
result.alu_ovf := '0';
|
||||
result.alu_uvf := '0';
|
||||
result.syscall := '0';
|
||||
result.break := '0';
|
||||
result.illegal := '0';
|
||||
|
||||
return result;
|
||||
|
||||
end events_clr;
|
||||
|
||||
function event_is_active(e : event_t) return std_logic is
|
||||
variable result : std_logic;
|
||||
begin
|
||||
result := '0';
|
||||
|
||||
for i in e.Int'range loop
|
||||
result := result or e.Int(i);
|
||||
end loop;
|
||||
|
||||
result := result or e.data_load_err;
|
||||
result := result or e.data_store_err;
|
||||
result := result or e.inst_load_err;
|
||||
result := result or e.inst_priv_addr;
|
||||
result := result or e.alu_ovf;
|
||||
result := result or e.alu_uvf;
|
||||
result := result or e.syscall;
|
||||
result := result or e.break;
|
||||
result := result or e.illegal;
|
||||
|
||||
return result;
|
||||
|
||||
end event_is_active;
|
||||
|
||||
function "or" (a, b : event_t) return event_t is
|
||||
variable result : event_t;
|
||||
begin
|
||||
for i in a.Int'range loop
|
||||
result.Int(i) := a.Int(i) or b.Int(i);
|
||||
end loop;
|
||||
result.data_load_err := a.data_load_err or b.data_load_err;
|
||||
result.data_store_err := a.data_store_err or b.data_store_err;
|
||||
result.inst_load_err := a.inst_load_err or b.inst_load_err;
|
||||
result.inst_priv_addr := a.inst_priv_addr or b.inst_priv_addr;
|
||||
result.alu_ovf := a.alu_ovf or b.alu_ovf;
|
||||
result.alu_uvf := a.alu_uvf or b.alu_uvf;
|
||||
result.syscall := a.syscall or b.syscall;
|
||||
result.break := a.break or b.break;
|
||||
result.illegal := a.illegal or b.illegal;
|
||||
|
||||
return result;
|
||||
|
||||
end "or";
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
end mips_types;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------
|
||||
@@ -0,0 +1,332 @@
|
||||
-------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: Testbench for JCPU
|
||||
-- also writes 'opc.lst' for JASM-assembler
|
||||
--
|
||||
-- Copyright (C) 2007 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
LIBRARY ieee;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
USE ieee.numeric_std.ALL;
|
||||
|
||||
library work;
|
||||
use work.mips_types.all;
|
||||
use work.mips_instr.all;
|
||||
|
||||
ENTITY tb_mips_muldiv IS
|
||||
END tb_mips_muldiv;
|
||||
|
||||
ARCHITECTURE behavior OF tb_mips_muldiv IS
|
||||
|
||||
COMPONENT muldiv is
|
||||
Port
|
||||
(
|
||||
rst : in std_logic;
|
||||
clk : in std_logic;
|
||||
hilo_we : in std_logic;
|
||||
din_hi : in word_t;
|
||||
din_lo : in word_t;
|
||||
mul_divn : in std_logic;
|
||||
s_un : in std_logic;
|
||||
start : in std_logic;
|
||||
hilo_sel : in std_logic;
|
||||
busy : out std_logic;
|
||||
dout : out word_t
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
constant CLK_PERIOD : time := 10 ns;
|
||||
signal ENABLE_FAIL_REPORT : boolean := true;
|
||||
signal rst : std_logic := '1';
|
||||
signal clk : std_logic := '1';
|
||||
signal busy : std_logic;
|
||||
signal mul_divn : std_logic := '0';
|
||||
signal s_un : std_logic := '1';
|
||||
signal hilo_we : std_logic := '0';
|
||||
signal start : std_logic := '0';
|
||||
signal din_hi : word_t := (others => '-');
|
||||
signal din_lo : word_t := (others => '-');
|
||||
signal dout : word_t;
|
||||
signal hilo_sel : std_logic := '0';
|
||||
signal md_result : unsigned (2*word_t'length-1 downto 0) := (others => '0');
|
||||
signal ref_result : unsigned (2*word_t'length-1 downto 0);
|
||||
signal ref_hi : unsigned (word_t'length-1 downto 0);
|
||||
signal rtmp : unsigned (2*word_t'length-1 downto 0);
|
||||
signal tmp2 : unsigned (word_t'length-1 downto 0);
|
||||
signal check : std_logic;
|
||||
|
||||
type word_array_t is array (natural range <>) of word_t;
|
||||
|
||||
constant operands : word_array_t(0 to 63) :=
|
||||
(
|
||||
X"00000000",
|
||||
X"00000001",
|
||||
X"00000010",
|
||||
X"00000100",
|
||||
X"00001000",
|
||||
X"00010000",
|
||||
X"00100000",
|
||||
X"01000000",
|
||||
X"10000000",
|
||||
X"0000000F",
|
||||
X"000000FF",
|
||||
X"00000FFF",
|
||||
X"0000FFFF",
|
||||
X"000FFFFF",
|
||||
X"00FFFFFF",
|
||||
X"0FFFFFFF",
|
||||
X"12345678",
|
||||
X"23456789",
|
||||
X"7FFFFFFF",
|
||||
X"80000000",
|
||||
X"A541B3B9",
|
||||
X"80000001",
|
||||
X"80000010",
|
||||
X"80000100",
|
||||
X"80001000",
|
||||
X"80010000",
|
||||
X"80100000",
|
||||
X"81000000",
|
||||
X"87654321",
|
||||
X"98765432",
|
||||
X"FFFFFFFF",
|
||||
X"FFFFFFFE",
|
||||
X"FFFFFFFD",
|
||||
X"FFFFFFFB",
|
||||
X"FFFFFFF7",
|
||||
X"FFFFFFEF",
|
||||
X"FFFFFFDF",
|
||||
X"FFFFFFBF",
|
||||
X"FFFFFF7F",
|
||||
X"FFFFFEFF",
|
||||
X"FFFFFDFF",
|
||||
X"FFFFFBFF",
|
||||
X"FFFFF7FF",
|
||||
X"FFFFEFFF",
|
||||
X"FFFFDFFF",
|
||||
X"FFFFBFFF",
|
||||
X"FFFF7FFF",
|
||||
X"FFFEFFFF",
|
||||
X"FFFDFFFF",
|
||||
X"FFFBFFFF",
|
||||
X"FFF7FFFF",
|
||||
X"FFEFFFFF",
|
||||
X"FFDFFFFF",
|
||||
X"FFBFFFFF",
|
||||
X"FF7FFFFF",
|
||||
X"FEFFFFFF",
|
||||
X"FDFFFFFF",
|
||||
X"FBFFFFFF",
|
||||
X"F7FFFFFF",
|
||||
X"EFFFFFFF",
|
||||
X"DFFFFFFF",
|
||||
X"BFFFFFFF",
|
||||
X"CFFFFFFF",
|
||||
X"7FFFFFFF"
|
||||
);
|
||||
|
||||
BEGIN
|
||||
|
||||
uut: muldiv
|
||||
PORT MAP(
|
||||
rst => rst,
|
||||
clk => clk,
|
||||
hilo_we => hilo_we,
|
||||
din_hi => din_hi,
|
||||
din_lo => din_lo,
|
||||
mul_divn => mul_divn,
|
||||
s_un => s_un,
|
||||
start => start,
|
||||
hilo_sel => hilo_sel,
|
||||
busy => busy,
|
||||
dout => dout
|
||||
);
|
||||
|
||||
CLK_GEN: process
|
||||
begin
|
||||
wait for CLK_PERIOD/2;
|
||||
clk <= not clk;
|
||||
end process;
|
||||
|
||||
REF_GEN: process
|
||||
begin
|
||||
if mul_divn = '0' then
|
||||
wait until rising_edge(clk) and check = '1';
|
||||
if s_un = '1' then
|
||||
rtmp <= unsigned(signed(md_result(31 downto 0)) * signed(din_lo));
|
||||
wait until rising_edge(clk);
|
||||
tmp2 <= unsigned(signed(rtmp(31 downto 0)) + signed(md_result(63 downto 32)));
|
||||
wait until rising_edge(clk);
|
||||
ref_hi <= tmp2(31 downto 0);
|
||||
else
|
||||
rtmp <= md_result(31 downto 0) * din_lo;
|
||||
wait until rising_edge(clk);
|
||||
tmp2 <= rtmp(31 downto 0) + md_result(63 downto 32);
|
||||
wait until rising_edge(clk);
|
||||
ref_hi <= tmp2(31 downto 0);
|
||||
end if;
|
||||
wait until rising_edge(clk);
|
||||
|
||||
if din_lo /= X"00000000" then
|
||||
if ENABLE_FAIL_REPORT then
|
||||
assert din_hi = ref_hi report "Error on divison" severity failure;
|
||||
end if;
|
||||
end if;
|
||||
else
|
||||
wait until rising_edge(clk) and check = '1';
|
||||
if s_un = '1' then
|
||||
ref_result <= unsigned(signed(din_hi) * signed(din_lo));
|
||||
else
|
||||
ref_result <= unsigned(din_hi) * unsigned(din_lo);
|
||||
end if;
|
||||
wait until rising_edge(clk);
|
||||
wait until rising_edge(clk);
|
||||
wait until rising_edge(clk);
|
||||
if ENABLE_FAIL_REPORT then
|
||||
assert ref_result = md_result report "Error on multiplication" severity failure;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end process;
|
||||
|
||||
STIMULUS: process
|
||||
|
||||
begin
|
||||
|
||||
wait for 3*CLK_PERIOD;
|
||||
wait until rising_edge(clk);
|
||||
rst <= '0';
|
||||
wait for 2*CLK_PERIOD;
|
||||
|
||||
mul_divn <= '0';
|
||||
s_un <= '0';
|
||||
for i in 0 to operands'length-1 loop
|
||||
for j in 0 to operands'length-1 loop
|
||||
check <= '0';
|
||||
wait until rising_edge(clk) and busy = '0';
|
||||
din_hi <= operands(i);
|
||||
din_lo <= operands(j);
|
||||
start <= '1';
|
||||
wait until rising_edge(clk);
|
||||
start <= '0';
|
||||
hilo_sel <= '0';
|
||||
|
||||
-- Read result
|
||||
wait until rising_edge(clk) and busy = '0';
|
||||
wait until rising_edge(clk);
|
||||
md_result(31 downto 0) <= dout;
|
||||
wait until rising_edge(clk);
|
||||
hilo_sel <= '1';
|
||||
wait until rising_edge(clk);
|
||||
md_result(63 downto 32) <= dout;
|
||||
check <= '1';
|
||||
wait until rising_edge(clk);
|
||||
check <= '0';
|
||||
wait for 8*CLK_PERIOD;
|
||||
end loop;
|
||||
end loop;
|
||||
|
||||
s_un <= '1';
|
||||
for i in 0 to operands'length-1 loop
|
||||
for j in 0 to operands'length-1 loop
|
||||
check <= '0';
|
||||
wait until rising_edge(clk) and busy = '0';
|
||||
din_hi <= operands(i);
|
||||
din_lo <= operands(j);
|
||||
start <= '1';
|
||||
wait until rising_edge(clk);
|
||||
start <= '0';
|
||||
hilo_sel <= '0';
|
||||
|
||||
-- Read result
|
||||
wait until rising_edge(clk) and busy = '0';
|
||||
wait until rising_edge(clk);
|
||||
md_result(31 downto 0) <= dout;
|
||||
wait until rising_edge(clk);
|
||||
hilo_sel <= '1';
|
||||
wait until rising_edge(clk);
|
||||
md_result(63 downto 32) <= dout;
|
||||
check <= '1';
|
||||
wait until rising_edge(clk);
|
||||
check <= '0';
|
||||
wait for 8*CLK_PERIOD;
|
||||
end loop;
|
||||
end loop;
|
||||
|
||||
mul_divn <= '1';
|
||||
s_un <= '0';
|
||||
for i in 0 to operands'length-1 loop
|
||||
for j in 0 to operands'length-1 loop
|
||||
check <= '0';
|
||||
wait until rising_edge(clk) and busy = '0';
|
||||
din_hi <= operands(i);
|
||||
din_lo <= operands(j);
|
||||
start <= '1';
|
||||
wait until rising_edge(clk);
|
||||
start <= '0';
|
||||
hilo_sel <= '0';
|
||||
|
||||
-- Read result
|
||||
wait until rising_edge(clk) and busy = '0';
|
||||
wait until rising_edge(clk);
|
||||
md_result(31 downto 0) <= dout;
|
||||
wait until rising_edge(clk);
|
||||
hilo_sel <= '1';
|
||||
wait until rising_edge(clk);
|
||||
md_result(63 downto 32) <= dout;
|
||||
check <= '1';
|
||||
wait until rising_edge(clk);
|
||||
check <= '0';
|
||||
wait for 8*CLK_PERIOD;
|
||||
end loop;
|
||||
end loop;
|
||||
|
||||
s_un <= '1';
|
||||
for i in 0 to operands'length-1 loop
|
||||
for j in 0 to operands'length-1 loop
|
||||
check <= '0';
|
||||
wait until rising_edge(clk) and busy = '0';
|
||||
din_hi <= operands(i);
|
||||
din_lo <= operands(j);
|
||||
start <= '1';
|
||||
wait until rising_edge(clk);
|
||||
start <= '0';
|
||||
hilo_sel <= '0';
|
||||
|
||||
-- Read result
|
||||
wait until rising_edge(clk) and busy = '0';
|
||||
wait until rising_edge(clk);
|
||||
md_result(31 downto 0) <= dout;
|
||||
wait until rising_edge(clk);
|
||||
hilo_sel <= '1';
|
||||
wait until rising_edge(clk);
|
||||
md_result(63 downto 32) <= dout;
|
||||
check <= '1';
|
||||
wait until rising_edge(clk);
|
||||
check <= '0';
|
||||
wait for 8*CLK_PERIOD;
|
||||
end loop;
|
||||
end loop;
|
||||
|
||||
wait;
|
||||
|
||||
end process;
|
||||
|
||||
END;
|
||||
@@ -0,0 +1,405 @@
|
||||
-------------------------------------------------------------------------
|
||||
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
|
||||
-- This file: Testbench for JCPU
|
||||
-- also writes 'opc.lst' for JASM-assembler
|
||||
--
|
||||
-- Copyright (C) 2007 J. Ahrensfeld
|
||||
--
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-- For questions and ideas, please contact the author at jens@jayfield.org
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
LIBRARY ieee;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
USE ieee.numeric_std.ALL;
|
||||
|
||||
library work;
|
||||
use work.mips_types.all;
|
||||
use work.mips_instr.all;
|
||||
use work.async_types.all;
|
||||
use work.async_defs.all;
|
||||
|
||||
ENTITY tb_mips_top IS
|
||||
END tb_mips_top;
|
||||
|
||||
ARCHITECTURE behavior OF tb_mips_top IS
|
||||
|
||||
constant CLK_PERIOD : time := 10 ns;
|
||||
constant SRAM_ADDR_WIDTH : integer := 14; -- bits
|
||||
constant FLASH_ADDR_WIDTH : integer := 14; -- bits
|
||||
|
||||
signal debug : unsigned(1 downto 0);
|
||||
|
||||
-- Master
|
||||
signal rst : STD_LOGIC := '1';
|
||||
signal clk : STD_LOGIC := '0';
|
||||
signal ACK_I : STD_LOGIC := '0';
|
||||
signal SRDY_I : STD_LOGIC := '0';
|
||||
signal ADDR_O : word_t;
|
||||
signal DAT_I : word_t := (others => '0');
|
||||
signal DAT_O : word_t;
|
||||
signal WE_O : STD_LOGIC;
|
||||
signal SEL_O : unsigned(3 downto 0);
|
||||
signal CYC_O : STD_LOGIC;
|
||||
signal STB_O : STD_LOGIC;
|
||||
signal MRDY_O : STD_LOGIC;
|
||||
signal INT : unsigned (5 downto 0) := (others => '0');
|
||||
|
||||
-- Slaves
|
||||
signal CYC_I_rom : std_logic;
|
||||
signal ACK_O_rom : std_logic;
|
||||
signal SRDY_O_rom : std_logic;
|
||||
signal DAT_O_rom : unsigned(31 downto 0);
|
||||
|
||||
signal CYC_I_flash : std_logic;
|
||||
signal ACK_O_flash : std_logic;
|
||||
signal SRDY_O_flash : std_logic;
|
||||
signal DAT_O_flash : unsigned(31 downto 0);
|
||||
|
||||
signal CYC_I_sram : std_logic;
|
||||
signal ACK_O_sram : std_logic;
|
||||
signal SRDY_O_sram : std_logic;
|
||||
signal DAT_O_sram : unsigned(31 downto 0);
|
||||
|
||||
signal CYC_I_gpio : std_logic;
|
||||
signal ACK_O_gpio : std_logic;
|
||||
signal SRDY_O_gpio : std_logic;
|
||||
signal DAT_O_gpio : unsigned(31 downto 0);
|
||||
|
||||
signal CYC_I_uart : std_logic;
|
||||
signal ACK_O_uart : std_logic;
|
||||
signal SRDY_O_uart : std_logic;
|
||||
signal DAT_O_uart : unsigned(31 downto 0);
|
||||
|
||||
signal flash_cs_n : std_logic;
|
||||
signal flash_oe_n : std_logic;
|
||||
signal sram_cs_n : std_logic;
|
||||
signal sram_wr_n : unsigned(3 downto 0);
|
||||
signal sram_oe_n : std_logic;
|
||||
signal sram_a : unsigned(SRAM_ADDR_WIDTH-1 downto 0);
|
||||
signal sram_d : unsigned(31 downto 0);
|
||||
signal flash_a : unsigned(FLASH_ADDR_WIDTH-1 downto 0);
|
||||
signal flash_d : unsigned(31 downto 0);
|
||||
|
||||
signal gpo0 : unsigned(31 downto 0);
|
||||
signal gpo1 : unsigned(31 downto 0);
|
||||
signal gpi0 : unsigned(31 downto 0) := (others => '0');
|
||||
signal gpi1 : unsigned(31 downto 0) := (others => '0');
|
||||
|
||||
signal int_uart_rx : std_logic;
|
||||
signal rx : std_logic := '1';
|
||||
signal tx : std_logic;
|
||||
|
||||
type mem_area_t is (mem_dead, mem_flash, mem_sram, mem_rom, mem_gpio, mem_uart);
|
||||
signal mem_area : mem_area_t;
|
||||
|
||||
type word_array_t is array (natural range <>) of word_t;
|
||||
signal sram_data : word_array_t(0 to 2**SRAM_ADDR_WIDTH-1);
|
||||
signal flash_data : word_array_t(0 to 2**FLASH_ADDR_WIDTH-1);
|
||||
|
||||
BEGIN
|
||||
|
||||
------------------------------------------------------------------
|
||||
CLK_GEN: process
|
||||
begin
|
||||
wait for CLK_PERIOD/2;
|
||||
clk <= not clk;
|
||||
end process;
|
||||
|
||||
------------------------------------------------------------------
|
||||
-- Memory mux
|
||||
------------------------------------------------------------------
|
||||
mem_mux:
|
||||
process(ADDR_O)
|
||||
begin
|
||||
mem_area <= mem_dead;
|
||||
if ADDR_O(31 downto 28) = X"0" then
|
||||
mem_area <= mem_flash;
|
||||
elsif ADDR_O(31 downto 28) = X"A" then
|
||||
if ADDR_O(27 downto 26) = "00" then
|
||||
if ADDR_O(18 downto 16) = "000" then
|
||||
mem_area <= mem_gpio;
|
||||
elsif ADDR_O(18 downto 16) = "001" then
|
||||
mem_area <= mem_uart;
|
||||
end if;
|
||||
elsif ADDR_O(27 downto 26) = "01" then
|
||||
mem_area <= mem_flash;
|
||||
end if;
|
||||
elsif (ADDR_O(31 downto 28) = X"B" and ADDR_O(15) = '0') then
|
||||
mem_area <= mem_rom;
|
||||
elsif (ADDR_O(31 downto 28) = X"8" or ADDR_O(30) = '1') then
|
||||
mem_area <= mem_sram;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
signal_mux:
|
||||
process(mem_area, CYC_O)
|
||||
begin
|
||||
|
||||
CYC_I_uart <= '0';
|
||||
CYC_I_gpio <= '0';
|
||||
CYC_I_flash <= '0';
|
||||
CYC_I_rom <= '0';
|
||||
CYC_I_sram <= '0';
|
||||
|
||||
case mem_area is
|
||||
|
||||
when mem_gpio =>
|
||||
CYC_I_gpio <= CYC_O;
|
||||
|
||||
when mem_uart =>
|
||||
CYC_I_uart <= CYC_O;
|
||||
|
||||
when mem_flash =>
|
||||
CYC_I_flash <= CYC_O;
|
||||
|
||||
when mem_rom =>
|
||||
CYC_I_rom <= CYC_O;
|
||||
|
||||
when mem_sram =>
|
||||
CYC_I_sram <= CYC_O;
|
||||
|
||||
when others => null;
|
||||
|
||||
end case;
|
||||
|
||||
end process;
|
||||
|
||||
SRDY_I <= SRDY_O_flash or SRDY_O_sram or SRDY_O_rom or SRDY_O_uart or SRDY_O_gpio;
|
||||
ACK_I <= ACK_O_flash or ACK_O_sram or ACK_O_rom or ACK_O_uart or ACK_O_gpio;
|
||||
DAT_I <= DAT_O_sram when CYC_I_sram = '1' else
|
||||
DAT_O_rom when CYC_I_rom = '1' else
|
||||
DAT_O_flash when CYC_I_flash = '1' else
|
||||
DAT_O_uart when CYC_I_uart = '1' else
|
||||
DAT_O_gpio when CYC_I_gpio = '1' else X"DEADBEEF";
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
uut: entity work.mips_top
|
||||
PORT MAP
|
||||
(
|
||||
debug => debug,
|
||||
RST_I => rst,
|
||||
CLK_I => clk,
|
||||
ACK_I => ACK_I,
|
||||
SRDY_I => SRDY_I,
|
||||
ADDR_O => ADDR_O,
|
||||
DAT_I => DAT_I,
|
||||
DAT_O => DAT_O,
|
||||
WE_O => WE_O,
|
||||
SEL_O => SEL_O,
|
||||
CYC_O => CYC_O,
|
||||
STB_O => STB_O,
|
||||
MRDY_O => MRDY_O,
|
||||
INT => INT
|
||||
);
|
||||
INT(1) <= int_uart_rx;
|
||||
|
||||
inst_rom : entity work.rom_wb
|
||||
PORT MAP
|
||||
(
|
||||
CLK_I => clk,
|
||||
RST_I => rst,
|
||||
CYC_I => CYC_I_rom,
|
||||
STB_I => STB_O,
|
||||
ACK_O => ACK_O_rom,
|
||||
MRDY_I => MRDY_O,
|
||||
SRDY_O => SRDY_O_rom,
|
||||
ADDR_I => ADDR_O,
|
||||
DAT_O => DAT_O_rom
|
||||
);
|
||||
|
||||
inst_gpio : entity work.gpio_wb
|
||||
PORT MAP
|
||||
(
|
||||
CLK_I => clk,
|
||||
RST_I => rst,
|
||||
CYC_I => CYC_I_gpio,
|
||||
STB_I => STB_O,
|
||||
SEL_I => SEL_O,
|
||||
WE_I => WE_O,
|
||||
ACK_O => ACK_O_gpio,
|
||||
SRDY_O => SRDY_O_gpio,
|
||||
MRDY_I => MRDY_O,
|
||||
ADDR_I => ADDR_O,
|
||||
DAT_I => DAT_O,
|
||||
DAT_O => DAT_O_gpio,
|
||||
|
||||
sys_gpo0 => gpo0,
|
||||
sys_gpo1 => gpo1,
|
||||
sys_gpi0 => gpi0,
|
||||
sys_gpi1 => gpi1
|
||||
);
|
||||
|
||||
inst_flash_port : entity work.async_port_wb
|
||||
GENERIC MAP
|
||||
(
|
||||
addr_width => FLASH_ADDR_WIDTH,
|
||||
data_width => 32,
|
||||
byte_sel_width => 1,
|
||||
async_timespec => ts_flash
|
||||
)
|
||||
PORT MAP
|
||||
(
|
||||
CLK_I => clk,
|
||||
RST_I => rst,
|
||||
CYC_I => CYC_I_flash,
|
||||
STB_I => STB_O,
|
||||
WE_I => WE_O,
|
||||
ACK_O => ACK_O_flash,
|
||||
SRDY_O => SRDY_O_flash,
|
||||
MRDY_I => MRDY_O,
|
||||
SEL_I => SEL_O,
|
||||
ADDR_I => ADDR_O,
|
||||
DAT_I => DAT_O,
|
||||
DAT_O => DAT_O_flash,
|
||||
async_a => flash_a,
|
||||
async_d => flash_d,
|
||||
async_cs => flash_cs_n,
|
||||
async_wr => open,
|
||||
async_rd => flash_oe_n,
|
||||
async_rst => open
|
||||
);
|
||||
|
||||
inst_sram_port : entity work.async_port_wb
|
||||
GENERIC MAP
|
||||
(
|
||||
addr_width => SRAM_ADDR_WIDTH,
|
||||
data_width => 32,
|
||||
byte_sel_width => 4,
|
||||
async_timespec => ts_sram
|
||||
)
|
||||
PORT MAP
|
||||
(
|
||||
CLK_I => clk,
|
||||
RST_I => rst,
|
||||
CYC_I => CYC_I_sram,
|
||||
STB_I => STB_O,
|
||||
WE_I => WE_O,
|
||||
ACK_O => ACK_O_sram,
|
||||
SRDY_O => SRDY_O_sram,
|
||||
MRDY_I => MRDY_O,
|
||||
SEL_I => SEL_O,
|
||||
ADDR_I => ADDR_O,
|
||||
DAT_I => DAT_O,
|
||||
DAT_O => DAT_O_sram,
|
||||
async_a => sram_a,
|
||||
async_d => sram_d,
|
||||
async_cs => sram_cs_n,
|
||||
async_wr => sram_wr_n,
|
||||
async_rd => sram_oe_n,
|
||||
async_rst => open
|
||||
);
|
||||
|
||||
inst_uart : entity work.uart_wb
|
||||
PORT MAP
|
||||
(
|
||||
CLK_I => clk,
|
||||
RST_I => rst,
|
||||
CYC_I => CYC_I_uart,
|
||||
STB_I => STB_O,
|
||||
SEL_I => SEL_O,
|
||||
WE_I => WE_O,
|
||||
ACK_O => ACK_O_uart,
|
||||
SRDY_O => SRDY_O_uart,
|
||||
MRDY_I => MRDY_O,
|
||||
ADDR_I => ADDR_O,
|
||||
DAT_I => DAT_O,
|
||||
DAT_O => DAT_O_uart,
|
||||
INT_RX_O => int_uart_rx,
|
||||
INT_TX_O => open,
|
||||
ser_rx => rx,
|
||||
ser_tx => tx
|
||||
);
|
||||
|
||||
------------------------------------------------------------------
|
||||
SRAM_READ:
|
||||
process(sram_a, sram_cs_n, sram_oe_n)
|
||||
begin
|
||||
sram_d <= (others => 'Z');
|
||||
if sram_oe_n = '0' then
|
||||
if sram_cs_n = '0' then
|
||||
sram_d <= sram_data(to_integer(sram_a(SRAM_ADDR_WIDTH-1 downto 2)));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
SRAM_WRITE:
|
||||
process(sram_a, sram_cs_n, sram_wr_n)
|
||||
begin
|
||||
if rising_edge(sram_wr_n(0)) then
|
||||
if sram_cs_n = '0' then
|
||||
sram_data(to_integer(sram_a(SRAM_ADDR_WIDTH-1 downto 2)))(7 downto 0) <= sram_d(7 downto 0);
|
||||
end if;
|
||||
end if;
|
||||
if rising_edge(sram_wr_n(1)) then
|
||||
if sram_cs_n = '0' then
|
||||
sram_data(to_integer(sram_a(SRAM_ADDR_WIDTH-1 downto 2)))(15 downto 8) <= sram_d(15 downto 8);
|
||||
end if;
|
||||
end if;
|
||||
if rising_edge(sram_wr_n(2)) then
|
||||
if sram_cs_n = '0' then
|
||||
sram_data(to_integer(sram_a(SRAM_ADDR_WIDTH-1 downto 2)))(23 downto 16) <= sram_d(23 downto 16);
|
||||
end if;
|
||||
end if;
|
||||
if rising_edge(sram_wr_n(3)) then
|
||||
if sram_cs_n = '0' then
|
||||
sram_data(to_integer(sram_a(SRAM_ADDR_WIDTH-1 downto 2)))(31 downto 24) <= sram_d(31 downto 24);
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
------------------------------------------------------------------
|
||||
FLASH_READ:
|
||||
process(rst, flash_cs_n, flash_oe_n, flash_a)
|
||||
type file_t is file of integer;
|
||||
file load_flash : file_t open read_mode is "hello.flash.bin";
|
||||
variable instr : integer;
|
||||
variable index : natural;
|
||||
variable temp : signed(31 downto 0);
|
||||
begin
|
||||
if rst = '1' then
|
||||
index := 0;
|
||||
while not endfile(load_flash) loop
|
||||
read(load_flash, instr);
|
||||
temp := to_signed(instr, word_t'length);
|
||||
flash_data(index) <= unsigned(temp);
|
||||
index := index + 1;
|
||||
end loop;
|
||||
else
|
||||
flash_d <= (others => 'Z') after 10 ns;
|
||||
if flash_oe_n = '0' and flash_cs_n = '0' then
|
||||
index := to_integer(flash_a(FLASH_ADDR_WIDTH-1 downto 2));
|
||||
flash_d <= flash_data(index) after 10 ns;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
------------------------------------------------------------------
|
||||
STIMULUS: process
|
||||
|
||||
begin
|
||||
|
||||
|
||||
wait for 3*CLK_PERIOD;
|
||||
wait until rising_edge(clk);
|
||||
rst <= '0';
|
||||
|
||||
wait;
|
||||
|
||||
end process;
|
||||
|
||||
END;
|
||||
@@ -0,0 +1,20 @@
|
||||
vhdl work "../../src/core/mips_types.vhd"
|
||||
vhdl work "../../../../misc/dpram_2w2r.vhd"
|
||||
vhdl work "../../../../misc/dpram_1w1r_dist.vhd"
|
||||
vhdl work "../../../../misc/dpram_1w1r.vhd"
|
||||
vhdl work "../../../../FIFO/src/sync_fifo_ctrl.vhd"
|
||||
vhdl work "../../../../FIFO/src/fifo_ctrl_pkg.vhd"
|
||||
vhdl work "../../src/core/mips_instr.vhd"
|
||||
vhdl work "../../../../FIFO/src/fifo_sync_dist.vhd"
|
||||
vhdl work "../../src/core/mips_shifter.vhd"
|
||||
vhdl work "../../src/core/mips_reg.vhd"
|
||||
vhdl work "../../src/core/mips_muldiv.vhd"
|
||||
vhdl work "../../src/core/mips_idecode_rom.vhd"
|
||||
vhdl work "../../src/core/mips_icache.vhd"
|
||||
vhdl work "../../src/core/mips_dcache.vhd"
|
||||
vhdl work "../../src/core/mips_cop.vhd"
|
||||
vhdl work "../../src/core/mips_bcu.vhd"
|
||||
vhdl work "../../src/core/mips_alu.vhd"
|
||||
vhdl work "../../src/core/mips_pipeline.vhd"
|
||||
vhdl work "../../src/core/mips_biu.vhd"
|
||||
vhdl work "../../src/core/mips_top.vhd"
|
||||
@@ -0,0 +1,20 @@
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_types.vhd"
|
||||
vhdl work "W:\vhdl\lib\misc\dpram_2w2r.vhd"
|
||||
vhdl work "W:\vhdl\lib\misc\dpram_1w1r_dist.vhd"
|
||||
vhdl work "W:\vhdl\lib\misc\dpram_1w1r.vhd"
|
||||
vhdl work "W:\vhdl\lib\FIFO\src\sync_fifo_ctrl.vhd"
|
||||
vhdl work "W:\vhdl\lib\FIFO\src\fifo_ctrl_pkg.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_instr.vhd"
|
||||
vhdl work "W:\vhdl\lib\FIFO\src\fifo_sync_dist.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_shifter.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_reg.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_muldiv.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_idecode_rom.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_icache.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_dcache.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_cop.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_bcu.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_alu.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_pipeline.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_biu.vhd"
|
||||
vhdl work "W:\vhdl\lib\CPUs\MIPS\src\core\mips_top.vhd"
|
||||
@@ -0,0 +1,5 @@
|
||||
2008-10-26
|
||||
- Optimierung: MUL32x32 primitive für Virtex-4
|
||||
- External COP 1..3 interface
|
||||
- FPU (COP1)
|
||||
- MMU
|
||||
@@ -0,0 +1,17 @@
|
||||
CFLAGS=-O2
|
||||
|
||||
CC=gcc
|
||||
|
||||
all: romgen ramgen flashgen
|
||||
|
||||
romgen: ./src/romgen.c
|
||||
$(CC) $(CFLAGS) ./src/romgen.c -o ./romgen
|
||||
|
||||
ramgen: ./src/ramgen.c
|
||||
$(CC) $(CFLAGS) ./src/ramgen.c -o ./ramgen
|
||||
|
||||
flashgen: ./src/flashgen.c
|
||||
$(CC) $(CFLAGS) ./src/flashgen.c -o ./flashgen
|
||||
|
||||
clean:
|
||||
rm -rf romgen* ramgen* flashgen*
|
||||
@@ -0,0 +1,117 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define INT8 char
|
||||
#define INT16 short
|
||||
#define INT32 long
|
||||
#define UINT8 unsigned char
|
||||
#define UINT16 unsigned short
|
||||
#define UINT32 unsigned long
|
||||
#define INT int
|
||||
#define UINT unsigned int
|
||||
#define FLOAT32 float
|
||||
#define FLOAT64 double
|
||||
|
||||
#define SDRAM_BASE 0x40000000
|
||||
#define FLASH_OFFSET 0x00000000
|
||||
|
||||
// --------------------------------------------------------------
|
||||
typedef struct _sflash_img_hdr_t
|
||||
{
|
||||
UINT8 magic[4];
|
||||
UINT32 target_addr;
|
||||
UINT32 img_offset;
|
||||
UINT32 img_size;
|
||||
UINT32 hdr_next;
|
||||
UINT8 img_name[128];
|
||||
UINT8 res[108];
|
||||
|
||||
} flash_img_hdr_t;
|
||||
|
||||
// --------------------------------------------------------------
|
||||
void basename(char *pSrc, char *pDst)
|
||||
{
|
||||
int i, size;
|
||||
|
||||
size = strlen(pSrc);
|
||||
|
||||
while(pSrc[size] != '.')
|
||||
size--;
|
||||
|
||||
for (i=0; i < size; i++)
|
||||
pDst[i] = pSrc[i];
|
||||
|
||||
pDst[i] = 0;
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *pFilenameIn;
|
||||
char name_flash[1024];
|
||||
char name_prj[1024];
|
||||
char *pBuf;
|
||||
flash_img_hdr_t img_hdr = {0};
|
||||
|
||||
FILE *pFile;
|
||||
int filesize;
|
||||
long start, end;
|
||||
int i;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: flashgen <input file>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pFilenameIn = argv[1];
|
||||
pFile = fopen(pFilenameIn, "rb");
|
||||
if (!pFile)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameIn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
basename(pFilenameIn, name_prj);
|
||||
sprintf(name_flash, "%s.flash.bin", name_prj);
|
||||
|
||||
// determine filesize
|
||||
fseek(pFile, 0, SEEK_SET);
|
||||
start = ftell(pFile);
|
||||
fseek(pFile, 0, SEEK_END);
|
||||
end = ftell(pFile);
|
||||
fseek(pFile, 0, SEEK_SET);
|
||||
filesize = (end-start);
|
||||
|
||||
pBuf = (char*)malloc(filesize);
|
||||
fread(pBuf, 1, filesize, pFile);
|
||||
|
||||
fclose(pFile);
|
||||
|
||||
pFile = fopen(name_flash, "wb");
|
||||
if (!pFile)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", name_flash);
|
||||
return 1;
|
||||
}
|
||||
|
||||
img_hdr.magic[0] = 'J';
|
||||
img_hdr.magic[1] = 'F';
|
||||
img_hdr.magic[2] = 'I';
|
||||
img_hdr.magic[3] = '1';
|
||||
img_hdr.target_addr = SDRAM_BASE;
|
||||
img_hdr.img_size = filesize;
|
||||
img_hdr.img_offset = FLASH_OFFSET + sizeof(flash_img_hdr_t);
|
||||
img_hdr.hdr_next = FLASH_OFFSET;
|
||||
|
||||
fwrite(&img_hdr, sizeof(flash_img_hdr_t), 1, pFile);
|
||||
fwrite(pBuf, 1, filesize, pFile);
|
||||
|
||||
fclose(pFile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define ARCH_NAME "data"
|
||||
#define ENT_NAME "ram"
|
||||
#define JTAG_ADDR_WIDTH 16
|
||||
|
||||
// --------------------------------------------------------------
|
||||
void basename(char *pSrc, char *pDst)
|
||||
{
|
||||
int i, size;
|
||||
|
||||
size = strlen(pSrc);
|
||||
|
||||
while(pSrc[size] != '.')
|
||||
size--;
|
||||
|
||||
for (i=0; i < size; i++)
|
||||
pDst[i] = pSrc[i];
|
||||
|
||||
pDst[i] = 0;
|
||||
|
||||
}
|
||||
|
||||
int SaveRAM(char *pFilenameIn, char *pFilenameOut, char *pArchName, char *pEntName, int nbits_addr, int nbits_data)
|
||||
{
|
||||
FILE *pFileIn, *pFileOut;
|
||||
long start, end;
|
||||
int i, word, filesize, romsize;
|
||||
|
||||
pFileIn = fopen(pFilenameIn, "rb");
|
||||
if (!pFileIn)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameIn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pFileOut = fopen(pFilenameOut, "wb");
|
||||
if (!pFileOut)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameOut);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
start = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_END);
|
||||
end = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
|
||||
filesize = (end-start);
|
||||
romsize = (int)pow(2, nbits_addr+2);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Header
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "LIBRARY IEEE;\n");
|
||||
fprintf(pFileOut, "USE IEEE.STD_LOGIC_1164.ALL;\n");
|
||||
fprintf(pFileOut, "USE IEEE.NUMERIC_STD.ALL;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "ENTITY %s IS\n", ENT_NAME);
|
||||
fprintf(pFileOut, "\tPort\n");
|
||||
fprintf(pFileOut, "\t(\n");
|
||||
fprintf(pFileOut, "\t\tclk\t\t: in STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\t\tce\t\t: in STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\t\twe\t\t: in unsigned(%d downto 0);\n", nbits_data/8-1);
|
||||
fprintf(pFileOut, "\t\taddr\t\t: in unsigned(%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\t\tdin\t\t: in unsigned(%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\t\tdout\t\t: out unsigned(%d downto 0)\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\t);\n");
|
||||
fprintf(pFileOut, "END %s;\n", ENT_NAME);
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
|
||||
fprintf(pFileOut, "ARCHITECTURE %s OF %s IS\n", ARCH_NAME, ENT_NAME);
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "\tconstant depth : natural := %d;\n", romsize/4);
|
||||
fprintf(pFileOut, "\tsubtype word_t is unsigned(%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\ttype word_array_t is array (0 to %d) of word_t;\n", romsize/4-1);
|
||||
|
||||
fprintf(pFileOut, "\tsignal sram : word_array_t :=\n");
|
||||
fprintf(pFileOut, "\t(\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// ROM part
|
||||
// -------------------------------------------------------------------------
|
||||
for (i=0; i < filesize; i += sizeof(int))
|
||||
{
|
||||
fread(&word, 1, sizeof(int), pFileIn);
|
||||
fprintf(pFileOut, "\t\tX\"%8.8X\"", word);
|
||||
if (i < (romsize-sizeof(int)))
|
||||
fprintf(pFileOut, ", -- %8.8X\n", i);
|
||||
else
|
||||
fprintf(pFileOut, " -- %8.8X\n", i);
|
||||
}
|
||||
word = 0;
|
||||
for (; i < romsize; i += sizeof(int))
|
||||
{
|
||||
fprintf(pFileOut, "\t\tX\"%8.8X\"", word);
|
||||
if (i < (romsize-sizeof(int)))
|
||||
fprintf(pFileOut, ", -- %8.8X\n", i);
|
||||
else
|
||||
fprintf(pFileOut, " -- %8.8X\n", i);
|
||||
}
|
||||
fprintf(pFileOut, "\t);\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Trailer
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "begin\n", ARCH_NAME);
|
||||
fprintf(pFileOut, "\n");
|
||||
fprintf(pFileOut, "RAM_RW:\n", ARCH_NAME);
|
||||
fprintf(pFileOut, "\tprocess(clk)\n");
|
||||
fprintf(pFileOut, "\tvariable index : natural range 0 to depth-1;\n");
|
||||
fprintf(pFileOut, "\tbegin\n");
|
||||
fprintf(pFileOut, "\t\tif rising_edge(clk) and ce = '1' then\n");
|
||||
fprintf(pFileOut, "\t\t\tindex := to_integer(addr(%d downto 2));\n", nbits_addr+1);
|
||||
fprintf(pFileOut, "\t\t\tif we(0) = '1' then\n");
|
||||
fprintf(pFileOut, "\t\t\t\tsram(index)(7 downto 0)\t\t<= din(7 downto 0);\n");
|
||||
fprintf(pFileOut, "\t\t\tend if;\n");
|
||||
fprintf(pFileOut, "\t\t\tif we(1) = '1' then\n");
|
||||
fprintf(pFileOut, "\t\t\t\tsram(index)(15 downto 8)\t<= din(15 downto 8);\n");
|
||||
fprintf(pFileOut, "\t\t\tend if;\n");
|
||||
fprintf(pFileOut, "\t\t\tif we(2) = '1' then\n");
|
||||
fprintf(pFileOut, "\t\t\t\tsram(index)(23 downto 16)\t<= din(23 downto 16);\n");
|
||||
fprintf(pFileOut, "\t\t\tend if;\n");
|
||||
fprintf(pFileOut, "\t\t\tif we(3) = '1' then\n");
|
||||
fprintf(pFileOut, "\t\t\t\tsram(index)(31 downto 24)\t\t<= din(31 downto 24);\n");
|
||||
fprintf(pFileOut, "\t\t\tend if;\n");
|
||||
fprintf(pFileOut, "\t\t\tdout <= sram(index);\n");
|
||||
fprintf(pFileOut, "\t\tend if;\n");
|
||||
fprintf(pFileOut, "\tend process;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
fprintf(pFileOut, "end %s;\n", ARCH_NAME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SaveRAM_V4LD(char *pFilenameIn, char *pFilenameOut, char *pArchName, char *pEntName, int nbits_addr, int nbits_data)
|
||||
{
|
||||
FILE *pFileIn, *pFileOut;
|
||||
long start, end;
|
||||
int i, word, filesize, romsize;
|
||||
|
||||
char tpl[] = {"--------------------------------------------------------------------------\n-- Virtex-4: JTAG Loader\n--------------------------------------------------------------------------\n\ti00_BUFG : BUFG\n\tport map\n\t(\n\t\tO => bs_clk1,\n I => bs_clk0\n\t);\n\t\n\ti01_BUFG : BUFG\n\tport map\n\t(\n\t\tO => bs_update1,\n I => bs_update0\n\t);\n\n\tBSCAN_VIRTEX4_inst1 : BSCAN_VIRTEX4 \n\tgeneric map\n\t(\n\t\tJTAG_CHAIN => 1 -- Value to set BSCAN site of device. Possible values: (1,2,3 or 4)\n\t)\n\tport map \n\t(\n\t\tCAPTURE => bs_capture, -- CAPTURE output from TAP controller\n\t\tDRCK => bs_clk0, -- Data register output for USER functions\n\t\tRESET => bs_rst, -- Reset output from TAP controller\n\t\tSEL => bs_sel, -- USER active output\n\t\tSHIFT => bs_shift, -- SHIFT output from TAP controller\n\t\tTDI => bs_tdi, -- TDI output from TAP controller\n\t\tUPDATE => bs_update0, -- UPDATE output from TAP controller\n\t\tTDO => bs_tdo -- Data input for USER function\n\t);\n\n\tjtag_ld_addr <= user_regi(user_regi'left downto jtag_ld_dout'length);\n\tjtag_ld_din <= user_regi(jtag_ld_dout'length-1 downto 0);\n\tjtag_ld_clk <= bs_update1;\n\tjtag_ld_we <= bs_sel;\n\t\nsipo:\n\tprocess (bs_rst, bs_clk1, bs_tdi, bs_shift)\n\tbegin\n\t\tif bs_rst = '1' then\n\t\t\tuser_regi <= (others => '0');\n\t\telsif rising_edge(bs_clk1) then\n\t\t\tif bs_shift = '1' then\n\t\t\t\tuser_regi <= bs_tdi & user_regi(user_regi'left downto 1);\n\t\t\tend if;\n\t\tend if;\n\tend process;\t\n\npiso:\n\tprocess (bs_rst, bs_clk1, bs_shift, user_rego)\n\tbegin\n\t\tbs_tdo <= user_rego(0);\n\t\tif bs_rst = '1' then\n\t\t\tuser_rego <= (others => '0');\n\t\telsif rising_edge(bs_clk1) then\n\t\t\tif bs_shift = '1' then\n\t\t\t\tuser_rego <= user_rego(0) & user_rego(user_rego'left downto 1);\n\t\t\telse\n\t\t\t\tuser_rego <= (user_rego'left downto jtag_ld_dout'length => '0') & jtag_ld_dout;\t\n\t\n\t\t\tend if;\n\t\tend if;\n\tend process;\n\n"};
|
||||
|
||||
pFileIn = fopen(pFilenameIn, "rb");
|
||||
if (!pFileIn)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameIn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pFileOut = fopen(pFilenameOut, "wb");
|
||||
if (!pFileOut)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameOut);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
start = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_END);
|
||||
end = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
|
||||
filesize = (end-start);
|
||||
romsize = (int)pow(2, nbits_addr+2);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Header
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "LIBRARY IEEE;\n");
|
||||
fprintf(pFileOut, "USE IEEE.STD_LOGIC_1164.ALL;\n");
|
||||
fprintf(pFileOut, "USE IEEE.NUMERIC_STD.ALL;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "library UNISIM;\n");
|
||||
fprintf(pFileOut, "use UNISIM.VComponents.all;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "ENTITY %s IS\n", ENT_NAME);
|
||||
fprintf(pFileOut, "\tPort\n");
|
||||
fprintf(pFileOut, "\t(\n");
|
||||
fprintf(pFileOut, "\t\tclk\t\t: in STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\t\tce\t\t: in STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\t\taddr\t\t: in unsigned(%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\t\tdout\t\t: out unsigned(%d downto 0)\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\t);\n");
|
||||
fprintf(pFileOut, "END %s;\n", ENT_NAME);
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
|
||||
fprintf(pFileOut, "ARCHITECTURE %s OF %s IS\n", ARCH_NAME, ENT_NAME);
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "\tsubtype word_t is unsigned(%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\ttype word_array_t is array (0 to %d) of word_t;\n", romsize/4-1);
|
||||
|
||||
fprintf(pFileOut, "\tsignal jtag_ld_clk\t\t: STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\tsignal jtag_ld_we\t\t: STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\tsignal jtag_ld_addr\t\t: unsigned (%d downto 0);\n", JTAG_ADDR_WIDTH-1);
|
||||
fprintf(pFileOut, "\tsignal jtag_ld_dout\t\t: unsigned (%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\tsignal jtag_ld_din\t\t: unsigned (%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\tsignal bs_rst, bs_sel, bs_shift, bs_tdi, bs_tdo : std_logic;\n");
|
||||
fprintf(pFileOut, "\tsignal bs_capture, bs_clk0, bs_clk1, bs_update0, bs_update1 : std_logic;\n");
|
||||
fprintf(pFileOut, "\tsignal user_regi, user_rego : unsigned (%d downto 0);\n", 31 + JTAG_ADDR_WIDTH);
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "\tsignal word_array : word_array_t :=\n");
|
||||
fprintf(pFileOut, "\t(\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// ROM part
|
||||
// -------------------------------------------------------------------------
|
||||
for (i=0; i < filesize; i += sizeof(int))
|
||||
{
|
||||
fread(&word, 1, sizeof(int), pFileIn);
|
||||
fprintf(pFileOut, "\t\tX\"%8.8X\"", word);
|
||||
if (i < (romsize-sizeof(int)))
|
||||
fprintf(pFileOut, ", -- %8.8X\n", i);
|
||||
else
|
||||
fprintf(pFileOut, " -- %8.8X\n", i);
|
||||
}
|
||||
word = 0;
|
||||
for (; i < romsize; i += sizeof(int))
|
||||
{
|
||||
fprintf(pFileOut, "\t\tX\"%8.8X\"", word);
|
||||
if (i < (romsize-sizeof(int)))
|
||||
fprintf(pFileOut, ", -- %8.8X\n", i);
|
||||
else
|
||||
fprintf(pFileOut, " -- %8.8X\n", i);
|
||||
}
|
||||
fprintf(pFileOut, "\t);\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "begin\n", ARCH_NAME);
|
||||
|
||||
fprintf(pFileOut, "\n");
|
||||
fprintf(pFileOut, "PROM_READ:\n", ARCH_NAME);
|
||||
fprintf(pFileOut, "\tprocess(clk)\n");
|
||||
fprintf(pFileOut, "\tbegin\n");
|
||||
fprintf(pFileOut, "\t\tif rising_edge(clk) and ce = '1' then\n");
|
||||
fprintf(pFileOut, "\t\t\tdout <= word_array(to_integer(addr(%d downto 2)));\n", nbits_addr+1);
|
||||
fprintf(pFileOut, "\t\tend if;\n");
|
||||
fprintf(pFileOut, "\tend process;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Trailer
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "\n");
|
||||
fputs(tpl, pFileOut);
|
||||
|
||||
fprintf(pFileOut, "PROM_WRITE:\n", ARCH_NAME);
|
||||
fprintf(pFileOut, "\tprocess(jtag_ld_clk, jtag_ld_we)\n");
|
||||
fprintf(pFileOut, "\tbegin\n");
|
||||
fprintf(pFileOut, "\t\tif rising_edge(jtag_ld_clk) then\n");
|
||||
fprintf(pFileOut, "\t\t\tif jtag_ld_we = '1' then\n");
|
||||
fprintf(pFileOut, "\t\t\t\tword_array(to_integer(jtag_ld_addr(%d downto 0))) <= jtag_ld_din;\n", nbits_addr-1);
|
||||
fprintf(pFileOut, "\t\t\telse\n");
|
||||
fprintf(pFileOut, "\t\t\t\tjtag_ld_dout <= word_array(to_integer(jtag_ld_addr(%d downto 0)));\n", nbits_addr-1);
|
||||
fprintf(pFileOut, "\t\t\tend if;\n");
|
||||
fprintf(pFileOut, "\t\tend if;\n");
|
||||
fprintf(pFileOut, "\tend process;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "end %s;\n", ARCH_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SaveRAM_TCL(char *pFilenameIn, char *pFilenameOut, char *pArchName, char *pEntName, int nbits_addr, int nbits_data)
|
||||
{
|
||||
FILE *pFileIn, *pFileOut;
|
||||
long start, end;
|
||||
int i, word, word_addr, filesize, romsize;
|
||||
char binstr_addr[33];
|
||||
char binstr_data[33];
|
||||
|
||||
char tpl[] = {"# ---------------------------------------------------------------------\n# For Chipscope 9.1\n# ---------------------------------------------------------------------\n# Source JTAG/TCL frame work\ncd $env(CHIPSCOPE)\\\\bin\\\\nt\nsource csejtag.tcl\n\nnamespace import ::chipscope::*\n\n# Platform USB Cable\nset PLATFORM_USB_CABLE_ARGS [list \"port=USB2\" \"frequency=6000000\"]\n# frequency=\"24000000 | 12000000 | 6000000 | 3000000 | 1500000 | 750000\"\n\n# Create session\nset handle [::chipscope::csejtag_session create 0]\n\n# Open JTAG and lock\nset open_result [::chipscope::csejtag_target open $handle $CSEJTAG_TARGET_PLATFORMUSB 0 $PLATFORM_USB_CABLE_ARGS]\nset lock_result [::chipscope::csejtag_target lock $handle 1000]\n\nset devlist [::chipscope::csejtag_tap autodetect_chain $handle $CSEJTAG_SCAN_DEFAULT]\n\n# Get Device ID\nset devtype \"Virtex-4SX\"\nset devid 2\nset irlength [::chipscope::csejtag_tap get_irlength $handle $devid]\nset idcode [::chipscope::csejtag_tap get_device_idcode $handle $devid]\n\nset CSE_OP $CSEJTAG_SHIFT_READWRITE\nset CSE_ES $CSEJTAG_RUN_TEST_IDLE\n\n# Write Program\n"};
|
||||
|
||||
pFileIn = fopen(pFilenameIn, "rb");
|
||||
if (!pFileIn)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameIn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pFileOut = fopen(pFilenameOut, "wb");
|
||||
if (!pFileOut)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameOut);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
start = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_END);
|
||||
end = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
|
||||
filesize = (end-start);
|
||||
romsize = (int)pow(2, nbits_addr+2);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Header
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
fputs(tpl, pFileOut);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// ROM part
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "# Assembled from %s\n", pFilenameIn);
|
||||
fprintf(pFileOut, "# ---------------------------------------------------------------\n");
|
||||
fprintf(pFileOut, "# Shift the USER2 Instruction (b1111000011) into the Instruction Register of FPGA\n");
|
||||
fprintf(pFileOut, "# User 2\n");
|
||||
fprintf(pFileOut, "set result [::chipscope::csejtag_tap shift_device_ir $handle $devid $CSE_OP $CSE_ES 0 $irlength \"3C3\"]\n\n");
|
||||
|
||||
word_addr = 0;
|
||||
for (i=0; i < filesize; i += sizeof(int))
|
||||
{
|
||||
fread(&word, 1, sizeof(int), pFileIn);
|
||||
fprintf(pFileOut, "::chipscope::csejtag_tap shift_device_dr $handle $devid $CSE_OP $CSE_ES 0 %d \"%4.4X%8.8X\"\n", nbits_data + JTAG_ADDR_WIDTH, word_addr, word);
|
||||
word_addr++;
|
||||
}
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Trailer
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "::chipscope::csejtag_target unlock $handle\n");
|
||||
fprintf(pFileOut, "::chipscope::csejtag_target close $handle\n");
|
||||
fprintf(pFileOut, "::chipscope::csejtag_session destroy $handle\n");
|
||||
fprintf(pFileOut, "exit\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *pFilenameIn;
|
||||
char name_prj[1024];
|
||||
char name_rom_tcl[1024];
|
||||
char name_rom[1024];
|
||||
char name_rom_v4ld[1024];
|
||||
|
||||
FILE *pFileIn;
|
||||
int filesize, romsize, nbits_addr, nbits_data;
|
||||
long start, end;
|
||||
int word, i;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: ramgen <input file> <num. word address bits>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pFilenameIn = argv[1];
|
||||
if (argc == 3)
|
||||
nbits_addr = atoi(argv[2]);
|
||||
|
||||
|
||||
basename(pFilenameIn, name_prj);
|
||||
sprintf(name_rom, "%s.vhd", name_prj);
|
||||
sprintf(name_rom_v4ld, "%s_ld.vhd", name_prj);
|
||||
sprintf(name_rom_tcl, "%s.tcl", name_prj);
|
||||
|
||||
SaveRAM(pFilenameIn, name_rom, ARCH_NAME, ENT_NAME, nbits_addr, 32);
|
||||
// SaveROM_V4LD(pFilenameIn, name_rom_v4ld, ARCH_NAME, ENT_NAME, nbits_addr, 32);
|
||||
SaveRAM_TCL(pFilenameIn, name_rom_tcl, ARCH_NAME, ENT_NAME, nbits_addr, 32);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define ARCH_NAME "data"
|
||||
#define ENT_NAME "rom"
|
||||
#define JTAG_ADDR_WIDTH 16
|
||||
|
||||
// --------------------------------------------------------------
|
||||
void basename(char *pSrc, char *pDst)
|
||||
{
|
||||
int i, size;
|
||||
|
||||
size = strlen(pSrc);
|
||||
|
||||
while(pSrc[size] != '.')
|
||||
size--;
|
||||
|
||||
for (i=0; i < size; i++)
|
||||
pDst[i] = pSrc[i];
|
||||
|
||||
pDst[i] = 0;
|
||||
|
||||
}
|
||||
|
||||
int SaveROM(char *pFilenameIn, char *pFilenameOut, char *pArchName, char *pEntName, int nbits_addr, int nbits_data)
|
||||
{
|
||||
FILE *pFileIn, *pFileOut;
|
||||
long start, end;
|
||||
int i, word, filesize, romsize;
|
||||
|
||||
pFileIn = fopen(pFilenameIn, "rb");
|
||||
if (!pFileIn)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameIn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pFileOut = fopen(pFilenameOut, "wb");
|
||||
if (!pFileOut)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameOut);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
start = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_END);
|
||||
end = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
|
||||
filesize = (end-start);
|
||||
romsize = (int)pow(2, nbits_addr+2);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Header
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "LIBRARY IEEE;\n");
|
||||
fprintf(pFileOut, "USE IEEE.STD_LOGIC_1164.ALL;\n");
|
||||
fprintf(pFileOut, "USE IEEE.NUMERIC_STD.ALL;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "ENTITY %s IS\n", ENT_NAME);
|
||||
fprintf(pFileOut, "\tPort\n");
|
||||
fprintf(pFileOut, "\t(\n");
|
||||
fprintf(pFileOut, "\t\tclk\t\t: in STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\t\tce\t\t: in STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\t\taddr\t\t: in unsigned(%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\t\tdout\t\t: out unsigned(%d downto 0)\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\t);\n");
|
||||
fprintf(pFileOut, "END %s;\n", ENT_NAME);
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
|
||||
fprintf(pFileOut, "ARCHITECTURE %s OF %s IS\n", ARCH_NAME, ENT_NAME);
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "\tsubtype word_t is unsigned(%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\ttype word_array_t is array (0 to %d) of word_t;\n", romsize/4-1);
|
||||
|
||||
fprintf(pFileOut, "\tconstant word_array : word_array_t :=\n");
|
||||
fprintf(pFileOut, "\t(\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// ROM part
|
||||
// -------------------------------------------------------------------------
|
||||
for (i=0; i < filesize; i += sizeof(int))
|
||||
{
|
||||
fread(&word, 1, sizeof(int), pFileIn);
|
||||
fprintf(pFileOut, "\t\tX\"%8.8X\"", word);
|
||||
if (i < (romsize-sizeof(int)))
|
||||
fprintf(pFileOut, ", -- %8.8X\n", i);
|
||||
else
|
||||
fprintf(pFileOut, " -- %8.8X\n", i);
|
||||
}
|
||||
word = 0;
|
||||
for (; i < romsize; i += sizeof(int))
|
||||
{
|
||||
fprintf(pFileOut, "\t\tX\"%8.8X\"", word);
|
||||
if (i < (romsize-sizeof(int)))
|
||||
fprintf(pFileOut, ", -- %8.8X\n", i);
|
||||
else
|
||||
fprintf(pFileOut, " -- %8.8X\n", i);
|
||||
}
|
||||
fprintf(pFileOut, "\t);\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Trailer
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "begin\n", ARCH_NAME);
|
||||
fprintf(pFileOut, "\n");
|
||||
fprintf(pFileOut, "PROM_READ:\n", ARCH_NAME);
|
||||
fprintf(pFileOut, "\tprocess(clk)\n");
|
||||
fprintf(pFileOut, "\tbegin\n");
|
||||
fprintf(pFileOut, "\t\tif rising_edge(clk) and ce = '1' then\n");
|
||||
fprintf(pFileOut, "\t\t\tdout <= word_array(to_integer(addr(%d downto 2)));\n", nbits_addr+1);
|
||||
fprintf(pFileOut, "\t\tend if;\n");
|
||||
fprintf(pFileOut, "\tend process;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
fprintf(pFileOut, "end %s;\n", ARCH_NAME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SaveROM_V4LD(char *pFilenameIn, char *pFilenameOut, char *pArchName, char *pEntName, int nbits_addr, int nbits_data)
|
||||
{
|
||||
FILE *pFileIn, *pFileOut;
|
||||
long start, end;
|
||||
int i, word, filesize, romsize;
|
||||
|
||||
char tpl[] = {"--------------------------------------------------------------------------\n-- Virtex-4: JTAG Loader\n--------------------------------------------------------------------------\n\ti00_BUFG : BUFG\n\tport map\n\t(\n\t\tO => bs_clk1,\n I => bs_clk0\n\t);\n\t\n\ti01_BUFG : BUFG\n\tport map\n\t(\n\t\tO => bs_update1,\n I => bs_update0\n\t);\n\n\tBSCAN_VIRTEX4_inst1 : BSCAN_VIRTEX4 \n\tgeneric map\n\t(\n\t\tJTAG_CHAIN => 1 -- Value to set BSCAN site of device. Possible values: (1,2,3 or 4)\n\t)\n\tport map \n\t(\n\t\tCAPTURE => bs_capture, -- CAPTURE output from TAP controller\n\t\tDRCK => bs_clk0, -- Data register output for USER functions\n\t\tRESET => bs_rst, -- Reset output from TAP controller\n\t\tSEL => bs_sel, -- USER active output\n\t\tSHIFT => bs_shift, -- SHIFT output from TAP controller\n\t\tTDI => bs_tdi, -- TDI output from TAP controller\n\t\tUPDATE => bs_update0, -- UPDATE output from TAP controller\n\t\tTDO => bs_tdo -- Data input for USER function\n\t);\n\n\tjtag_ld_addr <= user_regi(user_regi'left downto jtag_ld_dout'length);\n\tjtag_ld_din <= user_regi(jtag_ld_dout'length-1 downto 0);\n\tjtag_ld_clk <= bs_update1;\n\tjtag_ld_we <= bs_sel;\n\t\nsipo:\n\tprocess (bs_rst, bs_clk1, bs_tdi, bs_shift)\n\tbegin\n\t\tif bs_rst = '1' then\n\t\t\tuser_regi <= (others => '0');\n\t\telsif rising_edge(bs_clk1) then\n\t\t\tif bs_shift = '1' then\n\t\t\t\tuser_regi <= bs_tdi & user_regi(user_regi'left downto 1);\n\t\t\tend if;\n\t\tend if;\n\tend process;\t\n\npiso:\n\tprocess (bs_rst, bs_clk1, bs_shift, user_rego)\n\tbegin\n\t\tbs_tdo <= user_rego(0);\n\t\tif bs_rst = '1' then\n\t\t\tuser_rego <= (others => '0');\n\t\telsif rising_edge(bs_clk1) then\n\t\t\tif bs_shift = '1' then\n\t\t\t\tuser_rego <= user_rego(0) & user_rego(user_rego'left downto 1);\n\t\t\telse\n\t\t\t\tuser_rego <= (user_rego'left downto jtag_ld_dout'length => '0') & jtag_ld_dout;\t\n\t\n\t\t\tend if;\n\t\tend if;\n\tend process;\n\n"};
|
||||
|
||||
pFileIn = fopen(pFilenameIn, "rb");
|
||||
if (!pFileIn)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameIn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pFileOut = fopen(pFilenameOut, "wb");
|
||||
if (!pFileOut)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameOut);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
start = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_END);
|
||||
end = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
|
||||
filesize = (end-start);
|
||||
romsize = (int)pow(2, nbits_addr+2);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Header
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "LIBRARY IEEE;\n");
|
||||
fprintf(pFileOut, "USE IEEE.STD_LOGIC_1164.ALL;\n");
|
||||
fprintf(pFileOut, "USE IEEE.NUMERIC_STD.ALL;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "library UNISIM;\n");
|
||||
fprintf(pFileOut, "use UNISIM.VComponents.all;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "ENTITY %s IS\n", ENT_NAME);
|
||||
fprintf(pFileOut, "\tPort\n");
|
||||
fprintf(pFileOut, "\t(\n");
|
||||
fprintf(pFileOut, "\t\tclk\t\t: in STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\t\tce\t\t: in STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\t\taddr\t\t: in unsigned(%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\t\tdout\t\t: out unsigned(%d downto 0)\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\t);\n");
|
||||
fprintf(pFileOut, "END %s;\n", ENT_NAME);
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
|
||||
fprintf(pFileOut, "ARCHITECTURE %s OF %s IS\n", ARCH_NAME, ENT_NAME);
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "\tsubtype word_t is unsigned(%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\ttype word_array_t is array (0 to %d) of word_t;\n", romsize/4-1);
|
||||
|
||||
fprintf(pFileOut, "\tsignal jtag_ld_clk\t\t: STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\tsignal jtag_ld_we\t\t: STD_LOGIC;\n");
|
||||
fprintf(pFileOut, "\tsignal jtag_ld_addr\t\t: unsigned (%d downto 0);\n", JTAG_ADDR_WIDTH-1);
|
||||
fprintf(pFileOut, "\tsignal jtag_ld_dout\t\t: unsigned (%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\tsignal jtag_ld_din\t\t: unsigned (%d downto 0);\n", nbits_data-1);
|
||||
fprintf(pFileOut, "\tsignal bs_rst, bs_sel, bs_shift, bs_tdi, bs_tdo : std_logic;\n");
|
||||
fprintf(pFileOut, "\tsignal bs_capture, bs_clk0, bs_clk1, bs_update0, bs_update1 : std_logic;\n");
|
||||
fprintf(pFileOut, "\tsignal user_regi, user_rego : unsigned (%d downto 0);\n", 31 + JTAG_ADDR_WIDTH);
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "\tsignal word_array : word_array_t :=\n");
|
||||
fprintf(pFileOut, "\t(\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// ROM part
|
||||
// -------------------------------------------------------------------------
|
||||
for (i=0; i < filesize; i += sizeof(int))
|
||||
{
|
||||
fread(&word, 1, sizeof(int), pFileIn);
|
||||
fprintf(pFileOut, "\t\tX\"%8.8X\"", word);
|
||||
if (i < (romsize-sizeof(int)))
|
||||
fprintf(pFileOut, ", -- %8.8X\n", i);
|
||||
else
|
||||
fprintf(pFileOut, " -- %8.8X\n", i);
|
||||
}
|
||||
word = 0;
|
||||
for (; i < romsize; i += sizeof(int))
|
||||
{
|
||||
fprintf(pFileOut, "\t\tX\"%8.8X\"", word);
|
||||
if (i < (romsize-sizeof(int)))
|
||||
fprintf(pFileOut, ", -- %8.8X\n", i);
|
||||
else
|
||||
fprintf(pFileOut, " -- %8.8X\n", i);
|
||||
}
|
||||
fprintf(pFileOut, "\t);\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "begin\n", ARCH_NAME);
|
||||
|
||||
fprintf(pFileOut, "\n");
|
||||
fprintf(pFileOut, "PROM_READ:\n", ARCH_NAME);
|
||||
fprintf(pFileOut, "\tprocess(clk)\n");
|
||||
fprintf(pFileOut, "\tbegin\n");
|
||||
fprintf(pFileOut, "\t\tif rising_edge(clk) and ce = '1' then\n");
|
||||
fprintf(pFileOut, "\t\t\tdout <= word_array(to_integer(addr(%d downto 2)));\n", nbits_addr+1);
|
||||
fprintf(pFileOut, "\t\tend if;\n");
|
||||
fprintf(pFileOut, "\tend process;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Trailer
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "\n");
|
||||
fputs(tpl, pFileOut);
|
||||
|
||||
fprintf(pFileOut, "PROM_WRITE:\n", ARCH_NAME);
|
||||
fprintf(pFileOut, "\tprocess(jtag_ld_clk, jtag_ld_we)\n");
|
||||
fprintf(pFileOut, "\tbegin\n");
|
||||
fprintf(pFileOut, "\t\tif rising_edge(jtag_ld_clk) then\n");
|
||||
fprintf(pFileOut, "\t\t\tif jtag_ld_we = '1' then\n");
|
||||
fprintf(pFileOut, "\t\t\t\tword_array(to_integer(jtag_ld_addr(%d downto 0))) <= jtag_ld_din;\n", nbits_addr-1);
|
||||
fprintf(pFileOut, "\t\t\telse\n");
|
||||
fprintf(pFileOut, "\t\t\t\tjtag_ld_dout <= word_array(to_integer(jtag_ld_addr(%d downto 0)));\n", nbits_addr-1);
|
||||
fprintf(pFileOut, "\t\t\tend if;\n");
|
||||
fprintf(pFileOut, "\t\tend if;\n");
|
||||
fprintf(pFileOut, "\tend process;\n");
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
fprintf(pFileOut, "end %s;\n", ARCH_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SaveROM_TCL(char *pFilenameIn, char *pFilenameOut, char *pArchName, char *pEntName, int nbits_addr, int nbits_data)
|
||||
{
|
||||
FILE *pFileIn, *pFileOut;
|
||||
long start, end;
|
||||
int i, word, word_addr, filesize, romsize;
|
||||
char binstr_addr[33];
|
||||
char binstr_data[33];
|
||||
|
||||
char tpl[] = {"# ---------------------------------------------------------------------\n# For Chipscope 9.1\n# ---------------------------------------------------------------------\n# Source JTAG/TCL frame work\ncd $env(CHIPSCOPE)\\\\bin\\\\nt\nsource csejtag.tcl\n\nnamespace import ::chipscope::*\n\n# Platform USB Cable\nset PLATFORM_USB_CABLE_ARGS [list \"port=USB2\" \"frequency=6000000\"]\n# frequency=\"24000000 | 12000000 | 6000000 | 3000000 | 1500000 | 750000\"\n\n# Create session\nset handle [::chipscope::csejtag_session create 0]\n\n# Open JTAG and lock\nset open_result [::chipscope::csejtag_target open $handle $CSEJTAG_TARGET_PLATFORMUSB 0 $PLATFORM_USB_CABLE_ARGS]\nset lock_result [::chipscope::csejtag_target lock $handle 1000]\n\nset devlist [::chipscope::csejtag_tap autodetect_chain $handle $CSEJTAG_SCAN_DEFAULT]\n\n# Get Device ID\nset devtype \"Virtex-4SX\"\nset devid 2\nset irlength [::chipscope::csejtag_tap get_irlength $handle $devid]\nset idcode [::chipscope::csejtag_tap get_device_idcode $handle $devid]\n\nset CSE_OP $CSEJTAG_SHIFT_READWRITE\nset CSE_ES $CSEJTAG_RUN_TEST_IDLE\n\n# Write Program\n"};
|
||||
|
||||
pFileIn = fopen(pFilenameIn, "rb");
|
||||
if (!pFileIn)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameIn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pFileOut = fopen(pFilenameOut, "wb");
|
||||
if (!pFileOut)
|
||||
{
|
||||
fprintf(stderr, "Error opening file %s\n", pFilenameOut);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
start = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_END);
|
||||
end = ftell(pFileIn);
|
||||
fseek(pFileIn, 0, SEEK_SET);
|
||||
|
||||
filesize = (end-start);
|
||||
romsize = (int)pow(2, nbits_addr+2);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Header
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
fputs(tpl, pFileOut);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// ROM part
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "# Assembled from %s\n", pFilenameIn);
|
||||
fprintf(pFileOut, "# ---------------------------------------------------------------\n");
|
||||
fprintf(pFileOut, "# Shift the USER1 Instruction (b1111000010) into the Instruction Register of FPGA\n");
|
||||
fprintf(pFileOut, "# User 1\n");
|
||||
fprintf(pFileOut, "set result [::chipscope::csejtag_tap shift_device_ir $handle $devid $CSE_OP $CSE_ES 0 $irlength \"3C2\"]\n\n");
|
||||
|
||||
word_addr = 0;
|
||||
for (i=0; i < filesize; i += sizeof(int))
|
||||
{
|
||||
fread(&word, 1, sizeof(int), pFileIn);
|
||||
fprintf(pFileOut, "::chipscope::csejtag_tap shift_device_dr $handle $devid $CSE_OP $CSE_ES 0 %d \"%4.4X%8.8X\"\n", nbits_data + JTAG_ADDR_WIDTH, word_addr, word);
|
||||
word_addr++;
|
||||
}
|
||||
fprintf(pFileOut, "\n");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Trailer
|
||||
// -------------------------------------------------------------------------
|
||||
fprintf(pFileOut, "::chipscope::csejtag_target unlock $handle\n");
|
||||
fprintf(pFileOut, "::chipscope::csejtag_target close $handle\n");
|
||||
fprintf(pFileOut, "::chipscope::csejtag_session destroy $handle\n");
|
||||
fprintf(pFileOut, "exit\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *pFilenameIn;
|
||||
char name_prj[1024];
|
||||
char name_rom[1024];
|
||||
char name_rom_v4ld[1024];
|
||||
char name_rom_tcl[1024];
|
||||
|
||||
FILE *pFileIn;
|
||||
int filesize, romsize, nbits_addr, nbits_data;
|
||||
long start, end;
|
||||
int word, i;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: romgen <input file> <num. word address bits>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pFilenameIn = argv[1];
|
||||
if (argc == 3)
|
||||
nbits_addr = atoi(argv[2]);
|
||||
|
||||
|
||||
basename(pFilenameIn, name_prj);
|
||||
sprintf(name_rom, "%s.vhd", name_prj);
|
||||
sprintf(name_rom_v4ld, "%s_ld.vhd", name_prj);
|
||||
sprintf(name_rom_tcl, "%s.tcl", name_prj);
|
||||
|
||||
SaveROM(pFilenameIn, name_rom, ARCH_NAME, ENT_NAME, nbits_addr, 32);
|
||||
SaveROM_V4LD(pFilenameIn, name_rom_v4ld, ARCH_NAME, ENT_NAME, nbits_addr, 32);
|
||||
SaveROM_TCL(pFilenameIn, name_rom_tcl, ARCH_NAME, ENT_NAME, nbits_addr, 32);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
-----------------------------------------------------------------------
|
||||
-- $Header: /tmp/cvsroot/VHDL/lib/misc/pkg_template.vhd,v 1.1.2.1 2013-08-18 06:59:02 jens Exp $
|
||||
-----------------------------------------------------------------------
|
||||
LIBRARY IEEE;
|
||||
USE IEEE.STD_LOGIC_1164.ALL;
|
||||
USE IEEE.NUMERIC_STD.ALL;
|
||||
|
||||
package template_pkg is
|
||||
|
||||
-- Constants
|
||||
|
||||
-- Types
|
||||
|
||||
-- Functions
|
||||
|
||||
end template_pkg;
|
||||
|
||||
package body template_pkg is
|
||||
|
||||
end template_pkg;
|
||||
|
||||
Reference in New Issue
Block a user