function [obj, aliases] = createFromHWDeviceRegistryObject(hw)
% CREATEFROMHWDEVICEREGISTRYOBJECT converts the specified
% RTW.HWDeviceRegistry object to a targetrepository.physical.Microprocessor
% or targetrepository.physical.FPGA instance

%   Copyright 2018-2021 The MathWorks, Inc.

 % Special case for FPGA
 
    aliases = target.internal.Alias.empty();
    
    if isequal(hw.Vendor, 'ASIC/FPGA')
        fpga = target.internal.create('FPGA');
        fpga.Name = hw.Type;
        fpga.Grandfathered = hw.Grandfathered;
        fpga.Platform = target.internal.compatibility.HardwareImplementationPlatform.Production;
        cellfun(@(a) fpga.AliasList.add(a), hw.Alias);
        
        for i=1:length(hw.Alias)
            aliases(i) = target.internal.create('Alias', 'Name', hw.Alias{i}, 'For', fpga);
        end
        
        obj = fpga;
        return;
    end

    % Create new Microprocessor
    microprocessor = target.internal.create('Processor');
    microprocessor.Manufacturer = hw.Vendor;
    microprocessor.Name = hw.Type;
    microprocessor.Grandfathered = hw.Grandfathered;
    cellfun(@(a) microprocessor.AliasList.add(a), hw.Alias);        
    for i=1:length(hw.Alias)
        aliases(i) = target.internal.create('Alias', 'Name', hw.Alias{i}, 'For', microprocessor);
    end
    impl = target.internal.create('LanguageImplementation');
    impl.initialize();

    impl.DataTypes.Char.Size = hw.BitPerChar;
    impl.DataTypes.Short.Size = hw.BitPerShort;
    impl.DataTypes.Int.Size = hw.BitPerInt;
    impl.DataTypes.Long.Size = hw.BitPerLong;

    if hw.LongLongMode
        impl.DataTypes.LongLong.IsSupported = true;
        impl.DataTypes.LongLong.Size = int32(hw.BitPerLongLong);
    else
        impl.DataTypes.LongLong.IsSupported = false;
        impl.DataTypes.LongLong.Size = 64;
    end

    impl.DataTypes.Float.Size = hw.BitPerFloat;
    impl.DataTypes.Double.Size = hw.BitPerDouble;
    impl.DataTypes.Pointer.Size = hw.BitPerPointer;
    impl.DataTypes.SizeT.Size = hw.BitPerSizeT;
    impl.DataTypes.PtrDiffT.Size = hw.BitPerPtrDiffT;

    impl.Name = [hw.Vendor '-' hw.Type];
    impl.WordSize = hw.WordSize;

    switch hw.Endianess
        case 'LittleEndian'
            impl.Endianess = target.internal.Endianess.Little;
        case 'BigEndian'
            impl.Endianess = target.internal.Endianess.Big;
        otherwise
            impl.Endianess = target.internal.Endianess.Unspecified;
    end

    impl.IntegerDivisionRounding = target.internal.numerical.IntegerRounding.(hw.IntDivRoundTo);
    
    switch hw.LargestAtomicInteger
        case 'Char'
            impl.AtomicIntegerSize = impl.DataTypes.Char.Size;
        case 'Short'
            impl.AtomicIntegerSize = impl.DataTypes.Short.Size;
        case 'Int'
            impl.AtomicIntegerSize = impl.DataTypes.Int.Size;
        case 'Long'
            impl.AtomicIntegerSize = impl.DataTypes.Long.Size;
        case 'LongLong'
            impl.AtomicIntegerSize = impl.DataTypes.LongLong.Size;
    end
    
    switch hw.LargestAtomicFloat
        case 'Float'
            impl.AtomicFloatSize = impl.DataTypes.Float.Size;
        case 'Double'
            impl.AtomicFloatSize = impl.DataTypes.Double.Size;
        case 'None'
            impl.AtomicFloatSize = 0;
    end    

    impl.ArithmeticSignedIntegerRightShift = hw.ShiftRightIntArith; 

    impl.Grandfathered = hw.Grandfathered;

    params = RTW.HWProp.getHardwareParams();
    for i = 1:length(params)
        param = params{i}; 

        if hw.getEnabled(param)
            impl.EnabledParams.add(param);
        end

        if ~hw.Visible(RTW.HWProp.(param))
            impl.InvisibleParams.add(param);
        end
    end

    containsProd = any(strcmp(hw.Platform, 'Prod'));
    containsTarget = any(strcmp(hw.Platform, 'Target'));

    if containsProd && containsTarget
        microprocessor.Platform = target.internal.compatibility.HardwareImplementationPlatform.All;
    elseif containsProd
        microprocessor.Platform = target.internal.compatibility.HardwareImplementationPlatform.Production;
    elseif containsTarget
        microprocessor.Platform = target.internal.compatibility.HardwareImplementationPlatform.Target;                
    else
        assert(false, 'Hardware should target prod or target or both');
    end

    microprocessor.LanguageImplementations = impl;
    
    obj = microprocessor;
end
