Subversion Repositories ht46f47_simulator

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
unit HT46F47;
2
 
3
interface
4
 
5
type
6
  Nibble = 0..15;
7
 
8
  TRom = array[0..$FF] of byte;
9
 
3 daniel-mar 10
  TWaitEvent = procedure(milliseconds: integer) of object;
11
 
2 daniel-mar 12
  THT46F47 = class(TObject)
13
  strict private
14
    procedure WaitMs(milliseconds: integer);
15
  strict protected
3 daniel-mar 16
    FOnWait: TWaitEvent;
2 daniel-mar 17
    // ROM
18
    // Registers
19
    FPC: byte;
20
    FReturnAddress: byte;
21
    FPage: Nibble;
22
    FRegA: Nibble;
23
    FRegB: Nibble;
24
    FRegC: Nibble;
25
    FRegD: Nibble;
26
    FCalledOnce: boolean;
27
    // In
28
    FS1: boolean;
29
    FS2: boolean;
30
    FDIn: Nibble;
31
    FAD1: Nibble;
32
    FAD2: Nibble;
33
    // Out
34
    FPWM: Nibble;
35
    FPortOut: Nibble;
36
  public
37
    // ROM
38
    ROM: TRom;
39
    property FROM: TRom read ROM;
40
    // Registers
41
    property PC: byte read FPC;
42
    property ReturnAddress: byte read FReturnAddress;
43
    property Page: Nibble read FPage;
44
    property RegA: Nibble read FRegA;
45
    property RegB: Nibble read FRegB;
46
    property RegC: Nibble read FRegC;
47
    property RegD: Nibble read FRegD;
48
    // In
49
    property S1: boolean read FS1 write FS1;
50
    property S2: boolean read FS2 write FS2;
51
    property DIn: Nibble read FDIn write FDIn;
52
    property AD1: Nibble read FAD1 write FAD1;
53
    property AD2: Nibble read FAD2 write FAD2;
54
    // Out
55
    property PWM: Nibble read FPWM;
56
    property PortOut: Nibble read FPortOut;
57
    // Functions
3 daniel-mar 58
    property OnWait: TWaitEvent read FOnWait write FOnWait;
2 daniel-mar 59
    constructor Create;
60
    procedure Step;
61
    procedure Reset;
62
  end;
63
 
64
implementation
65
 
66
uses
67
  SysUtils, Forms;
68
 
69
{ THT46F47 }
70
 
71
constructor THT46F47.Create;
72
var
73
  i: integer;
74
begin
75
  for i := Low(FROM) to High(FROM) do
76
  begin
77
    ROM[i] := $00;
78
  end;
79
  Reset;
80
end;
81
 
82
procedure THT46F47.Reset;
83
begin
84
  // Internal
85
  FPC := 0;
86
  FReturnAddress := 0;
87
  FPage := 0;
88
  FRegA := 0; // Note: The registers don't seem to be reset in the actual chip, if a "soft reset" is done
89
  FRegB := 0;
90
  FRegC := 0;
91
  FRegD := 0;
92
  FCalledOnce := false;
93
  // In
94
  FS1 := false;
95
  FS2 := false;
96
  FDIn := 0;
97
  FAD1 := 0;
98
  FAD2 := 0;
99
  // Out
100
  FPWM := 0;
101
  FPortOut := 0;
102
end;
103
 
104
procedure THT46F47.Step;
105
var
106
  Instruction: byte;
107
  ProgramCounterNext: Byte;
108
  ProgramCounterCurrent: Byte;
109
begin
110
  Instruction := FROM[FPC];
111
 
112
  ProgramCounterCurrent := FPC;
113
  ProgramCounterNext := FPC+1;
114
 
115
  try
116
    (*
117
    ----------------------------------------------------
118
    Code        Assembly        Alternative     Comment
119
    ----------------------------------------------------
120
    10  LED 0000        PORT 0
121
    11  LED 0001        PORT 1
122
    12  LED 0010        PORT 2
123
    13  LED 0011        PORT 3
124
    14  LED 0100        PORT 4
125
    15  LED 0101        PORT 5
126
    16  LED 0110        PORT 6
127
    17  LED 0111        PORT 7
128
    18  LED 1000        PORT 8
129
    19  LED 1001        PORT 9
130
    1A  LED 1010        PORT 10
131
    1B  LED 1011        PORT 11
132
    1C  LED 1100        PORT 12
133
    1D  LED 1101        PORT 13
134
    1E  LED 1110        PORT 14
135
    1F  LED 1111        PORT 15
136
    *)
