1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Peripherals.Bus;
11 
12 namespace Antmicro.Renode.Peripherals.Miscellaneous
13 {
14     public class MSP430F2XXX_MPY : BasicWordPeripheral, IBytePeripheral
15     {
MSP430F2XXX_MPY(IMachine machine)16         public MSP430F2XXX_MPY(IMachine machine) : base(machine)
17         {
18             DefineRegisters();
19         }
20 
WriteByte(long offset, byte value)21         public void WriteByte(long offset, byte value)
22         {
23             if(offset == (long)Registers.MultiplySignedOperand1 || offset == (long)Registers.MultiplySignedAccumulateOperand1)
24             {
25                 ushort extendedValue = value;
26                 extendedValue |= (value & 0x80) > 0 ? (ushort)0xFF00 : (ushort)0;
27                 WriteWord(offset, extendedValue);
28                 return;
29             }
30 
31             WriteWord(offset, value);
32         }
33 
ReadByte(long offset)34         public byte ReadByte(long offset)
35         {
36             return (byte)ReadWord(offset);
37         }
38 
SetModeAndOperand(ulong value, Mode mode)39         private void SetModeAndOperand(ulong value, Mode mode)
40         {
41             operand1 = (uint)value;
42             currentMode = mode;
43         }
44 
StoreResult(ulong result)45         private void StoreResult(ulong result)
46         {
47             resultLow.Value = (ushort)result;
48             resultHigh.Value = (ushort)(result >> 16);
49         }
50 
PerformCalculation(ulong operand2)51         private void PerformCalculation(ulong operand2)
52         {
53             switch(currentMode)
54             {
55                 case Mode.Unsigned:
56                 {
57                     var result = operand1 * operand2;
58 
59                     StoreResult(result);
60                     sumExtend.Value = 0;
61                     break;
62                 }
63 
64                 case Mode.Signed:
65                 {
66                     var result = (short)operand1 * (short)operand2;
67                     StoreResult((ulong)result);
68                     sumExtend.Value = result < 0 ? 0xFFFFU : 0U;
69                     break;
70                 }
71 
72                 case Mode.UnsignedAccumulate:
73                 {
74                     var result = LastResult + (int)(operand1 * operand2);
75                     StoreResult((ulong)result);
76                     sumExtend.Value = result > ushort.MaxValue ? 1U : 0U;
77                     break;
78                 }
79 
80                 case Mode.SignedAccumulate:
81                 {
82                     var result = LastResult + (short)operand1 * (short)operand2;
83                     StoreResult((ulong)result);
84                     sumExtend.Value = result < 0 ? 0xFFFFU : 0U;
85                     break;
86                 }
87             }
88         }
89 
DefineRegisters()90         private void DefineRegisters()
91         {
92             Registers.MultiplyUnsignedOperand1.Define(this)
93                 .WithValueField(0, 16, name: "MPY",
94                     writeCallback: (_, value) => SetModeAndOperand(value, Mode.Unsigned))
95             ;
96 
97             Registers.MultiplySignedOperand1.Define(this)
98                 .WithValueField(0, 16, name: "MPYS",
99                     writeCallback: (_, value) => SetModeAndOperand(value, Mode.Signed))
100                 ;
101 
102             Registers.MultiplyAccumulateOperand1.Define(this)
103                 .WithValueField(0, 16, name: "MAC",
104                     writeCallback: (_, value) => SetModeAndOperand(value, Mode.UnsignedAccumulate))
105             ;
106 
107             Registers.MultiplySignedAccumulateOperand1.Define(this)
108                 .WithValueField(0, 16, name: "MACS",
109                     writeCallback: (_, value) => SetModeAndOperand(value, Mode.SignedAccumulate))
110             ;
111 
112             Registers.SecondOperand.Define(this)
113                 .WithValueField(0, 16, name: "OP2",
114                     writeCallback: (_, value) => PerformCalculation(value))
115             ;
116 
117             Registers.ResultLow.Define(this)
118                 .WithValueField(0, 16, out resultLow, name: "RESLO")
119             ;
120 
121             Registers.ResultHigh.Define(this)
122                 .WithValueField(0, 16, out resultHigh, name: "RESHI")
123             ;
124 
125             Registers.SumExtend.Define(this)
126                 .WithValueField(0, 16, out sumExtend, FieldMode.Read, name: "SUMEXT")
127             ;
128         }
129 
130         private int LastResult => (int)resultLow.Value | ((int)resultHigh.Value << 16);
131 
132         private Mode currentMode;
133         private uint operand1;
134 
135         private IValueRegisterField resultLow;
136         private IValueRegisterField resultHigh;
137         private IValueRegisterField sumExtend;
138 
139         private enum Mode
140         {
141             Unsigned,
142             Signed,
143             UnsignedAccumulate,
144             SignedAccumulate,
145         }
146 
147         private enum Registers
148         {
149             MultiplyUnsignedOperand1 = 0x00,
150             MultiplySignedOperand1 = 0x02,
151             MultiplyAccumulateOperand1 = 0x04,
152             MultiplySignedAccumulateOperand1 = 0x06,
153             SecondOperand = 0x8,
154             ResultLow = 0xA,
155             ResultHigh = 0xC,
156             SumExtend = 0xE,
157         }
158     }
159 }
160