|
Выпуск 4 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Доброе время суток, уважаемые читатели! В сегодняшнем выпуске мне хотелось бы перейти к поверхностному анализу и начальному планированию TMC 2. Фактически, модели первой части TMC описаны в моей работе, URL на которую я приводил еще в первом выпуске. Можно было, конечно, изложить более подробно и детально в этой рассылке, но я посчитал это бесполезным. Во-первых, мне бы пришлось заимствовать оттуда много материала. Во-вторых, описанные там классы и взаимодействие между ними будут не похожи на то, что я собираюсь делать в TMC 2. Я попытаюсь проводить некоторое сравнение и приводить TMC 1 в качестве примера, а также показывать какие достоинства или недостатки там были по сравнению с TMC 2. Начнем рассмотрение с самого начала, с принципов фон-Неймана. Согласно этих принципов, ЭВМ состоит из Центрального Процессора (ЦП), Памяти и Устройств Ввода-Вывода (УВВ). Это базовый принцип, использованный для построения большинства ПК, известен еще из школьного курса информатики, поэтому мы не будем на нем останавливаться. Интерес представляет среда, которая связывает ЦП, память и УВВ. С физической точки зрения, ЦП в персональном компьютере - это некая микросхема с множеством ножек, которые соединены с другими устройствами. Устройство современного ПК может быть весьма сложным, поэтому мы ограничимся некой моделью, уменьшив реализм, но для наших целей это вполне подойдет. Любые пересылки данных осуществляются с определенной частотой (фиксированной). В каждый момент времени, каждая ножка микропроцессора может быть в одном из двух состояний: 0 или 1 (низкое или высокое напряжение). Для того чтобы одна микросхема успела передать, а другая - принять сигнал, необходимо некоторое время. Обычно весьма небольшое. Время реакции регулируется генератором импульсов (кварцем). Эти устройства управляют временными интервалами, и характеризуются частотой (MHz). Чем выше частота, тем быстрее может происходить передача данных. Например, частота ISA шины - 8 MHz, PCI - 33 MHz. Еще одним важным параметром является количество самих соединенных ножек. Фактически, ширина электрической магистрали определяет количество битов, передаваемых за один такт. Правда, еще необходимо учитывать, что некоторые ножки могут использоваться для синхронизации и проверки корректности данных. Давайте рассмотрим процессор Intel 8086. Он имеет 16-ти (с возможностью маскировки первых или последних 8-ми) разрядную шину данных. Это означает, что он может передавать за один такт 16-ти битное число, либо 8-ми (если это необходимо). В первой версии TMC все передачи данных либо 8-ми, либо 16-ти битные. В современных ПК данные передаются не по одному байту или слову, а целыми пакетами. В связи с этим, во вторую версию закладывается передача данных пакетами. Эту абстракцию выразим классом Packet, который будет иметь следующие методы: Конструктор(Size:integer) Деструктор() getSize():integer getByte(ofs:integer):BYTE setByte(ofs:integer; b:BYTE) Конструктор определяет размер пакета, далее с пакетом можно работать как с набором байт. Деструктор осуществляет уничтожение пакета. getSize() возвращает размер созданного пакета. Методы getByte()/setByte() предназначены для записи и чтения данных пакета. Предполагается, что пакетами будет организован обмен между ЦП и памятью. Тип integer предполагается достаточным для указания адреса байта внутри пакета. Он же определяет максимальный размер пакета. Тип BYTE соответствует одному байту в эмулируемой архитектуре. Следующим фундаментальным понятием является сокет (socket). Это абстракция физического разъема, который присутствует в местах соединения микропроцессора с материнской платой. Его поведение сводится к передаче и приему информации. Он обладает следующими методами (тип conMax - целочисленный, имеющий разрядность, не меньшую адресной шины в эмулируемой архитектуре): BYTEWrite(bpack:BYTE, addr:conMax) BYTERead(addr:conMax, var bpack:BYTE) PacketWrite(var pack:Packet, addr:conMax) PacketRead(addr:conMax, pack:Packet) Первые два метода являются базовыми для отправки/получения байтов. В принципе, можно завести для удобства методы пересылки слова (двух байт) и двойного слова (четырех байт). Вторые два метода производят такие же операции над пакетами. Следующим шагом рассмотрим построение памяти в системе. С одном стороны, для операций с памятью процессор использует линейный адрес ячейки памяти (согласно принципам фон-Неймана). С другой стороны, видов памяти много и в одном адресном пространстве может присутствовать оперативная (ОЗУ), постоянная (ПЗУ) или иная память. Реально, даже оперативная память обычно располагается на нескольких микросхемах (DIMM, SIMM). Поэтому, процессор редко подключается напрямую к памяти, а обычно общается с ней через специальное устройство - контроллер памяти. Эту абстракцию можно представить классом MemoryController. Он обладает тем же интерфейсом, что и Socket (чтение/запись байтов и пакетов), поэтому является его прямым наследником. Задача, которая стоит перед этим классом - перенаправление обращений от процессора к нужным микросхемам памяти. Вряд ли нам понадобиться на практике разбивать память с точностью до микросхем, но разделить память на ОЗУ, ПЗУ, видеопамять представляется полезным. В дальнейшем, под термином Chip будем подразумевать не конкретную микросхему, а область памяти с постоянным на этой области поведением при чтении/записи. Введем класс MemoChipFrame. Он является наследником Socket, потому что имеет тот же интерфейс. Надо отметить, что этот класс опять же не предполагает хранения данных. Он предназначен для "подключения" к нему некоего устройства. Это может быть как RAM или ROM, так и регистры внешнего устройства. Этот класс представляется окном адресного пространства. Именно этими окнами и оперирует MemoryController. Вначале может показаться, что этот класс является ненужным усложнением объектной модели. Я с этим не согласен :). В первой версии TMC такого промежуточного уровня представления не было, и существовал сразу класс, который хранил данные, записываемые в память. Это прекрасно согласуется с использованием памяти в IBM PC (где фактически, в силу архитектуры x86, имеющей отдельное пространство портов, не было устройств, отображаемых в память), но не очень согласуется с принципами построения Macintosh (на базе MC68k), где существует единое адресное пространство, в которое проецируются порты внешних устройств. Не знаю, насколько я вас убедил в необходимости подобного усложнения, но в этом выпуске не хотелось бы пока касаться механизмов мониторинга и супервизорного воздействия на эмулируемую систему, а там тоже есть моменты, которые обосновывают подобный выбор. Следующим классом этой ветви иерархии рассмотрим класс MemoChip. Этот класс является наследником класса MemoChipFrame. Он уже предполагает хранение, записываемых в него данных. MemoChip в полной мере отражает поведение микросхемы ОЗУ. Напоследок, рассмотрим предполагаемый алгоритм обращения к памяти (на примере записи):
На этом хотелось бы закончить сегодняшний выпуск рассылки, спасибо за внимание. Автор рассылки: Виктор Петренко (Top)
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||