1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-15 07:53:37 +00:00

add V30 CPU

This commit is contained in:
Marcel 2022-07-30 13:31:00 +02:00
parent e61740cda2
commit 104392cbfd
7 changed files with 3684 additions and 0 deletions

6
common/CPU/v30/V30.qip Normal file
View File

@ -0,0 +1,6 @@
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) cpu.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) divider.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) export.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) registerpackage.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) bus_savestates.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) reg_savestates.vhd ]

View File

@ -0,0 +1,105 @@
-----------------------------------------------------------------
--------------- Bus Package --------------------------------
-----------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
package pBus_savestates is
constant SSBUS_buswidth : integer := 64;
constant SSBUS_busadr : integer := 7;
type savestate_type is record
Adr : integer range 0 to (2**SSBUS_busadr)-1;
upper : integer range 0 to SSBUS_buswidth-1;
lower : integer range 0 to SSBUS_buswidth-1;
size : integer range 0 to (2**SSBUS_busadr)-1;
defval : std_logic_vector(SSBUS_buswidth-1 downto 0);
end record;
end package;
-----------------------------------------------------------------
--------------- Reg Interface -----------------------------------
-----------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
library work;
use work.pBus_savestates.all;
entity eReg_SS is
generic
(
Reg : savestate_type;
index : integer := 0
);
port
(
clk : in std_logic;
BUS_Din : in std_logic_vector(SSBUS_buswidth-1 downto 0);
BUS_Adr : in std_logic_vector(SSBUS_busadr-1 downto 0);
BUS_wren : in std_logic;
BUS_rst : in std_logic;
BUS_Dout : out std_logic_vector(SSBUS_buswidth-1 downto 0) := (others => '0');
Din : in std_logic_vector(Reg.upper downto Reg.lower);
Dout : out std_logic_vector(Reg.upper downto Reg.lower)
);
end entity;
architecture arch of eReg_SS is
signal Dout_buffer : std_logic_vector(Reg.upper downto Reg.lower) := Reg.defval(Reg.upper downto Reg.lower);
signal AdrI : std_logic_vector(BUS_Adr'left downto 0);
begin
AdrI <= std_logic_vector(to_unsigned(Reg.Adr + index, BUS_Adr'length));
process (clk)
begin
if rising_edge(clk) then
if (BUS_rst = '1') then
Dout_buffer <= Reg.defval(Reg.upper downto Reg.lower);
else
if (BUS_Adr = AdrI and BUS_wren = '1') then
for i in Reg.lower to Reg.upper loop
Dout_buffer(i) <= BUS_Din(i);
end loop;
end if;
end if;
end if;
end process;
Dout <= Dout_buffer;
goutputbit: for i in Reg.lower to Reg.upper generate
BUS_Dout(i) <= Din(i) when BUS_Adr = AdrI else '0';
end generate;
glowzero_required: if Reg.lower > 0 generate
glowzero: for i in 0 to Reg.lower - 1 generate
BUS_Dout(i) <= '0';
end generate;
end generate;
ghighzero_required: if Reg.upper < SSBUS_buswidth-1 generate
ghighzero: for i in Reg.upper + 1 to SSBUS_buswidth-1 generate
BUS_Dout(i) <= '0';
end generate;
end generate;
end architecture;

3073
common/CPU/v30/cpu.vhd Normal file

File diff suppressed because it is too large Load Diff

123
common/CPU/v30/divider.vhd Normal file
View File

@ -0,0 +1,123 @@
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity divider is
port
(
clk : in std_logic;
start : in std_logic;
done : out std_logic := '0';
busy : out std_logic := '0';
dividend : in signed(32 downto 0);
divisor : in signed(32 downto 0);
quotient : out signed(32 downto 0);
remainder : out signed(32 downto 0)
);
end entity;
architecture arch of divider is
constant bits_per_cycle : integer := 1;
signal dividend_u : unsigned(dividend'length downto 0);
signal divisor_u : unsigned(divisor'length downto 0);
signal quotient_u : unsigned(quotient'length downto 0);
signal Akku : unsigned (divisor'left + 1 downto divisor'right);
signal QPointer : integer range quotient_u'range;
signal done_buffer : std_logic := '0';
begin
process (clk) is
variable XPointer : integer range dividend_u'range;
variable QPointerNew : integer range quotient_u'range;
variable AkkuNew : unsigned (divisor'left + 1 downto divisor'right);
variable Rdy_i : std_logic;
variable Q_bits : std_logic_vector(bits_per_cycle-1 downto 0);
variable Diff : unsigned (AkkuNew'range);
begin
if rising_edge(clk) then
done_buffer <= '0';
busy <= '0';
-- == Initialize loop ===============================================
if start = '1' then
busy <= '1';
dividend_u <= '0' & unsigned(abs(dividend));
divisor_u <= '0' & unsigned(abs(divisor));
QPointerNew := quotient_u'left;
XPointer := dividend_u'left;
Rdy_i := '0';
--AkkuNew := (Akku'left downto 1 => '0') & dividend(XPointer);
AkkuNew := (others => '0');
-- == Repeat for every Digit in Q ===================================
elsif Rdy_i = '0' then
busy <= '1';
AkkuNew := Akku;
QPointerNew := QPointer;
for i in 1 to bits_per_cycle loop
-- Calculate output digit and new Akku ---------------------------
Diff := AkkuNew - divisor_u;
if Diff(Diff'left) = '0' then -- Does Y fit in Akku?
Q_bits(bits_per_cycle-i) := '1'; -- YES: Digit is '1'
AkkuNew := unsigned(shift_left(Diff,1));-- Diff -> Akku
else --
Q_bits(bits_per_cycle-i) := '0'; -- NO : Digit is '0'
AkkuNew := unsigned(Shift_left(AkkuNew,1));-- Shift Akku
end if;
-- ---------------------------------------------------------------
if XPointer > dividend'right then -- divisor read completely?
XPointer := XPointer - 1; -- NO : Put next digit
AkkuNew(AkkuNew'right) := dividend_u(XPointer); -- in Akku
else
AkkuNew(AkkuNew'right) := '0' ; -- YES: Read Zeros (post point)
end if;
-- ---------------------------------------------------------------
if QPointerNew > quotient'right then -- Has this been the last cycle?
QPointerNew := QPointerNew - 1; -- NO : Prepare next cycle
else --
Rdy_i := '1'; -- YES: work done
done_buffer <= '1';
end if;
end loop;
quotient_u(QPointer downto QPointer-(bits_per_cycle-1)) <= unsigned(Q_bits);
end if;
QPointer <= QPointerNew;
Akku <= AkkuNew;
if ((dividend(dividend'left) xor divisor(divisor'left)) = '1') then
quotient <= -signed(quotient_u(quotient'left downto 0));
else
quotient <= signed(quotient_u(quotient'left downto 0));
end if;
if (dividend(dividend'left) = '1') then
remainder <= -signed(AkkuNew(remainder'left + 1 downto remainder'right + 1));
else
remainder <= signed(AkkuNew(remainder'left + 1 downto remainder'right + 1));
end if;
done <= done_buffer;
end if;
end process;
end architecture;

221
common/CPU/v30/export.vhd Normal file
View File

@ -0,0 +1,221 @@
-----------------------------------------------------------------
--------------- Export Package --------------------------------
-----------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
package pexport is
type cpu_export_type is record
reg_ax : unsigned(15 downto 0);
reg_cx : unsigned(15 downto 0);
reg_dx : unsigned(15 downto 0);
reg_bx : unsigned(15 downto 0);
reg_sp : unsigned(15 downto 0);
reg_bp : unsigned(15 downto 0);
reg_si : unsigned(15 downto 0);
reg_di : unsigned(15 downto 0);
reg_es : unsigned(15 downto 0);
reg_cs : unsigned(15 downto 0);
reg_ss : unsigned(15 downto 0);
reg_ds : unsigned(15 downto 0);
reg_ip : unsigned(15 downto 0);
reg_f : unsigned(15 downto 0);
opcodebyte_last : std_logic_vector(7 downto 0);
end record;
end package;
-----------------------------------------------------------------
--------------- Export module --------------------------------
-----------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use STD.textio.all;
use work.pexport.all;
entity export is
port
(
clk : in std_logic;
ce : in std_logic;
reset : in std_logic;
new_export : in std_logic;
export_cpu : in cpu_export_type;
export_irq : in std_logic_vector(7 downto 0);
export_8 : in std_logic_vector(7 downto 0);
export_16 : in std_logic_vector(15 downto 0);
export_32 : in std_logic_vector(31 downto 0)
);
end entity;
architecture arch of export is
signal totalticks : unsigned(31 downto 0) := (others => '0');
signal cyclenr : unsigned(31 downto 0) := x"00000001";
signal reset_1 : std_logic := '0';
signal export_reset : std_logic := '0';
signal exportnow : std_logic;
function to_lower(c: character) return character is
variable l: character;
begin
case c is
when 'A' => l := 'a';
when 'B' => l := 'b';
when 'C' => l := 'c';
when 'D' => l := 'd';
when 'E' => l := 'e';
when 'F' => l := 'f';
when 'G' => l := 'g';
when 'H' => l := 'h';
when 'I' => l := 'i';
when 'J' => l := 'j';
when 'K' => l := 'k';
when 'L' => l := 'l';
when 'M' => l := 'm';
when 'N' => l := 'n';
when 'O' => l := 'o';
when 'P' => l := 'p';
when 'Q' => l := 'q';
when 'R' => l := 'r';
when 'S' => l := 's';
when 'T' => l := 't';
when 'U' => l := 'u';
when 'V' => l := 'v';
when 'W' => l := 'w';
when 'X' => l := 'x';
when 'Y' => l := 'y';
when 'Z' => l := 'z';
when others => l := c;
end case;
return l;
end to_lower;
function to_lower(s: string) return string is
variable lowercase: string (s'range);
begin
for i in s'range loop
lowercase(i):= to_lower(s(i));
end loop;
return lowercase;
end to_lower;
begin
-- synthesis translate_off
process(clk)
begin
if rising_edge(clk) then
if (reset = '1') then
totalticks <= (others => '0');
elsif (ce = '1') then
totalticks <= totalticks + 1;
end if;
reset_1 <= reset;
end if;
end process;
export_reset <= '1' when (reset = '0' and reset_1 = '1') else '0';
exportnow <= export_reset or new_export;
process
file outfile: text;
file outfile_irp: text;
variable f_status: FILE_OPEN_STATUS;
variable line_out : line;
variable recordcount : integer := 0;
constant filenamebase : string := "R:\\debug_sim";
variable filename_current : string(1 to 25);
begin
filename_current := filenamebase & "00000000.txt";
file_open(f_status, outfile, filename_current, write_mode);
file_close(outfile);
file_open(f_status, outfile, filename_current, append_mode);
write(line_out, string'("IP F AX BX CX DX SP BP SI DI ES CS SS DS OP TICKS IQ GPU D8 D16 D32"));
writeline(outfile, line_out);
while (true) loop
wait until rising_edge(clk);
if (reset = '1') then
cyclenr <= x"00000001";
filename_current := filenamebase & "00000000.txt";
file_close(outfile);
file_open(f_status, outfile, filename_current, write_mode);
file_close(outfile);
file_open(f_status, outfile, filename_current, append_mode);
write(line_out, string'("IP F AX BX CX DX SP BP SI DI ES CS SS DS OP TICKS IQ GPU D8 D16 D32"));
writeline(outfile, line_out);
end if;
if (exportnow = '1') then
write(line_out, to_lower(to_hstring(export_cpu.reg_ip)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_f )) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_ax)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_bx)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_cx)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_dx)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_sp)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_bp)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_si)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_di)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_es)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_cs)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_ss)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.reg_ds)) & " ");
write(line_out, to_lower(to_hstring(export_cpu.opcodebyte_last)) & " ");
write(line_out, to_lower(to_hstring(totalticks)) & " ");
write(line_out, to_lower(to_hstring(export_irq )) & " ");
write(line_out, to_lower(to_hstring(to_unsigned(0, 12))) & " "); -- gpu
write(line_out, to_lower(to_hstring(export_8 )) & " ");
write(line_out, to_lower(to_hstring(export_16)) & " ");
write(line_out, to_lower(to_hstring(export_32)) & " ");
writeline(outfile, line_out);
cyclenr <= cyclenr + 1;
if (cyclenr mod 10000000 = 0) then
filename_current := filenamebase & to_hstring(cyclenr) & ".txt";
file_close(outfile);
file_open(f_status, outfile, filename_current, write_mode);
file_close(outfile);
file_open(f_status, outfile, filename_current, append_mode);
write(line_out, string'("IP F AX BX CX DX SP BP SI DI ES CS SS DS OP TICKS IQ GPU D8 D16 D32"));
writeline(outfile, line_out);
end if;
end if;
end loop;
end process;
-- synthesis translate_on
end architecture;

View File

@ -0,0 +1,37 @@
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.pBus_savestates.all;
package pReg_savestates is
-- ( adr upper lower size default)
-- cpu
constant REG_SAVESTATE_CPU1 : savestate_type := ( 0, 63, 0, 1, x"0000000000000000"); -- DX_CX_AX_IP
constant REG_SAVESTATE_CPU2 : savestate_type := ( 1, 63, 0, 1, x"0000000020000000"); -- SI_BP_SP_BX
constant REG_SAVESTATE_CPU3 : savestate_type := ( 2, 63, 0, 1, x"0000FFFF00000000"); -- SS_CS_ES_DI
constant REG_SAVESTATE_CPU4 : savestate_type := ( 3, 31, 0, 1, x"00000000F0020000"); -- F_DS
constant REG_SAVESTATE_IRQ : savestate_type := ( 5, 7, 0, 1, x"0000000000000000");
constant REG_SAVESTATE_GPU : savestate_type := ( 7, 15, 0, 1, x"0000000000009EFF");
constant REG_SAVESTATE_DMA : savestate_type := ( 11, 59, 0, 1, x"0000000000000000");
constant REG_SAVESTATE_SOUND3 : savestate_type := ( 15, 10, 0, 1, x"0000000000000000");
constant REG_SAVESTATE_SOUND4 : savestate_type := ( 16, 19, 0, 1, x"0000000000000000");
constant REG_SAVESTATE_SOUNDDMA : savestate_type := ( 17, 59, 0, 1, x"0000000000000000");
constant REG_SAVESTATE_EEPROMINT : savestate_type := ( 19, 16, 0, 1, x"0000000000000000");
constant REG_SAVESTATE_EEPROMEXT : savestate_type := ( 21, 16, 0, 1, x"0000000000000000");
constant REG_SAVESTATE_MIXED : savestate_type := ( 23, 0, 0, 1, x"0000000000000000");
constant REG_SAVESTATE_TIMER : savestate_type := ( 27, 35, 0, 1, x"0000000000000000");
end package;

View File

@ -0,0 +1,119 @@
-----------------------------------------------------------------
--------------- Bus Package --------------------------------
-----------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
package pRegisterBus is
constant BUS_buswidth : integer := 8;
constant BUS_busadr : integer := 8;
type regaccess_type is
(
readwrite,
readonly,
writeonly,
writeDone -- writeonly, but does send back done, so it is not dead
);
type regmap_type is record
Adr : integer range 0 to (2**BUS_busadr)-1;
upper : integer range 0 to BUS_buswidth-1;
lower : integer range 0 to BUS_buswidth-1;
size : integer range 0 to (2**BUS_busadr)-1;
defval : integer;
acccesstype : regaccess_type;
end record;
end package;
-----------------------------------------------------------------
--------------- Reg Interface ----------------------------------
-----------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
library work;
use work.pRegisterBus.all;
entity eReg is
generic
(
Reg : regmap_type;
index : integer := 0
);
port
(
clk : in std_logic;
BUS_Din : in std_logic_vector(BUS_buswidth-1 downto 0);
BUS_Adr : in std_logic_vector(BUS_busadr-1 downto 0);
BUS_wren : in std_logic;
BUS_rst : in std_logic;
BUS_Dout : out std_logic_vector(BUS_buswidth-1 downto 0) := (others => '0');
Din : in std_logic_vector(Reg.upper downto Reg.lower);
Dout : out std_logic_vector(Reg.upper downto Reg.lower);
written : out std_logic := '0'
);
end entity;
architecture arch of eReg is
signal Dout_buffer : std_logic_vector(Reg.upper downto Reg.lower) := std_logic_vector(to_unsigned(Reg.defval,Reg.upper-Reg.lower+1));
signal AdrI : std_logic_vector(BUS_Adr'left downto 0);
begin
AdrI <= std_logic_vector(to_unsigned(Reg.Adr + index, BUS_Adr'length));
process (clk)
begin
if rising_edge(clk) then
if (BUS_rst = '1') then
Dout_buffer <= std_logic_vector(to_unsigned(Reg.defval,Reg.upper-Reg.lower+1));
else
if (BUS_Adr = AdrI and BUS_wren = '1') then
for i in Reg.lower to Reg.upper loop
Dout_buffer(i) <= BUS_Din(i);
end loop;
end if;
end if;
end if;
end process;
Dout <= Dout_buffer;
written <= '1' when (BUS_Adr = AdrI and BUS_wren = '1') else '0';
goutputbit: for i in Reg.lower to Reg.upper generate
BUS_Dout(i) <= Din(i) when BUS_Adr = AdrI else '0';
end generate;
glowzero_required: if Reg.lower > 0 generate
glowzero: for i in 0 to Reg.lower - 1 generate
BUS_Dout(i) <= '0';
end generate;
end generate;
ghighzero_required: if Reg.upper < BUS_buswidth-1 generate
ghighzero: for i in Reg.upper + 1 to BUS_buswidth-1 generate
BUS_Dout(i) <= '0';
end generate;
end generate;
end architecture;