137
    if (Instruction >= $10) and (Instruction <= $1F) then
138
    begin
139
      FPortOut := Instruction and $F;
140
    end;
141
 
142
    (*
143
    ----------------------------------------------------
144
    Code        Assembly        Alternative     Comment
145
    ----------------------------------------------------
146
    20  WAIT 1ms
147
    21  WAIT 2ms
148
    22  WAIT 5ms
149
    23  WAIT 10ms
150
    24  WAIT 20ms
151
    25  WAIT 50ms
152
    26  WAIT 100ms
153
    27  WAIT 200ms
154
    28  WAIT 500ms
155
    29  WAIT 1s
156
    2A  WAIT 2s
157
    2B  WAIT 5s
158
    2C  WAIT 10s
159
    2D  WAIT 20s
160
    2E  WAIT 30s
161
    2F  WAIT 60s
162
    *)
163
    case Instruction of
164
      $20: WaitMs(1);      // WAIT 1ms
165
      $21: WaitMs(2);      // WAIT 2ms
166
      $22: WaitMs(5);      // WAIT 5ms
167
      $23: WaitMs(10);     // WAIT 10ms
168
      $24: WaitMs(20);     // WAIT 20ms
169
      $25: WaitMs(50);     // WAIT 50ms
170
      $26: WaitMs(100);    // WAIT 100ms
171
      $27: WaitMs(200);    // WAIT 200ms
172
      $28: WaitMs(500);    // WAIT 500ms
173
      $29: WaitMs(1000);   // WAIT 1s
174
      $2A: WaitMs(2000);   // WAIT 2s
175
      $2B: WaitMs(5000);   // WAIT 5s
176
      $2C: WaitMs(10000);  // WAIT 10s
177
      $2D: WaitMs(20000);  // WAIT 20s
178
      $2E: WaitMs(30000);  // WAIT 30s
179
      $2F: WaitMs(60000);  // WAIT 60s
180
    end;
181
 
182
    (*
183
    ----------------------------------------------------
184
    Code        Assembly        Alternative     Comment
185
    ----------------------------------------------------
186
    30  JUMP -0         HALT
187
    31  JUMP -1
188
    32  JUMP -2
189
    33  JUMP -3
190
    34  JUMP -4
191
    35  JUMP -5
192
    36  JUMP -6
193
    37  JUMP -7
194
    38  JUMP -8
195
    39  JUMP -9
196
    3A  JUMP -10
197
    3B  JUMP -11
198
    3C  JUMP -12
199
    3D  JUMP -13
200
    3E  JUMP -14
201
    3F  JUMP -15
202
    *)
203
    if (Instruction >= $30) and (Instruction <= $3F) then
204
    begin
205
      ProgramCounterNext := ProgramCounterCurrent - (Instruction and $F);
206
    end;
207
 
208
    (*
209
    ----------------------------------------------------
210
    Code        Assembly        Alternative     Comment
211
    ----------------------------------------------------
212
    40  SET A=0
213
    41  SET A=1
214
    42  SET A=2
215
    43  SET A=3
216
    44  SET A=4
217
    45  SET A=5
218
    46  SET A=6
219
    47  SET A=7
220
    48  SET A=8
221
    49  SET A=9
222
    4A  SET A=10
223
    4B  SET A=11
224
    4C  SET A=12
225
    4D  SET A=13
226
    4E  SET A=14
227
    4F  SET A=15
228
    *)
229
    if (Instruction >= $40) and (Instruction <= $4F) then
230
    begin
231
      FRegA := Instruction and $F;
232
    end;
233
 
234
    (*
235
    ----------------------------------------------------
236
    Code        Assembly        Alternative     Comment
237
    ----------------------------------------------------
238
    50
239
    51  SET B=A
240
    52  SET C=A
241
    53  SET D=A
242
    54  SET Dout=A
243
    55  SET Dout.0=A.0
244
    56  SET Dout.1=A.0
245
    57  SET Dout.2=A.0
246
    58  SET Dout.3=A.0
247
    59  SET PWM=A
248
    5A
249
    5B
250
    5C
251
    5D
252
    5E
253
    5F
254
    *)
