@@ -65,13 +65,31 @@ const UCSRC_UCSZ0 = 0x2; // Character Size 0
65
65
const UCSRC_UCPOL = 0x1 ; // Clock Polarity
66
66
/* eslint-enable @typescript-eslint/no-unused-vars */
67
67
68
+ const rxMasks = {
69
+ 5 : 0x1f ,
70
+ 6 : 0x3f ,
71
+ 7 : 0x7f ,
72
+ 8 : 0xff ,
73
+ 9 : 0xff ,
74
+ } ;
68
75
export class AVRUSART {
69
76
public onByteTransmit : USARTTransmitCallback | null = null ;
70
77
public onLineTransmit : USARTLineTransmitCallback | null = null ;
78
+ public onRxComplete : ( ( ) => void ) | null = null ;
71
79
80
+ private rxBusyValue = false ;
81
+ private rxByte = 0 ;
72
82
private lineBuffer = '' ;
73
83
74
84
// Interrupts
85
+ private RXC : AVRInterruptConfig = {
86
+ address : this . config . rxCompleteInterrupt ,
87
+ flagRegister : this . config . UCSRA ,
88
+ flagMask : UCSRA_RXC ,
89
+ enableRegister : this . config . UCSRB ,
90
+ enableMask : UCSRB_RXCIE ,
91
+ constant : true ,
92
+ } ;
75
93
private UDRE : AVRInterruptConfig = {
76
94
address : this . config . dataRegisterEmptyInterrupt ,
77
95
flagRegister : this . config . UCSRA ,
@@ -90,19 +108,29 @@ export class AVRUSART {
90
108
constructor ( private cpu : CPU , private config : USARTConfig , private freqHz : number ) {
91
109
this . reset ( ) ;
92
110
this . cpu . writeHooks [ config . UCSRA ] = ( value ) => {
93
- cpu . data [ config . UCSRA ] = value ;
94
- cpu . clearInterruptByFlag ( this . UDRE , value ) ;
111
+ cpu . data [ config . UCSRA ] = value & ( UCSRA_MPCM | UCSRA_U2X ) ;
95
112
cpu . clearInterruptByFlag ( this . TXC , value ) ;
96
113
return true ;
97
114
} ;
98
115
this . cpu . writeHooks [ config . UCSRB ] = ( value , oldValue ) => {
116
+ cpu . updateInterruptEnable ( this . RXC , value ) ;
99
117
cpu . updateInterruptEnable ( this . UDRE , value ) ;
100
118
cpu . updateInterruptEnable ( this . TXC , value ) ;
119
+ if ( value & UCSRB_RXEN && oldValue & UCSRB_RXEN ) {
120
+ cpu . clearInterrupt ( this . RXC ) ;
121
+ }
101
122
if ( value & UCSRB_TXEN && ! ( oldValue & UCSRB_TXEN ) ) {
102
123
// Enabling the transmission - mark UDR as empty
103
124
cpu . setInterruptFlag ( this . UDRE ) ;
104
125
}
105
126
} ;
127
+ this . cpu . readHooks [ config . UDR ] = ( ) => {
128
+ const mask = rxMasks [ this . bitsPerChar ] ?? 0xff ;
129
+ const result = this . rxByte & mask ;
130
+ this . rxByte = 0 ;
131
+ this . cpu . clearInterrupt ( this . RXC ) ;
132
+ return result ;
133
+ } ;
106
134
this . cpu . writeHooks [ config . UDR ] = ( value ) => {
107
135
if ( this . onByteTransmit ) {
108
136
this . onByteTransmit ( value ) ;
@@ -116,12 +144,10 @@ export class AVRUSART {
116
144
this . lineBuffer += ch ;
117
145
}
118
146
}
119
- const symbolsPerChar = 1 + this . bitsPerChar + this . stopBits + ( this . parityEnabled ? 1 : 0 ) ;
120
- const cyclesToComplete = ( this . UBRR * this . multiplier + 1 ) * symbolsPerChar ;
121
147
this . cpu . addClockEvent ( ( ) => {
122
148
cpu . setInterruptFlag ( this . UDRE ) ;
123
149
cpu . setInterruptFlag ( this . TXC ) ;
124
- } , cyclesToComplete ) ;
150
+ } , this . cyclesPerChar ) ;
125
151
this . cpu . clearInterrupt ( this . TXC ) ;
126
152
this . cpu . clearInterrupt ( this . UDRE ) ;
127
153
} ;
@@ -131,6 +157,33 @@ export class AVRUSART {
131
157
this . cpu . data [ this . config . UCSRA ] = UCSRA_UDRE ;
132
158
this . cpu . data [ this . config . UCSRB ] = 0 ;
133
159
this . cpu . data [ this . config . UCSRC ] = UCSRC_UCSZ1 | UCSRC_UCSZ0 ; // default: 8 bits per byte
160
+ this . rxBusyValue = false ;
161
+ this . rxByte = 0 ;
162
+ this . lineBuffer = '' ;
163
+ }
164
+
165
+ get rxBusy ( ) {
166
+ return this . rxBusyValue ;
167
+ }
168
+
169
+ writeByte ( value : number ) {
170
+ const { cpu, config } = this ;
171
+ if ( this . rxBusyValue || ! ( cpu . data [ config . UCSRB ] & UCSRB_RXEN ) ) {
172
+ return false ;
173
+ }
174
+ this . rxBusyValue = true ;
175
+ cpu . addClockEvent ( ( ) => {
176
+ this . rxByte = value ;
177
+ this . rxBusyValue = false ;
178
+ cpu . setInterruptFlag ( this . RXC ) ;
179
+ this . onRxComplete ?.( ) ;
180
+ } , this . cyclesPerChar ) ;
181
+ return true ;
182
+ }
183
+
184
+ private get cyclesPerChar ( ) {
185
+ const symbolsPerChar = 1 + this . bitsPerChar + this . stopBits + ( this . parityEnabled ? 1 : 0 ) ;
186
+ return ( this . UBRR * this . multiplier + 1 ) * symbolsPerChar ;
134
187
}
135
188
136
189
private get UBRR ( ) {
0 commit comments