Merge pull request #60 from kitune-san/ide-test3

IDE Implementation
This commit is contained in:
Aitor Gómez
2022-11-11 07:13:20 +01:00
committed by GitHub
6 changed files with 882 additions and 4 deletions

View File

@@ -213,8 +213,9 @@ module emu
"S0,IMGIMAVFD,Floppy A:;",
"S1,IMGIMAVFD,Floppy B:;",
"OJK,Write Protect,None,A:,B:,A: & B:;",
"-;",
"S2,IMG,HDD Image:;",
// "S2,IMG,HDD Image:;",
"S2,VHD,IDE 0-0;",
"S3,VHD,IDE 0-1;",
"-;",
"OHI,CPU Speed,4.77MHz,7.16MHz,14.318MHz;",
"-;",
@@ -373,7 +374,7 @@ module emu
wire mgmt_rd;
wire mgmt_wr;
wire [7:0] mgmt_req;
assign mgmt_req[5:0] = 6'b000000;
assign mgmt_req[5:3] = 3'b000;
wire [35:0] EXT_BUS;
hps_ext hps_ext
@@ -1033,6 +1034,7 @@ module emu
.clock_rate (cur_rate),
.floppy_wp (status[20:19]),
.fdd_request (mgmt_req[7:6]),
.ide0_request (mgmt_req[2:0]),
.xtctl (xtctl),
.enable_a000h (a000h)
);

View File