255
    case Instruction of
256
      $51: FRegB := FRegA;     // SET B=A
257
      $52: FRegC := FRegA;     // SET C=A
258
      $53: FRegD := FRegA;     // SET D=A
259
      $54: FPortOut := FRegA;  // SET Dout=A
260
      $55: FPortOut := ((FRegA and 1) shl 0) + (PortOut and 14); // SET Dout.0=A.0
261
      $56: FPortOut := ((FRegA and 1) shl 1) + (PortOut and 13); // SET Dout.1=A.0
262
      $57: FPortOut := ((FRegA and 1) shl 2) + (PortOut and 11); // SET Dout.2=A.0
263
      $58: FPortOut := ((FRegA and 1) shl 3) + (PortOut and  7); // SET Dout.3=A.0
264
      $59: FPWM := FRegA;      // SET PWM=A
265
    end;
266
 
267
    (*
268
    ----------------------------------------------------
269
    Code        Assembly        Alternative     Comment
270
    ----------------------------------------------------
271
    60
272
    61  SET A=B
273
    62  SET A=C
274
    63  SET A=D
275
    64  SET A=Din
276
    65  SET A=Din.0
277
    66  SET A=Din.1
278
    67  SET A=Din.2
279
    68  SET A=Din.3
280
    69  SET A=AD1
281
    6A  SET A=AD2
282
    6B
283
    6C
284
    6D
285
    6E
286
    6F
287
    *)
288
    case Instruction of
289
      $61: FRegA := FRegB; // SET A=B
290
      $62: FRegA := FRegC; // SET A=C
291
      $63: FRegA := FRegD; // SET A=D
292
      $64: FRegA := DIn;  // SET A=Din
293
      $65: FRegA := (DIn and 1) shr 0;  // SET A=Din.0
294
      $66: FRegA := (DIn and 2) shr 1;  // SET A=Din.1
295
      $67: FRegA := (DIn and 4) shr 1;  // SET A=Din.2
296
      $68: FRegA := (DIn and 8) shr 1;  // SET A=Din.3
297
      $69: FRegA := AD1;
298
      $6A: FRegA := AD2;
299
    end;
300
 
301
    (*
302
    ----------------------------------------------------
303
    Code        Assembly        Alternative     Comment
304
    ----------------------------------------------------
305
    70
306
    71  SET A=A+1
307
    72  SET A=A-1
308
    73  SET A=A+B
309
    74  SET A=A-B
310
    75  SET A=A*B
311
    76  SET A=A/B
312
    77  SET A=A&B                       AND
313
    78  SET A=A|B                       OR
314
    79  SET A=A^B                       XOR
315
    7A  SET A=~A                        NOT
316
    7B
317
    7C
318
    7D
319
    7E
320
    7F
321
    *)
322
    case Instruction of
323
      $71: FRegA := FRegA + 1;      // SET A=A+1
324
      $72: FRegA := FRegA - 1;      // SET A=A-1
325
      $73: FRegA := FRegA + FRegB;   // SET A=A+B
326
      $74: FRegA := FRegA - FRegB;   // SET A=A-B
327
      $75: FRegA := FRegA * FRegB;   // SET A=A*B
328
      $76: begin
329
             if FRegB = 0 then
330
               FRegA := $F // this is the actual behavior of the microchip (program 40 51 45 76 54 30)
331
             else
332
               FRegA := FRegA div FRegB; // SET A=A/B
333
           end;
334
      $77: FRegA := FRegA and FRegB; // SET A=A&B                       AND
335
      $78: FRegA := FRegA  or FRegB; // SET A=A|B                       OR
336
      $79: FRegA := FRegA xor FRegB; // SET A=A^B                       XOR
337
      $7A: FRegA := not FRegA;      // SET A=~A                 NOT
338
    end;
339
 
340
    (*
341
    ----------------------------------------------------
342
    Code        Assembly        Alternative     Comment
343
    ----------------------------------------------------
344
    80  PAGE 0                          Page is used by JUMP, CALL, CTIMES and DTIMES
345
    81  PAGE 1
346
    82  PAGE 2
347
    83  PAGE 3
348
    84  PAGE 4
349
    85  PAGE 5
350
    86  PAGE 6
351
    87  PAGE 7
352
    88  PAGE 8
353
    89  PAGE 9
354
    8A  PAGE A
355
    8B  PAGE B
356
    8C  PAGE C
357
    8D  PAGE D
358
    8E  PAGE E
359
    8F  PAGE F
360
    *)
