OpenCores
URL https://opencores.org/ocsvn/s80186/s80186/trunk

Subversion Repositories s80186

[/] [s80186/] [trunk/] [rtl/] [ModRMDecode.sv] - Rev 2

Compare with Previous | Blame | View Log

// Copyright Jamie Iles, 2017
//
// This file is part of s80x86.
//
// s80x86 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.
//
// s80x86 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 s80x86.  If not, see <http://www.gnu.org/licenses/>.

module ModRMDecode(input logic clk,
                   input logic reset,
                   // Control.
                   input logic start,
                   output logic busy,
                   output logic complete,
                   input logic clear,
                   // Results
                   output logic [15:0] effective_address,
                   output logic [2:0] regnum,
                   output logic rm_is_reg,
                   output logic [2:0] rm_regnum,
                   output logic bp_as_base,
                   // Registers.
                   output logic [2:0] reg_sel[2],
                   input logic [15:0] regs[2],
                   // Fifo Read Port.
                   output logic fifo_rd_en,
                   input logic [7:0] fifo_rd_data,
                   input logic fifo_empty,
                   // Immediates
                   output logic immed_start,
                   input logic immed_complete,
                   output logic immed_is_8bit,
                   input logic [15:0] immediate);

reg [7:0] _modrm;
reg _modrm_byte_read;
reg _started;
reg _registers_fetched;
reg [15:0] _cached_effective_address;
reg [15:0] _effective_address;
wire _has_address = _mod != 2'b11;
wire _fifo_valid = start & ~_modrm_byte_read & ~fifo_empty;
wire [1:0] _mod = _fifo_valid ? fifo_rd_data[7:6] : _modrm[7:6];
wire [2:0] _reg = _fifo_valid ? fifo_rd_data[5:3] : _modrm[5:3];
wire [2:0] _rm  = _fifo_valid ? fifo_rd_data[2:0] : _modrm[2:0];
wire _has_immediate = (_rm == 3'b110 && _mod == 2'b00) || ^_mod;

assign busy = (start | _started) & ~complete;
assign complete = reset ? 1'b0 :
    (_modrm_byte_read || _fifo_valid) &&
    (!_has_address || _registers_fetched) &&
    (!_has_immediate || immed_complete);
assign immed_start = _has_immediate && _modrm_byte_read;
assign immed_is_8bit = _mod == 2'b01;
assign effective_address = complete ? _effective_address : _cached_effective_address;

always_comb begin
    case (_mod)
    2'b00: bp_as_base = (_rm == 3'b010 || _rm == 3'b011);
    2'b01: bp_as_base = (_rm == 3'b010 || _rm == 3'b011 || _rm == 3'b110);
    2'b10: bp_as_base = (_rm == 3'b010 || _rm == 3'b011 || _rm == 3'b110);
    default: bp_as_base = 1'b0;
    endcase
end

always_ff @(posedge clk or posedge reset) begin
    if (reset)
        _started <= 1'b0;
    else if (complete)
        _started <= 1'b0;
    else if (start)
        _started <= 1'b1;
end

always_ff @(posedge clk or posedge reset)
    if (reset)
        _registers_fetched <= 1'b0;
    else if (complete)
        _registers_fetched <= 1'b0;
    else if (~fifo_empty & start & ~_modrm_byte_read)
        _registers_fetched <= 1'b1;

always_comb begin
    case (_rm)
    3'b000, 3'b001, 3'b111: reg_sel[0] = BX;
    3'b010, 3'b011, 3'b110: reg_sel[0] = BP;
    3'b100: reg_sel[0] = SI;
    3'b101: reg_sel[0] = DI;
    endcase

    case (_rm)
    3'b000, 3'b010: reg_sel[1] = SI;
    3'b001, 3'b011: reg_sel[1] = DI;
    default: reg_sel[1] = 0;
    endcase
end

always_comb begin
    regnum = _reg;
    rm_regnum = _rm;
    rm_is_reg = 1'b0;
    _effective_address = 16'b0;

    case (_mod)
    2'b00: begin
        case (_rm)
        3'b000, 3'b001, 3'b010, 3'b011: _effective_address = regs[0] + regs[1];
        3'b100, 3'b101, 3'b111: _effective_address = regs[0];
        3'b110: _effective_address = immediate;
        endcase
    end
    2'b01, 2'b10: begin
        case (_rm)
        3'b000, 3'b001, 3'b010, 3'b011: _effective_address = regs[0] + regs[1] + immediate;
        3'b100, 3'b101, 3'b110, 3'b111: _effective_address = regs[0] + immediate;
        endcase
    end
    2'b11: begin
        rm_regnum = _rm;
        rm_is_reg = 1'b1;
    end
    endcase
end

always_ff @(posedge clk)
    if (complete)
        _cached_effective_address <= _effective_address;

always_ff @(posedge clk or posedge reset)
    if (reset)
        _modrm_byte_read <= 1'b0;
    else if (complete)
        _modrm_byte_read <= 1'b0;
    else if (fifo_rd_en)
        _modrm_byte_read <= 1;

assign fifo_rd_en = ~fifo_empty & start & ~_modrm_byte_read;

always_ff @(posedge clk or posedge reset)
    if (reset)
        _modrm <= 8'b0;
    else if (clear)
        _modrm <= 8'b0;
    else if (~fifo_empty & start & ~_modrm_byte_read)
        _modrm <= fifo_rd_data;

endmodule

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.