@@ -137,6 +137,7 @@ module CHIPSET (
input logic [27:0] clock_rate,
input logic [1:0] floppy_wp,
output logic [1:0] fdd_request,
output logic [2:0] ide0_request,
// XTCTL DATA
output logic [7:0] xtctl,
// Optional flags
@@ -345,6 +346,7 @@ module CHIPSET (
.clock_rate (clock_rate),
.floppy_wp (floppy_wp),
.fdd_request (fdd_request),
.ide0_request (ide0_request),
.fdd_dma_req (fdd_dma_req),
.fdd_dma_ack (~dma_acknowledge_n[2]),
.terminal_count (terminal_count_n),

View File

@@ -108,6 +108,7 @@ module PERIPHERALS #(
input logic [27:0] clock_rate,
input logic [1:0] floppy_wp,
output logic [1:0] fdd_request,
output logic [2:0] ide0_request,
output logic fdd_dma_req,
input logic fdd_dma_ack,
input logic terminal_count,
@@ -205,6 +206,7 @@ module PERIPHERALS #(
assign ems_b3 = (~iorq && ena_ems[2] && (address[19:14] == {ems_page_address, 2'b10})); // C8000h - D8000h - E8000h
assign ems_b4 = (~iorq && ena_ems[3] && (address[19:14] == {ems_page_address, 2'b11})); // CC000h - DC000h - EC000h
wire ide0_cs_n = ~(iorq && ~address_enable_n && ({address[15:4], 4'd0} == 16'h0300));
wire floppy0_select_n = ~(~address_enable_n && (({address[15:2], 2'd0} == 16'h03F0) || ({address[15:1], 1'd0} == 16'h03F4) || ({address[15:0]} == 16'h03F7)));
logic [1:0] ems_access_address;
@@ -976,10 +978,113 @@ module PERIPHERALS #(
);
//
// XT2IDE
//
logic [7:0] xt2ide0_data_bus_out;
logic ide0_cs1fx;
logic ide0_cs3fx;
logic ide0_io_read_n;
logic ide0_io_write_n;
logic [2:0] ide0_address;
logic ide0_data_bus_io;
logic [15:0] ide0_data_bus_in;
logic [15:0] ide0_data_bus_out;
XT2IDE xt2ide0 (
.clock (clock),
.reset (reset),
.high_speed (0),
.chip_select_n (ide0_cs_n),
.io_read_n (io_read_n),
.io_write_n (io_write_n),
.address (address[3:0]),
.data_bus_in (internal_data_bus),
.data_bus_out (xt2ide0_data_bus_out),
.ide_cs1fx (ide0_cs1fx),
.ide_cs3fx (ide0_cs3fx),
.ide_io_read_n (ide0_io_read_n),
.ide_io_write_n (ide0_io_write_n),
.ide_address (ide0_address),
.ide_data_bus_io (ide0_data_bus_io),
.ide_data_bus_in (ide0_data_bus_in),
.ide_data_bus_out (ide0_data_bus_out)
);
//
// IDE
//
logic mgmt_ide0_cs;
logic [15:0] mgmt_ide0_readdata;
logic ide0_command_cs;
logic ide0_control_cs;
logic ide0_comd_ctrl_select;
logic ide0_io_read;
logic ide0_io_read_1;
logic ide0_io_write;
logic prev_ide0_io_read;
logic prev_ide0_io_write;
logic [3:0] ide0_address_1;
logic [15:0] ide0_writedata;
assign mgmt_ide0_cs = (mgmt_address[15:8] == 8'hF0);
assign ide0_command_cs = ~ide0_cs1fx;
assign ide0_control_cs = ~ide0_cs3fx & &ide0_address[2:1];
assign ide0_io_read = ~ide0_io_read_n & (ide0_command_cs | ide0_control_cs);
assign ide0_io_write = ~ide0_io_write_n & (ide0_command_cs | ide0_control_cs);
always_ff @(posedge clock)
begin
ide0_io_read_1 <= ide0_io_read;
prev_ide0_io_read <= ide0_io_read_1;
prev_ide0_io_write <= ide0_io_write;
ide0_address_1 <= ~ide0_control_cs ? {1'b0, ide0_address} : {1'b1, ide0_address};
ide0_writedata <= ide0_data_bus_out;
end
ide ide
(
.clk (clock),
.rst_n (~reset),
// .irq (),
// .drq (),
.use_fast (0),
// .no_data (),
// .drive_en (),
.io_address (ide0_address_1),
.io_read (ide0_io_read & ~prev_ide0_io_read),
.io_readdata (ide0_data_bus_in),
.io_write (~ide0_io_write & prev_ide0_io_write),
.io_writedata (ide0_writedata),
.io_32 (0),
// .io_wait (),
.request (ide0_request),
.mgmt_address (mgmt_address[3:0]),
.mgmt_writedata (mgmt_writedata),
.mgmt_readdata (mgmt_ide0_readdata),
.mgmt_write (mgmt_write & mgmt_ide0_cs),
.mgmt_read (mgmt_read & mgmt_ide0_cs)
);
//
// FDC
//
logic mgmt_fdd_cs;
logic [15:0] mgmt_fdd_readdata;
logic [7:0] write_to_fdd;
logic [2:0] fdd_io_address;
logic fdd_io_read;
@@ -1061,7 +1166,7 @@ module PERIPHERALS #(
.mgmt_write (mgmt_write & mgmt_fdd_cs),
.mgmt_writedata (mgmt_writedata),
.mgmt_read (mgmt_read & mgmt_fdd_cs),
.mgmt_readdata (mgmt_readdata),
.mgmt_readdata (mgmt_fdd_readdata),
.wp (floppy_wp),
@@ -1091,6 +1196,12 @@ module PERIPHERALS #(
end
//
// mgmt_readdata
//
assign mgmt_readdata = mgmt_ide0_cs ? mgmt_ide0_readdata : mgmt_fdd_readdata;
//
// KFTVGA
//
@@ -1227,6 +1338,11 @@ module PERIPHERALS #(
data_bus_out_from_chipset <= 1'b1;
data_bus_out <= joy_data;
end
else if ((~ide0_cs_n) && (~io_read_n))
begin
data_bus_out_from_chipset <= 1'b1;
data_bus_out <= xt2ide0_data_bus_out;
end
else if ((~floppy0_select_n || fdd_dma_read) && (~io_read_n))
begin
data_bus_out_from_chipset <= 1'b1;

114
rtl/KFPC-XT/HDL/XT2IDE.sv Normal file
View File

@@ -0,0 +1,114 @@
//
// XT2IDE written by kitune-san
//
module XT2IDE
(
input logic clock,
input logic reset,
input logic high_speed,
input logic chip_select_n,
input logic io_read_n,
input logic io_write_n,
input logic [4:0] address,
input logic [7:0] data_bus_in,
output logic [7:0] data_bus_out,
output logic ide_cs1fx,
output logic ide_cs3fx,
output logic ide_io_read_n,
output logic ide_io_write_n,
output logic [2:0] ide_address,
output logic ide_data_bus_io,
input logic [15:0] ide_data_bus_in,
output logic [15:0] ide_data_bus_out
);
logic select_1;
logic select_2;
logic latch_high_read_byte;
logic read_high_byte;
logic latch_high_write_byte;
logic [7:0] read_buffer;
//
// Control Signals
//
assign select_1 = high_speed ? address[0] : address[3];
assign select_2 = high_speed ? address[3] : address[0];
always_comb
begin
latch_high_read_byte = 1'b0;
ide_data_bus_io = 1'b1;
read_high_byte = 1'b0;
latch_high_write_byte = 1'b0;
if (~address[2] & ~address[1] & ~select_2 & ~chip_select_n) begin
casez ({select_1, io_read_n, io_write_n})
3'b001: latch_high_read_byte = 1'b1;
3'b010: ide_data_bus_io = 1'b0;
3'b101: read_high_byte = 1'b1;
3'b110: latch_high_write_byte = 1'b1;
endcase
end
end
assign ide_io_read_n = io_read_n;
assign ide_io_write_n = io_write_n;
assign ide_cs1fx = select_1 | chip_select_n;
assign ide_cs3fx = ~select_1 | chip_select_n;
//
// XT Address -> IDE Address
//
assign ide_address = {address[2:1], select_2};
//
// XT Data Bus -> IDE Data Bus
//
always_ff @(posedge clock, posedge reset)
begin
if (reset)
ide_data_bus_out[15:8] <= 8'hFF;
else if (~chip_select_n & latch_high_write_byte)
ide_data_bus_out[15:8] <= data_bus_in;
else
ide_data_bus_out[15:8] <= ide_data_bus_out[15:8];
end
always_comb
begin
if (io_write_n | chip_select_n)
ide_data_bus_out[7:0] = 8'hFF;
else
ide_data_bus_out[7:0] = data_bus_in;
end
//
// IDE Data Bus -> XT Data Bus
//
always_ff @(posedge clock, posedge reset)
begin
if (reset)
read_buffer <= 8'hFF;
else if (~ide_io_read_n & latch_high_read_byte)
read_buffer <= ide_data_bus_in[15:8];
else
read_buffer <= read_buffer;
end
always_comb
begin
if (read_high_byte)
data_bus_out = read_buffer;
else if (~io_read_n & ~chip_select_n)
data_bus_out = ide_data_bus_in[7:0];
else
data_bus_out = 8'hFF;
end
endmodule

330
rtl/common/bram.vhd Normal file
View File

@@ -0,0 +1,330 @@
--------------------------------------------------------------
-- Single port Block RAM
--------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.altera_mf_components.all;
ENTITY spram IS
generic (
addr_width : integer := 8;
data_width : integer := 8;
mem_init_file : string := " ";
mem_name : string := "MEM" -- for InSystem Memory content editor.
);
PORT
(
clock : in STD_LOGIC;
address : in STD_LOGIC_VECTOR (addr_width-1 DOWNTO 0);
data : in STD_LOGIC_VECTOR (data_width-1 DOWNTO 0) := (others => '0');
enable : in STD_LOGIC := '1';
wren : in STD_LOGIC := '0';
q : out STD_LOGIC_VECTOR (data_width-1 DOWNTO 0);
cs : in std_logic := '1'
);
END spram;
ARCHITECTURE SYN OF spram IS
BEGIN
spram_sz : work.spram_sz
generic map(addr_width, data_width, 2**addr_width, mem_init_file, mem_name)
port map(clock,address,data,enable,wren,q,cs);
END SYN;
--------------------------------------------------------------
-- Single port Block RAM with specific size
--------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.altera_mf_components.all;
ENTITY spram_sz IS
generic (
addr_width : integer := 8;
data_width : integer := 8;
numwords : integer := 2**8;
mem_init_file : string := " ";
mem_name : string := "MEM" -- for InSystem Memory content editor.
);
PORT
(
clock : in STD_LOGIC;
address : in STD_LOGIC_VECTOR (addr_width-1 DOWNTO 0);
data : in STD_LOGIC_VECTOR (data_width-1 DOWNTO 0) := (others => '0');
enable : in STD_LOGIC := '1';
wren : in STD_LOGIC := '0';
q : out STD_LOGIC_VECTOR (data_width-1 DOWNTO 0);
cs : in std_logic := '1'
);
END ENTITY;
ARCHITECTURE SYN OF spram_sz IS
signal q0 : std_logic_vector((data_width - 1) downto 0);
BEGIN
q<= q0 when cs = '1' else (others => '1');
altsyncram_component : altsyncram
GENERIC MAP (
clock_enable_input_a => "BYPASS",
clock_enable_output_a => "BYPASS",
intended_device_family => "Cyclone V",
lpm_hint => "ENABLE_RUNTIME_MOD=YES,INSTANCE_NAME="&mem_name,
lpm_type => "altsyncram",
numwords_a => numwords,
operation_mode => "SINGLE_PORT",
outdata_aclr_a => "NONE",
outdata_reg_a => "UNREGISTERED",
power_up_uninitialized => "FALSE",
read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ",
init_file => mem_init_file,
widthad_a => addr_width,
width_a => data_width,
width_byteena_a => 1
)
PORT MAP (
address_a => address,
clock0 => clock,
data_a => data,
wren_a => wren and cs,
q_a => q0
);
END SYN;
--------------------------------------------------------------
-- Dual port Block RAM same parameters on both ports
--------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.altera_mf_components.all;
entity dpram is
generic (
addr_width : integer := 8;
data_width : integer := 8;
mem_init_file : string := " "
);
PORT
(
clock : in STD_LOGIC;
address_a : in STD_LOGIC_VECTOR (addr_width-1 DOWNTO 0);
data_a : in STD_LOGIC_VECTOR (data_width-1 DOWNTO 0) := (others => '0');
enable_a : in STD_LOGIC := '1';
wren_a : in STD_LOGIC := '0';
q_a : out STD_LOGIC_VECTOR (data_width-1 DOWNTO 0);
cs_a : in std_logic := '1';
address_b : in STD_LOGIC_VECTOR (addr_width-1 DOWNTO 0) := (others => '0');
data_b : in STD_LOGIC_VECTOR (data_width-1 DOWNTO 0) := (others => '0');
enable_b : in STD_LOGIC := '1';
wren_b : in STD_LOGIC := '0';
q_b : out STD_LOGIC_VECTOR (data_width-1 DOWNTO 0);
cs_b : in std_logic := '1'
);
end entity;
ARCHITECTURE SYN OF dpram IS
BEGIN
ram : work.dpram_dif generic map(addr_width,data_width,addr_width,data_width,mem_init_file)
port map(clock,address_a,data_a,enable_a,wren_a,q_a,cs_a,address_b,data_b,enable_b,wren_b,q_b,cs_b);
END SYN;
--------------------------------------------------------------
-- Dual port Block RAM different parameters on ports
--------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.altera_mf_components.all;
entity dpram_dif is
generic (
addr_width_a : integer := 8;
data_width_a : integer := 8;
addr_width_b : integer := 8;
data_width_b : integer := 8;
mem_init_file : string := " "
);
PORT
(
clock : in STD_LOGIC;
address_a : in STD_LOGIC_VECTOR (addr_width_a-1 DOWNTO 0);
data_a : in STD_LOGIC_VECTOR (data_width_a-1 DOWNTO 0) := (others => '0');
enable_a : in STD_LOGIC := '1';
wren_a : in STD_LOGIC := '0';
q_a : out STD_LOGIC_VECTOR (data_width_a-1 DOWNTO 0);
cs_a : in std_logic := '1';
address_b : in STD_LOGIC_VECTOR (addr_width_b-1 DOWNTO 0) := (others => '0');
data_b : in STD_LOGIC_VECTOR (data_width_b-1 DOWNTO 0) := (others => '0');
enable_b : in STD_LOGIC := '1';
wren_b : in STD_LOGIC := '0';
q_b : out STD_LOGIC_VECTOR (data_width_b-1 DOWNTO 0);
cs_b : in std_logic := '1'
);
end entity;
ARCHITECTURE SYN OF dpram_dif IS
signal q0 : std_logic_vector((data_width_a - 1) downto 0);
signal q1 : std_logic_vector((data_width_b - 1) downto 0);
BEGIN
q_a<= q0 when cs_a = '1' else (others => '1');
q_b<= q1 when cs_b = '1' else (others => '1');
altsyncram_component : altsyncram
GENERIC MAP (
address_reg_b => "CLOCK1",
clock_enable_input_a => "NORMAL",
clock_enable_input_b => "NORMAL",
clock_enable_output_a => "BYPASS",
clock_enable_output_b => "BYPASS",
indata_reg_b => "CLOCK1",
intended_device_family => "Cyclone V",
lpm_type => "altsyncram",
numwords_a => 2**addr_width_a,
numwords_b => 2**addr_width_b,
operation_mode => "BIDIR_DUAL_PORT",
outdata_aclr_a => "NONE",
outdata_aclr_b => "NONE",
outdata_reg_a => "UNREGISTERED",
outdata_reg_b => "UNREGISTERED",
power_up_uninitialized => "FALSE",
read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ",
read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ",
init_file => mem_init_file,
widthad_a => addr_width_a,
widthad_b => addr_width_b,
width_a => data_width_a,
width_b => data_width_b,
width_byteena_a => 1,
width_byteena_b => 1,
wrcontrol_wraddress_reg_b => "CLOCK1"
)
PORT MAP (
address_a => address_a,
address_b => address_b,
clock0 => clock,
clock1 => clock,
clocken0 => enable_a,
clocken1 => enable_b,
data_a => data_a,
data_b => data_b,
wren_a => wren_a and cs_a,
wren_b => wren_b and cs_b,
q_a => q0,
q_b => q1
);
END SYN;
--------------------------------------------------------------
-- Dual port Block RAM different parameters and clocks on ports
--------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.altera_mf_components.all;
entity dpram_difclk is
generic (
addr_width_a : integer := 8;
data_width_a : integer := 8;
addr_width_b : integer := 8;
data_width_b : integer := 8;
mem_init_file : string := " "
);
PORT
(
clk_a : in STD_LOGIC;
clk_b : in STD_LOGIC;
address_a : in STD_LOGIC_VECTOR (addr_width_a-1 DOWNTO 0);
data_a : in STD_LOGIC_VECTOR (data_width_a-1 DOWNTO 0) := (others => '0');
enable_a : in STD_LOGIC := '1';
wren_a : in STD_LOGIC := '0';
q_a : out STD_LOGIC_VECTOR (data_width_a-1 DOWNTO 0);
cs_a : in std_logic := '1';
address_b : in STD_LOGIC_VECTOR (addr_width_b-1 DOWNTO 0) := (others => '0');
data_b : in STD_LOGIC_VECTOR (data_width_b-1 DOWNTO 0) := (others => '0');
enable_b : in STD_LOGIC := '1';
wren_b : in STD_LOGIC := '0';
q_b : out STD_LOGIC_VECTOR (data_width_b-1 DOWNTO 0);
cs_b : in std_logic := '1'
);
end entity;
ARCHITECTURE SYN OF dpram_difclk IS
signal q0 : std_logic_vector((data_width_a - 1) downto 0);
signal q1 : std_logic_vector((data_width_b - 1) downto 0);
BEGIN
q_a<= q0 when cs_a = '1' else (others => '1');
q_b<= q1 when cs_b = '1' else (others => '1');
altsyncram_component : altsyncram
GENERIC MAP (
address_reg_b => "CLOCK1",
clock_enable_input_a => "NORMAL",
clock_enable_input_b => "NORMAL",
clock_enable_output_a => "BYPASS",
clock_enable_output_b => "BYPASS",
indata_reg_b => "CLOCK1",
intended_device_family => "Cyclone V",
lpm_type => "altsyncram",
numwords_a => 2**addr_width_a,
numwords_b => 2**addr_width_b,
operation_mode => "BIDIR_DUAL_PORT",
outdata_aclr_a => "NONE",
outdata_aclr_b => "NONE",
outdata_reg_a => "UNREGISTERED",
outdata_reg_b => "UNREGISTERED",
power_up_uninitialized => "FALSE",
read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ",
read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ",
init_file => mem_init_file,
widthad_a => addr_width_a,
widthad_b => addr_width_b,
width_a => data_width_a,
width_b => data_width_b,
width_byteena_a => 1,
width_byteena_b => 1,
wrcontrol_wraddress_reg_b => "CLOCK1"
)
PORT MAP (
address_a => address_a,
address_b => address_b,
clock0 => clk_a,
clock1 => clk_b,
clocken0 => enable_a,
clocken1 => enable_b,
data_a => data_a,
data_b => data_b,
wren_a => wren_a and cs_a,
wren_b => wren_b and cs_b,
q_a => q0,
q_b => q1
);
END SYN;

314
rtl/common/ide.v Normal file
View File

@@ -0,0 +1,314 @@
/*
* Copyright (c) 2020, Alexey Melnikov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
module ide
(
input clk,
input rst_n,
output reg irq,
output drq,
input use_fast, // 1 - supports fast read mode
output no_data, // pause for system when no data is available in fast mode
output [1:0] drive_en,
input [3:0] io_address,
input io_read,
output reg [31:0] io_readdata,
input io_write,
input [31:0] io_writedata,
input io_32,
output reg io_wait,
output reg [2:0] request,
input [3:0] mgmt_address,
input mgmt_write,
input [15:0] mgmt_writedata,
input mgmt_read,
output reg [15:0] mgmt_readdata
);
assign drq = status[3];
assign drive_en = present;
//------------------------------------------------------------------------------
wire io_wr = io_write & |present;
//------------------------------------------------------------------------------
always @(posedge clk) if(io_read) begin
if(!present) io_readdata <= 32'hFFFFFFFF;
else begin
case(io_address)
0: io_readdata <= status[3] ? {buf_q[31:16], (~io_32 & io_cnt[0]) ? buf_q[31:16] : buf_q[15:0]} : 32'd0;
1: io_readdata <= error;
2: io_readdata <= (hob ? sector_count[15:8] : sector_count[7:0] );
3: io_readdata <= (hob ? sector[15:8] : sector[7:0] );
4: io_readdata <= (hob ? cylinder[23:16] : cylinder[7:0] );
5: io_readdata <= (hob ? cylinder[31:24] : cylinder[15:8] );
6: io_readdata <= drv_addr;
7: io_readdata <= status;
14: io_readdata <= status;
15: io_readdata <= { 2'b10, ~drv_addr[3:0], ~drv_addr[4], drv_addr[4]};
default: io_readdata <= 0;
endcase
end
end
//------------------------------------------------------------------------------
reg [7:0] features;
always @(posedge clk) begin
if(~rst_n) features <= 8'h00;
else if(io_wr && io_address == 1) features <= io_writedata[7:0];
end
reg [15:0] blk_size;
always @(posedge clk) begin
if(~rst_n) blk_size <= 16'h0000;
else if(mgmt_write && mgmt_address == 0) blk_size <= {mgmt_writedata[7:0], 8'h00};
else if(mgmt_write && mgmt_address == 4 && blk_size[15]) blk_size <= mgmt_writedata[15:0];
end
reg [7:0] error;
always @(posedge clk) begin
if(~rst_n) error <= 8'h00;
else if(mgmt_write && mgmt_address == 0) error <= mgmt_writedata[15:8];
end
reg [15:0] sector_count;
always @(posedge clk) begin
if(~rst_n) sector_count <= 16'd1;
else if(mgmt_write && mgmt_address == 1) sector_count[7:0] <= mgmt_writedata[7:0];
else if(mgmt_write && mgmt_address == 3) sector_count[15:8] <= mgmt_writedata[7:0];
else if(io_wr && io_address == 2) sector_count <= {sector_count[7:0], io_writedata[7:0]};
end
reg [15:0] sector;
always @(posedge clk) begin
if(~rst_n) sector <= 16'd1;
else if(mgmt_write && mgmt_address == 1) sector[7:0] <= mgmt_writedata[15:8];
else if(mgmt_write && mgmt_address == 3) sector[15:8] <= mgmt_writedata[15:8];
else if(io_wr && io_address == 3) sector <= {sector[7:0],io_writedata[7:0]};
end
reg [31:0] cylinder;
always @(posedge clk) begin
if(~rst_n) cylinder <= 32'hFFFFFFFF;
else if(mgmt_write && mgmt_address == 2) cylinder[15:0] <= mgmt_writedata[15:0];
else if(mgmt_write && mgmt_address == 4) cylinder[31:16] <= mgmt_writedata[15:0];
else if(io_wr && io_address == 4) {cylinder[23:16], cylinder[7:0] } <= {cylinder[7:0], io_writedata[7:0]};
else if(io_wr && io_address == 5) {cylinder[31:24], cylinder[15:8]} <= {cylinder[15:8], io_writedata[7:0]};
end
reg [7:0] drv_addr;
always @(posedge clk) begin
if(~rst_n) drv_addr <= 8'd0;
else if(mgmt_write && mgmt_address == 5) drv_addr <= mgmt_writedata[7:0];
else if(io_wr && io_address == 6) drv_addr <= io_writedata[7:0];
end
reg [7:0] cmd;
always @(posedge clk) begin
if(~rst_n) cmd <= 8'd0;
else if(io_wr && io_address == 7) cmd <= io_writedata[7:0];
end
reg [7:0] status = 0;
always @(posedge clk) begin
if(reset) status <= 8'h80;
else if(mgmt_write && mgmt_address == 5) status <= {mgmt_writedata[15:14],1'b0,mgmt_writedata[12:11],2'b00,mgmt_writedata[8]};
else if(io_wr && io_address == 7) status <= 8'h80;
else if(io_done & drq & last_read) status <= 8'h40;
else if(io_done & drq) status <= 8'h80;
end
reg last_read = 0;
always @(posedge clk) begin
if(reset) last_read <= 0;
else if(mgmt_write && mgmt_address == 5) last_read <= mgmt_writedata[9];
else if(io_done & drq) last_read <= 0;
end
reg fast_read = 0;
always @(posedge clk) begin
if(reset) fast_read <= 0;
else if(mgmt_write && mgmt_address == 5) fast_read <= mgmt_writedata[13];
else if(io_done & drq) fast_read <= 0;
end
always @(posedge clk) begin
if(~rst_n) io_wait <= 1'd0;
else if(sw_reset) io_wait <= use_wait;
else if(mgmt_write && mgmt_address == 5) io_wait <= 1'd0;
else if(io_wr && io_address == 7) io_wait <= use_wait;
else if(io_done & drq) io_wait <= use_wait;
end
always @(posedge clk) begin
if(reset) request <= 3'b110; // reset
else if(mgmt_write && mgmt_address == 5) request <= 3'b000;
else if(io_wr && io_address == 7) request <= 3'b100; // new command
else if(io_done & drq & ~last_read) request <= 3'b101; // data send/recv
end
always @(posedge clk) begin
if(reset) irq <= 1'b0;
else if(mgmt_write && mgmt_address == 5 && mgmt_writedata[10] && ~disable_irq) irq <= 1'b1;
else if((io_read | io_wr) && io_address == 7) irq <= 1'b0;
end
always @(posedge clk) begin
case(mgmt_address)
0: mgmt_readdata <= {features, 6'd0, use_fast, io_done};
1: mgmt_readdata <= {sector[7:0], sector_count[7:0]};
2: mgmt_readdata <= {cylinder[15:0]};
3: mgmt_readdata <= {sector[15:8], sector_count[15:8]};
4: mgmt_readdata <= {cylinder[31:16]};
5: mgmt_readdata <= {cmd, drv_addr};
default: mgmt_readdata <= (mgmt_cnt[0]) ? buf_readdata[31:16] : buf_readdata[15:0];
endcase
end
//------------------------------------------------------------------------------
reg [1:0] hob_ena = 0;
reg [1:0] present = 0;
always @(posedge clk) begin
if(mgmt_write && mgmt_address == 6 && mgmt_writedata[3]) {hob_ena[0], present[0]} <= mgmt_writedata[1:0];
if(mgmt_write && mgmt_address == 6 && mgmt_writedata[7]) {hob_ena[1], present[1]} <= mgmt_writedata[5:4];
end
reg use_wait = 0;
always @(posedge clk) begin
if(mgmt_write && mgmt_address == 6 && mgmt_writedata[9]) use_wait <= mgmt_writedata[8];
end
//------------------------------------------------------------------------------
wire reset = ~rst_n | sw_reset;
reg disable_irq;
always @(posedge clk) begin
if(reset) disable_irq <= 1'b0;
else if(io_wr && io_address == 14) disable_irq <= io_writedata[1];
end
reg sw_reset;
always @(posedge clk) begin
if(~rst_n) sw_reset <= 1'b0;
else if(io_wr && io_address == 14) sw_reset <= io_writedata[2];
end
reg hob_pre;
always @(posedge clk) begin
if(reset) hob_pre <= 1'b0;
else if(io_wr && io_address == 14) hob_pre <= io_writedata[7];
end
reg hob;
always @(posedge clk) hob <= hob_pre & hob_ena[drv_addr[4]];
//------------------------------------------------------------------------------
wire write_data_io = io_wr && io_address == 0 && drq;
wire read_data_io = io_read && io_address == 0 && drq;
wire io_done = (blk_size && io_cnt >= blk_size);
reg [13:0] io_cnt;
wire io_stb = read_data_io | write_data_io;
always @(posedge clk) begin
reg old_stb, r_32;
old_stb <= io_stb;
if(io_stb) r_32 <= io_32;
if(reset) io_cnt <= 0;
else if(mgmt_write && mgmt_address == 5) io_cnt <= 0;
else if(old_stb & ~io_stb) io_cnt <= io_cnt + 1'd1 + r_32;
end
reg [13:0] mgmt_cnt;
always @(posedge clk) begin
reg old_wr, old_rd;
old_wr <= mgmt_write;
old_rd <= mgmt_read;
if((old_wr & ~mgmt_write) | (old_rd & ~mgmt_read)) begin
if(&mgmt_address) mgmt_cnt <= mgmt_cnt + 1'd1;
else mgmt_cnt <= 0;
end
if(~rst_n) mgmt_cnt <= 0;
end
wire n_data = (mgmt_cnt[13:1] <= io_cnt[13:1]) && drq && fast_read;
reg [1:0] n_data_r;
assign no_data = n_data || n_data_r;
always @(posedge clk) n_data_r <= {n_data_r[0], n_data};
wire [31:0] buf_readdata;
wire [31:0] buf_q;
dpram #(12,16) io_buf0
(
.clock(clk),
.address_a(mgmt_cnt[12:1]),
.data_a(mgmt_writedata),
.wren_a(mgmt_write & &mgmt_address & ~mgmt_cnt[0]),
.q_a(buf_readdata[15:0]),
.address_b(io_cnt[12:1]),
.data_b(io_writedata[15:0]),
.wren_b(write_data_io & (io_32 | ~io_cnt[0])),
.q_b(buf_q[15:0])
);
dpram #(12,16) io_buf1
(
.clock(clk),
.address_a(mgmt_cnt[12:1]),
.data_a(mgmt_writedata),
.wren_a(mgmt_write & &mgmt_address & mgmt_cnt[0]),
.q_a(buf_readdata[31:16]),
.address_b(io_cnt[12:1]),
.data_b(io_32 ? io_writedata[31:16] : io_writedata[15:0]),
.wren_b(write_data_io & (io_32 | io_cnt[0])),
.q_b(buf_q[31:16])
);
//------------------------------------------------------------------------------
endmodule