361
    if (Instruction >= $80) and (Instruction <= $8F) then
362
    begin
363
      FPage := Instruction and $F;
364
    end;
365
 
366
    (*
367
    ----------------------------------------------------
368
    Code        Assembly        Alternative     Comment
369
    ----------------------------------------------------
370
    90  JUMP <PAGE>0
371
    91  JUMP <PAGE>1
372
    92  JUMP <PAGE>2
373
    93  JUMP <PAGE>3
374
    94  JUMP <PAGE>4
375
    95  JUMP <PAGE>5
376
    96  JUMP <PAGE>6
377
    97  JUMP <PAGE>7
378
    98  JUMP <PAGE>8
379
    99  JUMP <PAGE>9
380
    9A  JUMP <PAGE>A
381
    9B  JUMP <PAGE>B
382
    9C  JUMP <PAGE>C
383
    9D  JUMP <PAGE>D
384
    9E  JUMP <PAGE>E
385
    9F  JUMP <PAGE>F
386
    *)
387
    if (Instruction >= $90) and (Instruction <= $9F) then
388
    begin
389
      ProgramCounterNext := (FPage shl 4) + (Instruction and $F);
390
    end;
391
 
392
    (*
393
    ----------------------------------------------------
394
    Code        Assembly        Alternative     Comment
395
    ----------------------------------------------------
396
    A0  CTIMES <PAGE>0                  IF C>0 THEN ( C=C-1 ; JUMP <PAGE>X ) ELSE CONTINUE
397
    A1  CTIMES <PAGE>1
398
    A2  CTIMES <PAGE>2
399
    A3  CTIMES <PAGE>3
400
    A4  CTIMES <PAGE>4
401
    A5  CTIMES <PAGE>5
402
    A6  CTIMES <PAGE>6
403
    A7  CTIMES <PAGE>7
404
    A8  CTIMES <PAGE>8
405
    A9  CTIMES <PAGE>9
406
    AA  CTIMES <PAGE>A
407
    AB  CTIMES <PAGE>B
408
    AC  CTIMES <PAGE>C
409
    AD  CTIMES <PAGE>D
410
    AE  CTIMES <PAGE>E
411
    AF  CTIMES <PAGE>F
412
    *)
413
    if (Instruction >= $A0) and (Instruction <= $AF) then
414
    begin
415
      if FRegC > 0 then
416
      begin
417
        Dec(FRegC);
418
        FReturnAddress     := ProgramCounterCurrent;
419
        ProgramCounterNext := (FPage shl 4) + (Instruction and $F);
420
      end;
421
    end;
422
 
423
    (*
424
    ----------------------------------------------------
425
    Code        Assembly        Alternative     Comment
426
    ----------------------------------------------------
427
    B0  DTIMES <PAGE>0                  IF D>0 THEN ( D=D-1 ; JUMP <PAGE>X ) ELSE CONTINUE
428
    B1  DTIMES <PAGE>1
429
    B2  DTIMES <PAGE>2
430
    B3  DTIMES <PAGE>3
431
    B4  DTIMES <PAGE>4
432
    B5  DTIMES <PAGE>5
433
    B6  DTIMES <PAGE>6
434
    B7  DTIMES <PAGE>7
435
    B8  DTIMES <PAGE>8
436
    B9  DTIMES <PAGE>9
437
    BA  DTIMES <PAGE>A
438
    BB  DTIMES <PAGE>B
439
    BC  DTIMES <PAGE>C
440
    BD  DTIMES <PAGE>D
441
    BE  DTIMES <PAGE>E
442
    BF  DTIMES <PAGE>F
443
    *)
444
    if (Instruction >= $B0) and (Instruction <= $BF) then
445
    begin
446
      if FRegD > 0 then
447
      begin
448
        Dec(FRegD);
449
        FReturnAddress     := ProgramCounterCurrent;
450
        ProgramCounterNext := (FPage shl 4) + (Instruction and $F);
451
      end;
452
    end;
453
 
