Mirror of CollapseOS
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

432 Zeilen
11KB

  1. .include "tn45def.inc"
  2. ; Receives keystrokes from PS/2 keyboard and send them to the 595. As long as
  3. ; that number is not collected, we buffer the scan code received from ps/2. As
  4. ; soon as that number is collected we put the next number in the buffer. If the
  5. ; buffer is empty, we do nothing (the 595 already had its SRCLR pin triggered
  6. ; and shows 0).
  7. ;
  8. ; PS/2 is a bidirectional protocol, but in this program, we only care about
  9. ; receiving keystrokes. We don't send anything to the keyboard.
  10. ;
  11. ; The PS/2 keyboard has two data wires: Clock and Data. It is the keyboard that
  12. ; drives the clock with about 30-50 us between each clock.
  13. ;
  14. ; We wire the Clock to INT0 (PB2) and make it trigger an interrupt on the
  15. ; falling edge (the edge, in the PS/2 protocol, when data is set).
  16. ;
  17. ; Data is sent by the keyboard in 11-bit frames. 1 start bit (0), 8 data bits,
  18. ; one parity bit, one stop bit (1).
  19. ;
  20. ; Parity bit is set if number of bits in data bits is even. Unset otherwise.
  21. ;
  22. ; *** Receiving a data frame ***
  23. ;
  24. ; In idle mode, R18 is zero. When INT0 is triggered, it is increased and R17 is
  25. ; loaded with 0x80. We do this because we're going to right shift our data in
  26. ; (byte is sent LSB first). When the carry flag is set, we'll know we're
  27. ; finished. When that happens, we increase R18 again. We're waiting for parity
  28. ; bit. When we get it, we check parity and increase R18 again. We're waiting
  29. ; for stop bit. After we receive stop bit, we reset R18 to 0.
  30. ;
  31. ; On error, we ignore and reset our counters.
  32. ; *** Buffering scan codes ***
  33. ;
  34. ; The buffer starts at SRAM and stops at 0x100. It leaves space for the stack
  35. ; and makes overflow check easy. Also, we don't need a very big buffer. In this
  36. ; address space, Z chasing Y. When Y == Z, the buffer is empty. When 0x100 is
  37. ; reached, we go back to SRAM_START.
  38. ;
  39. ; Whenever a new scan code is received, we place it in Y and increase it.
  40. ; Whenever we send a scan code to the 595 (which can't be done when Z == Y
  41. ; because Z points to an invalid value), we send the value of Z and increase.
  42. ; *** Sending to the 595 ***
  43. ;
  44. ; Whenever a scan code is read from the 595, CE goes low and triggers a PCINT
  45. ; on PB4. When we get it, we clear the GPIOR0/1 flag to indicate that we're
  46. ; ready to send a new scan code to the 595.
  47. ;
  48. ; Because that CE flip/flop is real fast (375ns), it requires us to run at 8MHz.
  49. ;
  50. ; During the PCINT, we also trigger RCLK once because CE is also wired to SRCLR
  51. ; and we want the z80 to be able to know that the device has nothing to give
  52. ; (has a value of zero) rather than having to second guess (is this value, which
  53. ; is the same as the one that was read before, a new value or not?). With that
  54. ; "quick zero-in" scheme, there's no ambiguity: no scan code can be ready twice
  55. ; because it's replaced by a 0 as soon as it's read, until it can be filled with
  56. ; the next char in the buffer.
  57. ; *** Register Usage ***
  58. ;
  59. ; GPIOR0 flags:
  60. ; 0 - when set, indicates that the DATA pin was high when we received a
  61. ; bit through INT0. When we receive a bit, we set flag T to indicate
  62. ; it.
  63. ; 1 - When set, indicate that the 595 holds a value that hasn't been read
  64. ; by the z80 yet.
  65. ;
  66. ; R16: tmp stuff
  67. ; R17: recv buffer. Whenever we receive a bit, we push it in there.
  68. ; R18: recv step:
  69. ; - 0: idle
  70. ; - 1: receiving data
  71. ; - 2: awaiting parity bit
  72. ; - 3: awaiting stop bit
  73. ; R19: Register used for parity computations and tmp value in some other places
  74. ; R20: data being sent to the 595
  75. ; Y: pointer to the memory location where the next scan code from ps/2 will be
  76. ; written.
  77. ; Z: pointer to the next scan code to push to the 595
  78. ;
  79. ; *** Constants ***
  80. ;
  81. .equ CLK = PINB2
  82. .equ DATA = PINB1
  83. .equ SRCLK = PINB3
  84. .equ CE = PINB4
  85. .equ RCLK = PINB0
  86. ; init value for TCNT0 so that overflow occurs in 100us
  87. .equ TIMER_INITVAL = 0x100-100
  88. rjmp main
  89. rjmp hdlINT0
  90. rjmp hdlPCINT
  91. ; Read DATA and set GPIOR0/0 if high. Then, set flag T.
  92. ; no SREG fiddling because no SREG-modifying instruction
  93. hdlINT0:
  94. sbic PINB, DATA ; DATA clear? skip next
  95. sbi GPIOR0, 0
  96. set
  97. reti
  98. ; Only PB4 is hooked to PCINT and we don't bother checking the value of the PB4
  99. ; pin: things go too fast for this.
  100. ; no SREG fiddling because no SREG-modifying instruction
  101. hdlPCINT:
  102. ; SRCLR has been triggered. Let's trigger RCLK too.
  103. sbi PORTB, RCLK
  104. cbi PORTB, RCLK
  105. cbi GPIOR0, 1 ; 595 is now free
  106. reti
  107. main:
  108. ldi r16, low(RAMEND)
  109. out SPL, r16
  110. ldi r16, high(RAMEND)
  111. out SPH, r16
  112. ; Set clock prescaler to 1 (8MHz)
  113. ldi r16, (1<<CLKPCE)
  114. out CLKPR, r16
  115. clr r16
  116. out CLKPR, r16
  117. ; init variables
  118. clr r18
  119. out GPIOR0, r18
  120. ; Setup int0/PCINT
  121. ; INT0, falling edge
  122. ldi r16, (1<<ISC01)
  123. out MCUCR, r16
  124. ; Enable both INT0 and PCINT
  125. ldi r16, (1<<INT0)|(1<<PCIE)
  126. out GIMSK, r16
  127. ; For PCINT, enable only PB4
  128. ldi r16, (1<<PCINT4)
  129. out PCMSK, r16
  130. ; Setup buffer
  131. clr YH
  132. ldi YL, low(SRAM_START)
  133. clr ZH
  134. ldi ZL, low(SRAM_START)
  135. ; Setup timer. We use the timer to clear up "processbit" registers after
  136. ; 100us without a clock. This allows us to start the next frame in a
  137. ; fresh state. at 8MHZ, setting the counter's prescaler to 8 gives us
  138. ; a nice 1us for each TCNT0.
  139. ldi r16, (1<<CS01) ; clk/8 prescaler
  140. out TCCR0B, r16
  141. ; init DDRB
  142. sbi DDRB, SRCLK
  143. cbi PORTB, RCLK ; RCLK is generally kept low
  144. sbi DDRB, RCLK
  145. sei
  146. loop:
  147. brts processbit ; flag T set? we have a bit to process
  148. cp YL, ZL ; if YL == ZL, buffer is empty
  149. brne sendTo595 ; YL != ZL? our buffer has data
  150. ; nothing to do. Before looping, let's check if our communication timer
  151. ; overflowed.
  152. in r16, TIFR
  153. sbrc r16, TOV0
  154. rjmp processbitReset ; Timer0 overflow? reset processbit
  155. ; Nothing to do for real.
  156. rjmp loop
  157. ; Process the data bit received in INT0 handler.
  158. processbit:
  159. in r19, GPIOR0 ; backup GPIOR0 before we reset T
  160. andi r19, 0x1 ; only keep the first flag
  161. cbi GPIOR0, 0
  162. clt ; ready to receive another bit
  163. ; We've received a bit. reset timer
  164. rcall resetTimer
  165. ; Which step are we at?
  166. tst r18
  167. breq processbits0
  168. cpi r18, 1
  169. breq processbits1
  170. cpi r18, 2
  171. breq processbits2
  172. ; step 3: stop bit
  173. clr r18 ; happens in all cases
  174. ; DATA has to be set
  175. tst r19 ; Was DATA set?
  176. breq loop ; not set? error, don't push to buffer
  177. ; push r17 to the buffer
  178. st Y+, r17
  179. rcall checkBoundsY
  180. rjmp loop
  181. processbits0:
  182. ; step 0 - start bit
  183. ; DATA has to be cleared
  184. tst r19 ; Was DATA set?
  185. brne loop ; Set? error. no need to do anything. keep r18
  186. ; as-is.
  187. ; DATA is cleared. prepare r17 and r18 for step 1
  188. inc r18
  189. ldi r17, 0x80
  190. rjmp loop
  191. processbits1:
  192. ; step 1 - receive bit
  193. ; We're about to rotate the carry flag into r17. Let's set it first
  194. ; depending on whether DATA is set.
  195. clc
  196. sbrc r19, 0 ; skip if DATA cleared.
  197. sec
  198. ; Carry flag is set
  199. ror r17
  200. ; Good. now, are we finished rotating? If carry flag is set, it means
  201. ; that we've rotated in 8 bits.
  202. brcc loop ; we haven't finished yet
  203. ; We're finished, go to step 2
  204. inc r18
  205. rjmp loop
  206. processbits2:
  207. ; step 2 - parity bit
  208. mov r1, r19
  209. mov r19, r17
  210. rcall checkParity ; --> r16
  211. cp r1, r16
  212. brne processbitError ; r1 != r16? wrong parity
  213. inc r18
  214. rjmp loop
  215. processbitError:
  216. clr r18
  217. ldi r19, 0xfe
  218. rcall sendToPS2
  219. rjmp loop
  220. processbitReset:
  221. clr r18
  222. rcall resetTimer
  223. rjmp loop
  224. ; send next scan code in buffer to 595, MSB.
  225. sendTo595:
  226. sbic GPIOR0, 1
  227. rjmp loop ; flag 1 set? 595 is "busy". Don't send.
  228. ; We disable any interrupt handling during this routine. Whatever it
  229. ; is, it has no meaning to us at this point in time and processing it
  230. ; might mess things up.
  231. cli
  232. sbi DDRB, DATA
  233. ld r20, Z+
  234. rcall checkBoundsZ
  235. ldi r16, 8
  236. sendTo595Loop:
  237. cbi PORTB, DATA
  238. sbrc r20, 7 ; if leftmost bit isn't cleared, set DATA high
  239. sbi PORTB, DATA
  240. ; toggle SRCLK
  241. cbi PORTB, SRCLK
  242. lsl r20
  243. sbi PORTB, SRCLK
  244. dec r16
  245. brne sendTo595Loop ; not zero yet? loop
  246. ; We're finished sending our data to the 595 and we're ready to go back
  247. ; to business as usual. However, timing is important here. The z80 is
  248. ; very fast and constantly hammers our 595 with polls. While this
  249. ; routine was running, it was getting zeroes, which is fine, but as soon
  250. ; as we trigger RCLK, the z80 is going to fetch that value. What we want
  251. ; to do is to enable back the interrupts as soon as RCLK is triggered
  252. ; so that the z80 doesn't have enough time to poll twice. If it did, we
  253. ; would return a double character. This is why RCLK triggering is the
  254. ; last operation.
  255. ; release PS/2
  256. cbi DDRB, DATA
  257. ; Set GPIOR0/1 to "595 is busy"
  258. sbi GPIOR0, 1
  259. ; toggle RCLK
  260. sbi PORTB, RCLK
  261. cbi PORTB, RCLK
  262. sei
  263. rjmp loop
  264. resetTimer:
  265. ldi r16, TIMER_INITVAL
  266. out TCNT0, r16
  267. ldi r16, (1<<TOV0)
  268. out TIFR, r16
  269. ret
  270. ; Send the value of r19 to the PS/2 keyboard
  271. sendToPS2:
  272. ; We don't use the general INT0 mechanism here. However, we still want
  273. ; to listen to PCINT, so we don't disable interrupts entirely, just
  274. ; INT0.
  275. ldi r16, (1<<PCIE)
  276. out GIMSK, r16
  277. ; First, indicate our request to send by holding both Clock low for
  278. ; 100us, then pull Data low
  279. ; lines low for 100us.
  280. cbi PORTB, CLK
  281. sbi DDRB, CLK
  282. rcall resetTimer
  283. ; Wait until the timer overflows
  284. in r16, TIFR
  285. sbrs r16, TOV0
  286. rjmp PC-2
  287. ; Good, 100us passed.
  288. ; Pull Data low, that's our start bit.
  289. cbi PORTB, DATA
  290. sbi DDRB, DATA
  291. ; Now, let's release the clock. At the next raising edge, we'll be
  292. ; expected to have set up our first bit (LSB). We set up when CLK is
  293. ; low.
  294. cbi DDRB, CLK ; Should be starting high now.
  295. ; We will do the next loop 8 times
  296. ldi r16, 8
  297. ; Let's remember initial r19 for parity
  298. mov r1, r19
  299. sendToPS2Loop:
  300. ; Wait for CLK to go low
  301. sbic PINB, CLK
  302. rjmp PC-1
  303. ; set up DATA
  304. cbi PORTB, DATA
  305. sbrc r19, 0 ; skip if LSB is clear
  306. sbi PORTB, DATA
  307. lsr r19
  308. ; Wait for CLK to go high
  309. sbis PINB, CLK
  310. rjmp PC-1
  311. dec r16
  312. brne sendToPS2Loop ; not zero? loop
  313. ; Data was sent, CLK is high. Let's send parity
  314. mov r19, r1 ; recall saved value
  315. rcall checkParity ; --> r16
  316. ; Wait for CLK to go low
  317. sbic PINB, CLK
  318. rjmp PC-1
  319. ; set parity bit
  320. cbi PORTB, DATA
  321. sbrc r16, 0 ; parity bit in r16
  322. sbi PORTB, DATA
  323. ; Wait for CLK to go high
  324. sbis PINB, CLK
  325. rjmp PC-1
  326. ; Wait for CLK to go low
  327. sbic PINB, CLK
  328. rjmp PC-1
  329. ; We can now release the DATA line
  330. cbi DDRB, DATA
  331. ; Wait for DATA to go low. That's our ACK
  332. sbic PINB, DATA
  333. rjmp PC-1
  334. ; Wait for CLK to go low
  335. sbic PINB, CLK
  336. rjmp PC-1
  337. ; We're finished! Enable INT0, reset timer, everything back to normal!
  338. rcall resetTimer
  339. clt ; also, make sure T isn't mistakely set.
  340. ldi r16, (1<<INT0)|(1<<PCIE)
  341. out GIMSK, r16
  342. ret
  343. ; Check that Y is within bounds, reset to SRAM_START if not.
  344. checkBoundsY:
  345. tst YL
  346. breq PC+2
  347. ret ; not zero, nothing to do
  348. ; YL is zero. Reset Y
  349. clr YH
  350. ldi YL, low(SRAM_START)
  351. ret
  352. ; Check that Z is within bounds, reset to SRAM_START if not.
  353. checkBoundsZ:
  354. tst ZL
  355. breq PC+2
  356. ret ; not zero, nothing to do
  357. ; ZL is zero. Reset Z
  358. clr ZH
  359. ldi ZL, low(SRAM_START)
  360. ret
  361. ; Counts the number of 1s in r19 and set r16 to 1 if there's an even number of
  362. ; 1s, 0 if they're odd.
  363. checkParity:
  364. ldi r16, 1
  365. lsr r19
  366. brcc PC+2 ; Carry unset? skip next
  367. inc r16 ; Carry set? We had a 1
  368. tst r19 ; is r19 zero yet?
  369. brne checkParity+1 ; no? loop and skip first LDI
  370. andi r16, 0x1 ; Sets Z accordingly
  371. ret