1use core::ptr::{read_volatile, write_volatile};
15
16use crate::{WINDOW, reg};
17
18const PORT: *mut u8 = (WINDOW + 0x80) as *mut u8;
19
20const CS: u8 = 0x80;
21const CLK: u8 = 0x40;
22const DI: u8 = 0x02;
23const DO: u8 = 0x01;
24
25pub const WORDS: u8 = 128;
27
28fn port(bits: u8) {
29 unsafe { write_volatile(PORT, bits) };
30}
31
32fn exchange(state: u8, bit: bool) -> bool {
34 let level = state | if bit { DI } else { 0 };
35 port(level);
36 port(level | CLK);
37 let read = unsafe { read_volatile(PORT as *const u8) } & DO != 0;
38 port(level);
39 read
40}
41
42fn command(opcode: u8, address: u8) {
43 port(0);
44 port(CS);
45 exchange(CS, true);
46 for i in (0..2).rev() {
47 exchange(CS, opcode >> i & 1 != 0);
48 }
49 for i in (0..8).rev() {
50 exchange(CS, address >> i & 1 != 0);
51 }
52}
53
54fn finish() {
55 port(0);
56}
57
58pub fn read(address: u8) -> u16 {
60 reg::enable();
61 reg::select_raw(0x40);
62
63 command(0b10, address);
64 let mut word = 0u16;
65 for _ in 0..16 {
66 word = word << 1 | exchange(CS, false) as u16;
67 }
68 finish();
69
70 reg::disable();
71 word
72}
73
74pub fn write(address: u8, word: u16) {
76 reg::enable();
77 reg::select_raw(0x40);
78
79 command(0b01, address);
80 for i in (0..16).rev() {
81 exchange(CS, word >> i & 1 != 0);
82 }
83 finish();
84
85 port(CS);
87 while unsafe { read_volatile(PORT as *const u8) } & DO == 0 {}
88 finish();
89
90 reg::disable();
91}
92
93pub fn unlock() {
95 reg::enable();
96 reg::select_raw(0x40);
97 command(0b00, 0b1100_0000);
98 finish();
99 reg::disable();
100}
101
102pub fn lock() {
104 reg::enable();
105 reg::select_raw(0x40);
106 command(0b00, 0b0000_0000);
107 finish();
108 reg::disable();
109}