Каждая функция, когда вы вызываете ее, должна создавать кадр стека / стек вызовов в стеке, который включает в себя пространство для адреса возврата, любые параметры и любые локальные переменные, которые создаются внутри функции. По крайней мере, кадр активации в вашей ситуации должен содержать адрес возврата кода вызова. Дополнительные данные, которые входят в игру, основаны на том, принимает ли ваша функция параметры и / или создает ли она какие-либо локальные для функции переменные. Ваш стек может выглядеть так:
+------------------+
| Return address |
+------------------+
| Parameter 0 |
+------------------+
| ... |
+------------------+
| Parameter N |
+------------------+
| Local Var 0 |
+------------------+
| ... |
+------------------+
| Local Var N | <--- Top of Stack
+------------------+
Поскольку вы уже используете основную память для стека, именно здесь будет жить кадр активации. Я предполагаю, что ваш процессор имеет указатель стека, который указывает на вершину стека?
Вы могли бы создать два стека, но тогда вам нужно будет решить, куда поместить этот стек и сколько памяти он должен использовать. Вы хотите использовать половину основной памяти для аппаратного стека, а другую половину - для программного стека? Это также означает, что вы ограничиваете количество вложенных (или даже рекурсивных) вызовов, которые вы можете сделать. Вместо этого есть другой метод, который вы можете использовать для экономии памяти. Способ сделать это - включить параметры в вашу функцию после вызова функции (ваш ассемблер должен будет это сделать):
+--------------+
| JMP FUNC | Call the function
+--------------+
| Parameter 0 | <--- return address points here
+--------------+
| ... |
+--------------+
| Parameter N |
+--------------+
| (other code) | <--- after function call, return address should be fixed to point here
+--------------+
Это означает, что вам придется проделать немного больше работы внутри функции, чтобы загрузить параметры. Если вы помните, адрес возврата - это первое значение в стеке. Вы можете загрузить это значение, а затем индексировать его, чтобы загрузить ваши параметры. Как только вы закончите загружать ваши параметры, вам нужно будет настроить значение вашего обратного адреса так, чтобы он указывал на код, который запускается после параметров, которые вы определили.