Skip to content

Instantly share code, notes, and snippets.

@classilla
Created September 15, 2019 03:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save classilla/15d933d33ac88fe8eed2418cb827cd9e to your computer and use it in GitHub Desktop.
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.
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