| 1 | unit I8253;
|
|---|
| 2 |
|
|---|
| 3 | interface
|
|---|
| 4 |
|
|---|
| 5 | uses
|
|---|
| 6 | Classes, SysUtils;
|
|---|
| 7 |
|
|---|
| 8 | type
|
|---|
| 9 | TCounterMode = 0..5;
|
|---|
| 10 | TReadLoad = (rlCounterLatching, rlMostByteOnly,
|
|---|
| 11 | rlLeastByteOnly, rlLeastThenMostByte);
|
|---|
| 12 | TByteKind = (bkLeast, bkMost);
|
|---|
| 13 | TOutputEvent = procedure (Output: Boolean) of object;
|
|---|
| 14 |
|
|---|
| 15 | { TCounter }
|
|---|
| 16 |
|
|---|
| 17 | TCounter = record
|
|---|
| 18 | private
|
|---|
| 19 | FOnOutputChange: TOutputEvent;
|
|---|
| 20 | public
|
|---|
| 21 | ResetValue: Word;
|
|---|
| 22 | Value: Word;
|
|---|
| 23 | Mode: TCounterMode;
|
|---|
| 24 | Bcd: Boolean;
|
|---|
| 25 | ReadLoad: TReadLoad;
|
|---|
| 26 | ReadLoadByteKind: TByteKind;
|
|---|
| 27 | StorageValue: Word;
|
|---|
| 28 | procedure Load(Data: Byte);
|
|---|
| 29 | function Read: Byte;
|
|---|
| 30 | procedure Control(Data: Byte);
|
|---|
| 31 | procedure CountDown;
|
|---|
| 32 | property OnOutputChange: TOutputEvent read FOnOutputChange
|
|---|
| 33 | write FOnOutputChange;
|
|---|
| 34 | end;
|
|---|
| 35 |
|
|---|
| 36 | { T8253 }
|
|---|
| 37 |
|
|---|
| 38 | T8253 = class
|
|---|
| 39 | Counters: array[0..2] of TCounter;
|
|---|
| 40 | procedure Write(Address: Word; Data: Byte);
|
|---|
| 41 | function Read(Address: Word): Byte;
|
|---|
| 42 | constructor Create;
|
|---|
| 43 | end;
|
|---|
| 44 |
|
|---|
| 45 |
|
|---|
| 46 | implementation
|
|---|
| 47 |
|
|---|
| 48 | { TCounter }
|
|---|
| 49 |
|
|---|
| 50 | procedure TCounter.Load(Data: Byte);
|
|---|
| 51 | begin
|
|---|
| 52 | case ReadLoad of
|
|---|
| 53 | rlCounterLatching: ;
|
|---|
| 54 | rlLeastByteOnly: Value := (ResetValue and $ff00) or Data;
|
|---|
| 55 | rlMostByteOnly: Value := (ResetValue and $ff) or (Data shl 8);
|
|---|
| 56 | rlLeastThenMostByte: begin
|
|---|
| 57 | case ReadLoadByteKind of
|
|---|
| 58 | bkLeast: begin
|
|---|
| 59 | Value := (Value and $ff00) or Data;
|
|---|
| 60 | ReadLoadByteKind := bkMost;
|
|---|
| 61 | end;
|
|---|
| 62 | bkMost: begin
|
|---|
| 63 | Value := (Value and $ff) or (Data shl 8);
|
|---|
| 64 | ReadLoadByteKind := bkLeast;
|
|---|
| 65 | end;
|
|---|
| 66 | end;
|
|---|
| 67 | end;
|
|---|
| 68 | end;
|
|---|
| 69 | end;
|
|---|
| 70 |
|
|---|
| 71 | function TCounter.Read: Byte;
|
|---|
| 72 | begin
|
|---|
| 73 | case ReadLoad of
|
|---|
| 74 | rlCounterLatching: begin
|
|---|
| 75 | case ReadLoadByteKind of
|
|---|
| 76 | bkLeast: begin
|
|---|
| 77 | Result := StorageValue and $ff;
|
|---|
| 78 | ReadLoadByteKind := bkMost;
|
|---|
| 79 | end;
|
|---|
| 80 | bkMost: begin
|
|---|
| 81 | Result := (StorageValue shr 8) and $ff;
|
|---|
| 82 | ReadLoadByteKind := bkLeast;
|
|---|
| 83 | end;
|
|---|
| 84 | end;
|
|---|
| 85 | end;
|
|---|
| 86 | else begin
|
|---|
| 87 | case ReadLoadByteKind of
|
|---|
| 88 | bkLeast: begin
|
|---|
| 89 | Result := Value and $ff;
|
|---|
| 90 | ReadLoadByteKind := bkMost;
|
|---|
| 91 | end;
|
|---|
| 92 | bkMost: begin
|
|---|
| 93 | Result := (Value shr 8) and $ff;
|
|---|
| 94 | ReadLoadByteKind := bkLeast;
|
|---|
| 95 | end;
|
|---|
| 96 | end;
|
|---|
| 97 | end;
|
|---|
| 98 | end;
|
|---|
| 99 | end;
|
|---|
| 100 |
|
|---|
| 101 | procedure TCounter.Control(Data: Byte);
|
|---|
| 102 | begin
|
|---|
| 103 | ReadLoad := TReadLoad((Data and $30) shr 4);
|
|---|
| 104 | case ReadLoad of
|
|---|
| 105 | rlCounterLatching: StorageValue := Value;
|
|---|
| 106 | rlMostByteOnly: ReadLoadByteKind := bkMost;
|
|---|
| 107 | rlLeastByteOnly: ReadLoadByteKind := bkLeast;
|
|---|
| 108 | rlLeastThenMostByte: ReadLoadByteKind := bkLeast;
|
|---|
| 109 | end;
|
|---|
| 110 | Mode := (Data and $e) shr 1;
|
|---|
| 111 | Bcd := (Data and 1) > 0;
|
|---|
| 112 | end;
|
|---|
| 113 |
|
|---|
| 114 | procedure TCounter.CountDown;
|
|---|
| 115 | begin
|
|---|
| 116 | if Value > 0 then begin
|
|---|
| 117 | Dec(Value);
|
|---|
| 118 | if Value = 0 then begin
|
|---|
| 119 | if Assigned(FOnOutputChange) then
|
|---|
| 120 | FOnOutputChange(True);
|
|---|
| 121 | end;
|
|---|
| 122 | end;
|
|---|
| 123 | end;
|
|---|
| 124 |
|
|---|
| 125 | { T8253 }
|
|---|
| 126 |
|
|---|
| 127 | procedure T8253.Write(Address: Word; Data: Byte);
|
|---|
| 128 | var
|
|---|
| 129 | CounterNum: Byte;
|
|---|
| 130 | begin
|
|---|
| 131 | case Address of
|
|---|
| 132 | 0: Counters[0].Load(Data);
|
|---|
| 133 | 1: Counters[1].Load(Data);
|
|---|
| 134 | 2: Counters[2].Load(Data);
|
|---|
| 135 | 3: begin
|
|---|
| 136 | CounterNum := (Data and $c0) shr 6;
|
|---|
| 137 | Counters[CounterNum].Control(Data);
|
|---|
| 138 | end;
|
|---|
| 139 | end;
|
|---|
| 140 | end;
|
|---|
| 141 |
|
|---|
| 142 | function T8253.Read(Address: Word): Byte;
|
|---|
| 143 | begin
|
|---|
| 144 | case Address of
|
|---|
| 145 | 0: Result := Counters[0].Read;
|
|---|
| 146 | 1: Result := Counters[1].Read;
|
|---|
| 147 | 2: Result := Counters[2].Read;
|
|---|
| 148 | 3: Result := 0; // Illegal
|
|---|
| 149 | end;
|
|---|
| 150 | end;
|
|---|
| 151 |
|
|---|
| 152 | constructor T8253.Create;
|
|---|
| 153 | var
|
|---|
| 154 | I: Integer;
|
|---|
| 155 | begin
|
|---|
| 156 | for I := 0 to 2 do
|
|---|
| 157 | Counters[I].Value := 0;
|
|---|
| 158 | end;
|
|---|
| 159 |
|
|---|
| 160 | end.
|
|---|
| 161 |
|
|---|