Advice on 2D Surface Terrain Generation Using Noise

Not a super in depth question, just looking for some advice on how to approach this section of terrain generation.

Current Script

Currently, I have a script which generates the ‘underworld’ terrain using Cellular Automata. Here is a screenshot of a sample generation:

I have a map array which consists of either a 0 or 1 for each coordinate within the map - here is a sample:

// Filling tiles and creating cave
		for (int x = 0; x < width; x++)
		{
			for (int y = 0; y < height; y++)
			{
				if (x == 0 || x == width - 1 || y == 0) // Add  || y == height - 1 to remove surface openings
				{
					map[x, y] = 1; // Tiles around the edge are always filled
				}
				else
				{
					map[x, y] = (pseudoRandom.Next(0, 100) < caveFillPercent) ? 1 : 0; // If less than fillPercent, fill. Otherwise leave blank (cave)
				}
			}
		}

If the map array coordinate is then equal to 1, the tile to spawn is then calculated on a separate section of the script using Perlin Noise - here is a sample:

if (map[xx, yy] >= 1) // If map index is a filled tile (not empty)
				{
					GameObject selectedTile = null;

					selectedTile = stoneTile;
					map[xx, yy] = 1;

					// Adjust noise values according to rarity of each ore
					float DiamondOreNoise = Mathf.PerlinNoise((x / 4) + seed, (y / 4) + seed);
					float GoldOreNoise = Mathf.PerlinNoise((x / 5) + seed, (y / 5) + seed);
					float IronOreNoise = Mathf.PerlinNoise((x / 8) + seed, (y / 8) + seed);
					float CoalOreNoise = Mathf.PerlinNoise((x / 10) + seed, (y / 10) + seed);
    
					if (cavernBiome)
					{
						if (DiamondOreNoise > 0.92)
						{
							selectedTile = diamondTile;
						}
						if (GoldOreNoise > 0.90)
						{
							selectedTile = goldTile;
						}
						if (IronOreNoise > 0.86)
						{
							selectedTile = ironTile;
						}
						if (CoalOreNoise > 0.80)
						{
							selectedTile = coalTile;
						}
					}

					if (hellBiome)
					{
						selectedTile = obsidianTile;
					}

					GameObject newTile;
					newTile = Instantiate(selectedTile, new Vector2(x, (y - height) + 1), Quaternion.identity);
					newTile.transform.SetParent(gameObject.transform, false);
				}

My Question

My question is: when generating the ‘surface’ terrain with Perlin Noise, what would be the best - or most efficient - way to approach this?

Would the best approach utilize the ‘map[x, y]’ array somehow in conjunction with a new ‘surface Perlin Noise’? If so, how would I approach this?

Or would the best approach even be starting in another script, completely separate to this?

Any advice would be greatly appreciated!

Your question is very vague. It is not clear if the game is Terraria-styled side scroller or top-down dungeon crawler/miner game.

Generating surface terrain for Terraria style is totally different to generating terrain to topdown game.

For side view i think a noise wave (or sum of different frequency noise waves) to determine terrain height is good way, then sporadically create trees etc. on the surface.
For topdown view you could use the cellular automata approach to generate patches of forests/grass/sand etc…