454
    (*
455
    ----------------------------------------------------
456
    Code        Assembly        Alternative     Comment
457
    ----------------------------------------------------
458
    C0
459
    C1  SKIP_IF A>B
460
    C2  SKIP_IF A<B
461
    C3  SKIP_IF A=B
462
    C4  SKIP_IF Din.0=1
463
    C5  SKIP_IF Din.1=1
464
    C6  SKIP_IF Din.2=1
465
    C7  SKIP_IF Din.3=1
466
    C8  SKIP_IF Din.0=0
467
    C9  SKIP_IF Din.1=0
468
    CA  SKIP_IF Din.2=0
469
    CB  SKIP_IF Din.3=0
470
    CC  SKIP_IF S1=0
471
    CD  SKIP_IF S2=0
472
    CE  SKIP_IF S1=1
473
    CF  SKIP_IF S2=1
474
    *)
475
    case Instruction of
476
      $C1: if FRegA > FRegB then Inc(ProgramCounterNext);
477
      $C2: if FRegA < FRegB then Inc(ProgramCounterNext);
478
      $C3: if FRegA = FRegB then Inc(ProgramCounterNext);
479
      $C4: if ((Din and 1) shr 0) = 1 then Inc(ProgramCounterNext);
480
      $C5: if ((Din and 2) shr 1) = 1 then Inc(ProgramCounterNext);
481
      $C6: if ((Din and 4) shr 2) = 1 then Inc(ProgramCounterNext);
482
      $C7: if ((Din and 8) shr 3) = 1 then Inc(ProgramCounterNext);
483
      $C8: if ((Din and 1) shr 0) = 0 then Inc(ProgramCounterNext);
484
      $C9: if ((Din and 2) shr 1) = 0 then Inc(ProgramCounterNext);
485
      $CA: if ((Din and 4) shr 2) = 0 then Inc(ProgramCounterNext);
486
      $CB: if ((Din and 8) shr 3) = 0 then Inc(ProgramCounterNext);
487
      $CC: if S1 = false then Inc(ProgramCounterNext);
488
      $CD: if S2 = false then Inc(ProgramCounterNext);
489
      $CE: if S1 = true then Inc(ProgramCounterNext);
490
      $CF: if S2 = true then Inc(ProgramCounterNext);
491
    end;
492
 
493
    (*
494
    ----------------------------------------------------
495
    Code        Assembly        Alternative     Comment
496
    ----------------------------------------------------
497
    D0  CALL <PAGE>0
498
    D1  CALL <PAGE>1
499
    D2  CALL <PAGE>2
500
    D3  CALL <PAGE>3
501
    D4  CALL <PAGE>4
502
    D5  CALL <PAGE>5
503
    D6  CALL <PAGE>6
504
    D7  CALL <PAGE>7
505
    D8  CALL <PAGE>8
506
    D9  CALL <PAGE>9
507
    DA  CALL <PAGE>A
508
    DB  CALL <PAGE>B
509
    DC  CALL <PAGE>C
510
    DD  CALL <PAGE>D
511
    DE  CALL <PAGE>E
512
    DF  CALL <PAGE>F
513
    *)
514
    if (Instruction >= $D0) and (Instruction <= $DF) then
515
    begin
516
      FCalledOnce        := true;
517
      FReturnAddress     := ProgramCounterNext;
518
      ProgramCounterNext := (FPage shl 4) + (Instruction and $F)
519
    end;
520
 
521
    (*
522
    ----------------------------------------------------
523
    Code        Assembly        Alternative     Comment
524
    ----------------------------------------------------
525
    E0  RET
526
    *)
527
    if Instruction = $E0 then
528
    begin
529
      if not FCalledOnce then
530
      begin
531
        // "Freeze" is the behavior of the actual chip (see test program 41 54 27 42 54 27 E0 7A 27 54 33)
532
        ProgramCounterNext := ProgramCounterCurrent;
533
      end
534
      else
535
      begin
536
        ProgramCounterNext := FReturnAddress;
537
      end;
538
    end;
539
  finally
540
    FPC := ProgramCounterNext;
541
  end;
542
end;
543
 
544
procedure THT46F47.WaitMs(milliseconds: integer);
545
begin
3 daniel-mar 546
  if Assigned(FOnWait) then
547
    FOnWait(milliseconds)
548
  else
549
    Sleep(milliseconds);
2 daniel-mar 550
end;
551
 
552
end.