Created
September 15, 2019 03:05
-
-
Save classilla/15d933d33ac88fe8eed2418cb827cd9e to your computer and use it in GitHub Desktop.
Example of adding a "wait" instruction to Microwatt, the VHDL OpenPOWER ISA core.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/core.vhdl b/core.vhdl | |
index d34bf71..60c8cdf 100644 | |
--- a/core.vhdl | |
+++ b/core.vhdl | |
@@ -17,17 +17,18 @@ entity core is | |
wishbone_insn_in : in wishbone_slave_out; | |
wishbone_insn_out : out wishbone_master_out; | |
wishbone_data_in : in wishbone_slave_out; | |
wishbone_data_out : out wishbone_master_out; | |
-- Added for debug, ghdl doesn't support external names unfortunately | |
registers : out regfile; | |
- terminate_out : out std_ulogic | |
+ terminate_out : out std_ulogic; | |
+ halted_out : out std_ulogic | |
); | |
end core; | |
architecture behave of core is | |
-- fetch signals | |
signal fetch1_to_fetch2: Fetch1ToFetch2Type; | |
signal fetch2_to_decode1: Fetch2ToDecode1Type; | |
@@ -70,19 +71,21 @@ architecture behave of core is | |
signal decode1_stall_in : std_ulogic; | |
signal decode2_stall_out : std_ulogic; | |
signal flush: std_ulogic; | |
signal complete: std_ulogic; | |
signal terminate: std_ulogic; | |
+ signal halted: std_ulogic; | |
begin | |
terminate_out <= terminate; | |
+ halted_out <= halted; | |
fetch1_0: entity work.fetch1 | |
generic map ( | |
RESET_ADDRESS => (others => '0') | |
) | |
port map ( | |
clk => clk, | |
rst => rst, | |
@@ -173,17 +176,18 @@ begin | |
SIM => SIM | |
) | |
port map ( | |
clk => clk, | |
flush_out => flush, | |
e_in => decode2_to_execute1, | |
f_out => execute1_to_fetch1, | |
e_out => execute1_to_execute2, | |
- terminate_out => terminate | |
+ terminate_out => terminate, | |
+ halted_out => halted | |
); | |
execute2_0: entity work.execute2 | |
port map ( | |
clk => clk, | |
e_in => execute1_to_execute2, | |
e_out => execute2_to_writeback | |
); | |
diff --git a/decode1.vhdl b/decode1.vhdl | |
index d33c4d0..e39cd26 100644 | |
--- a/decode1.vhdl | |
+++ b/decode1.vhdl | |
@@ -214,16 +214,17 @@ architecture behaviour of decode1 is | |
PPC_SUBFIC => (ALU, OP_SUBFC, RA, CONST_SI, NONE, RT, NONE, NONE, NONE, '0', '0', '0', '1', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), | |
--PPC_SUBFME | |
PPC_SUBFZE => (ALU, OP_SUBFC, RA, NONE, NONE, RT, NONE, NONE, NONE, '0', '0', '1', '1', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '1'), | |
PPC_SYNC => (ALU, OP_NOP, NONE, NONE, NONE, NONE, NONE, NONE, NONE, '0', '0', '0', '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), | |
--PPC_TD | |
PPC_TDI => (ALU, OP_TDI, RA, CONST_SI, NONE, NONE, TOO, NONE, NONE, '0', '0', '0', '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), | |
--PPC_TW | |
--PPC_TWI | |
+ PPC_WAIT => (ALU, OP_WAIT, NONE, NONE, NONE, NONE, TOO, NONE, NONE, '0', '0', '0', '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), | |
PPC_XOR => (ALU, OP_XOR, RS, RB, NONE, RA, NONE, NONE, NONE, '0', '0', '0', '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '1'), | |
PPC_XORI => (ALU, OP_XOR, RS, CONST_UI, NONE, RA, NONE, NONE, NONE, '0', '0', '0', '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), | |
PPC_XORIS => (ALU, OP_XOR, RS, CONST_UI_HI, NONE, RA, NONE, NONE, NONE, '0', '0', '0', '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), | |
PPC_SIM_CONFIG => (ALU, OP_SIM_CONFIG,NONE, NONE, NONE, RT, NONE, NONE, NONE, '0', '0', '0', '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), | |
others => decode_rom_init | |
); | |
@@ -816,16 +817,19 @@ begin | |
report "PPC_tdi"; | |
ppc_insn := PPC_TDI; | |
elsif std_match(f_in.insn, "011111---------------0000000100-") then | |
report "PPC_tw"; | |
ppc_insn := PPC_TW; | |
elsif std_match(f_in.insn, "000011--------------------------") then | |
report "PPC_twi"; | |
ppc_insn := PPC_TWI; | |
+ elsif std_match(f_in.insn, "011111---------------0000011110-") then | |
+ report "PPC_wait"; | |
+ ppc_insn := PPC_WAIT; | |
elsif std_match(f_in.insn, "011111---------------0100111100-") then | |
report "PPC_xor"; | |
ppc_insn := PPC_XOR; | |
elsif std_match(f_in.insn, "011010--------------------------") then | |
report "PPC_xori"; | |
ppc_insn := PPC_XORI; | |
elsif std_match(f_in.insn, "011011--------------------------") then | |
report "PPC_xoris"; | |
diff --git a/decode_types.vhdl b/decode_types.vhdl | |
index faf1305..a3dd23d 100644 | |
--- a/decode_types.vhdl | |
+++ b/decode_types.vhdl | |
@@ -31,17 +31,17 @@ package decode_types is | |
PPC_RLDIC, PPC_RLDICL, PPC_RLDICR, PPC_RLDIMI, PPC_RLWIMI, | |
PPC_RLWINM, PPC_RLWNM, PPC_SETB, PPC_SLD, PPC_SLW, PPC_SRAD, | |
PPC_SRADI, PPC_SRAW, PPC_SRAWI, PPC_SRD, PPC_SRW, PPC_STB, | |
PPC_STBCX, PPC_STBU, PPC_STBUX, PPC_STBX, PPC_STD, PPC_STDBRX, | |
PPC_STDCX, PPC_STDU, PPC_STDUX, PPC_STDX, PPC_STH, PPC_STHBRX, | |
PPC_STHCX, PPC_STHU, PPC_STHUX, PPC_STHX, PPC_STW, PPC_STWBRX, | |
PPC_STWCX, PPC_STWU, PPC_STWUX, PPC_STWX, PPC_SUBF, PPC_SUBFC, | |
PPC_SUBFE, PPC_SUBFIC, PPC_SUBFME, PPC_SUBFZE, PPC_SYNC, PPC_TD, | |
- PPC_TDI, PPC_TW, PPC_TWI, PPC_XOR, PPC_XORI, PPC_XORIS, | |
+ PPC_TDI, PPC_TW, PPC_TWI, PPC_WAIT, PPC_XOR, PPC_XORI, PPC_XORIS, | |
PPC_SIM_CONFIG); | |
type insn_type_t is (OP_ILLEGAL, OP_NOP, OP_ADD, OP_ADDC, OP_ADDEX, OP_ADDME, | |
OP_ADDPCIS, OP_AND, OP_ANDC, OP_ATTN, OP_B, OP_BA, OP_BC, | |
OP_BCA, OP_BCCTR, OP_BCLA, OP_BCLR, OP_BCTAR, OP_BPERM, OP_CMP, | |
OP_CMPB, OP_CMPEQB, OP_CMPL, OP_CMPRB, | |
OP_CNTLZD, OP_CNTLZW, OP_CNTTZD, OP_CNTTZW, OP_CRAND, | |
OP_CRANDC, OP_CREQV, OP_CRNAND, OP_CRNOR, OP_CROR, OP_CRORC, | |
@@ -54,17 +54,17 @@ package decode_types is | |
OP_MFTB, OP_MFSPR, OP_MODSD, OP_MODSW, OP_MODUD, OP_MODUW, | |
OP_MTCRF, OP_MTOCRF, OP_MTCTR, OP_MTLR, OP_MTSPR, OP_MUL_L64, | |
OP_MUL_H64, OP_MUL_H32, OP_NAND, OP_NEG, OP_NOR, OP_OR, | |
OP_ORC, OP_POPCNTB, OP_POPCNTD, OP_POPCNTW, OP_PRTYD, | |
OP_PRTYW, OP_RLDCL, OP_RLDCR, OP_RLDIC, OP_RLDICL, OP_RLDICR, | |
OP_RLDIMI, OP_RLWIMI, OP_RLWINM, OP_RLWNM, OP_SETB, OP_SLD, | |
OP_SLW, OP_SRAD, OP_SRADI, OP_SRAW, OP_SRAWI, OP_SRD, OP_SRW, | |
OP_SUBF, OP_SUBFC, OP_SUBFME, OP_SYNC, OP_TD, OP_TDI, OP_TW, | |
- OP_TWI, OP_XOR, OP_SIM_CONFIG); | |
+ OP_TWI, OP_WAIT, OP_XOR, OP_SIM_CONFIG); | |
type input_reg_a_t is (NONE, RA, RA_OR_ZERO, RS); | |
type input_reg_b_t is (NONE, RB, RS, CONST_UI, CONST_SI, CONST_SI_HI, CONST_UI_HI, CONST_LI, CONST_BD, CONST_DS); | |
type input_reg_c_t is (NONE, RS); | |
type output_reg_a_t is (NONE, RT, RA); | |
type constant_a_t is (NONE, SH, SH32, FXM, BO, BF, TOO, BC); | |
type constant_b_t is (NONE, MB, ME, MB32, BI, L); | |
type constant_c_t is (NONE, ME32, BH); | |
diff --git a/execute1.vhdl b/execute1.vhdl | |
index 8aba386..c7c2465 100644 | |
--- a/execute1.vhdl | |
+++ b/execute1.vhdl | |
@@ -22,17 +22,18 @@ entity execute1 is | |
e_in : in Decode2ToExecute1Type; | |
-- asynchronous | |
f_out : out Execute1ToFetch1Type; | |
e_out : out Execute1ToExecute2Type; | |
- terminate_out : out std_ulogic | |
+ terminate_out : out std_ulogic; | |
+ halted_out : out std_ulogic | |
); | |
end entity execute1; | |
architecture behaviour of execute1 is | |
type reg_type is record | |
--f : Execute1ToFetch1Type; | |
e : Execute1ToExecute2Type; | |
end record; | |
@@ -66,31 +67,41 @@ begin | |
v.e := Execute1ToExecute2Init; | |
--v.f := Execute1ToFetch1TypeInit; | |
ctrl_tmp <= ctrl; | |
-- FIXME: run at 512MHz not core freq | |
ctrl_tmp.tb <= std_ulogic_vector(unsigned(ctrl.tb) + 1); | |
terminate_out <= '0'; | |
+ halted_out <= '0'; | |
flush_out <= '0'; | |
f_out <= Execute1ToFetch1TypeInit; | |
if e_in.valid = '1' then | |
v.e.valid := '1'; | |
v.e.write_reg := e_in.write_reg; | |
case_0: case e_in.insn_type is | |
when OP_ILLEGAL => | |
terminate_out <= '1'; | |
report "illegal"; | |
when OP_NOP => | |
-- Do nothing | |
+ when OP_WAIT => | |
+ -- Only 0b00 is defined; the rest are "reserved." | |
+ if unsigned(e_in.const1) /= 0 then | |
+ terminate_out <= '1'; | |
+ report "unsupported wait condition " & INTEGER'IMAGE(to_integer(unsigned(e_in.const1))); | |
+ else | |
+ halted_out <= '1'; | |
+ report "execution halted"; | |
+ end if; | |
when OP_ADD => | |
result := ppc_add(e_in.read_data1, e_in.read_data2); | |
result_en := 1; | |
when OP_ADDC => | |
result_with_carry := ppc_adde(e_in.read_data1, e_in.read_data2, ctrl.carry and e_in.input_carry); | |
result := result_with_carry(63 downto 0); | |
ctrl_tmp.carry <= result_with_carry(64) and e_in.output_carry; | |
result_en := 1; | |
diff --git a/soc.vhdl b/soc.vhdl | |
index 045679f..fee7d40 100644 | |
--- a/soc.vhdl | |
+++ b/soc.vhdl | |
@@ -1,12 +1,13 @@ | |
library ieee; | |
use ieee.std_logic_1164.all; | |
use ieee.math_real.all; | |
+use std.env.all; | |
use std.textio.all; | |
library work; | |
use work.common.all; | |
use work.wishbone_types.all; | |
-- 0x00000000: Main memory (1 MB) | |
@@ -48,33 +49,35 @@ architecture behaviour of soc is | |
-- Main memory signals: | |
signal wb_bram_in : wishbone_master_out; | |
signal wb_bram_out : wishbone_slave_out; | |
constant mem_adr_bits : positive := positive(ceil(log2(real(MEMORY_SIZE)))); | |
-- Debug signals (used in SIM only) | |
signal registers : regfile; | |
signal terminate : std_ulogic; | |
+ signal halted : std_ulogic; | |
begin | |
-- Processor core | |
processor: entity work.core | |
generic map( | |
SIM => SIM | |
) | |
port map( | |
clk => system_clk, | |
rst => rst, | |
wishbone_insn_in => wishbone_icore_in, | |
wishbone_insn_out => wishbone_icore_out, | |
wishbone_data_in => wishbone_dcore_in, | |
wishbone_data_out => wishbone_dcore_out, | |
registers => registers, | |
- terminate_out => terminate | |
+ terminate_out => terminate, | |
+ halted_out => halted | |
); | |
-- Wishbone bus master arbiter & mux | |
wishbone_arbiter_0: entity work.wishbone_arbiter | |
port map( | |
clk => system_clk, | |
rst => rst, | |
wb1_in => wishbone_dcore_out, | |
@@ -122,17 +125,19 @@ begin | |
end process slave_intercon; | |
-- Simulated memory and UART | |
sim_terminate_test: if SIM generate | |
-- Dump registers if core terminates | |
dump_registers: process(all) | |
begin | |
- if terminate = '1' then | |
+ if halted = '1' then | |
+ stop(0); | |
+ elsif terminate = '1' then | |
loop_0: for i in 0 to 31 loop | |
report "REG " & to_hstring(registers(i)); | |
end loop loop_0; | |
assert false report "end of test" severity failure; | |
end if; | |
end process; | |
end generate; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment