summaryrefslogtreecommitdiff
path: root/mkm_refdes/src/mkm_refdes.v
blob: 22e99184d0f5841b2fda7f04167caf75597fa97c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
module mkm_refdes
(
    output [3:0] leds,  // {blue, red, yellow, green}
                        
    input   mkm_cs_n, mkm_sclk, mkm_di,
    output  mkm_do,
    
    input   btn_panic
);

    //
    // Internal High-Speed Oscillator
    //
    wire clk_osc_lf;    // 48 MHz
    SB_LFOSC SB_LFOSC_inst
    (
        .CLKLFPU    (1'b1),
        .CLKLFEN    (1'b1),
        .CLKLF      (clk_osc_lf)
    ) /* synthesis ROUTE_THROUGH_FABRIC = 0 */;
    
    
    //
    // Blinking Green LED
    //
    reg [13:0] led_cnt   = 14'd0;
    reg        led_green = 1'b0;
    
    always @(posedge clk_osc_lf) begin
        led_cnt   <= led_cnt + 1'b1;
        led_green <= &led_cnt[13:12];
    end
    
    
    //
    // "Panic" Red LED
    //
    reg led_red = 1'b0;
        
    always @(posedge clk_osc_lf)
        led_red <= btn_panic;
        
    
    //
    // Blue LED to indicate MKM access over SPI
    //
    reg led_blue = 1'b0;
    
    reg mkm_cs_n_sync1 = 1'b1;
    reg mkm_cs_n_sync2 = 1'b1;
    
    always @(posedge clk_osc_lf)
        {mkm_cs_n_sync1, mkm_cs_n_sync2} <=
        {mkm_cs_n,       mkm_cs_n_sync1};
        
    reg [12:0] spi_cnt = 13'd0;
    
    always @(posedge clk_osc_lf)
        //
        if (spi_cnt > 13'd0)
            spi_cnt <= spi_cnt - 13'd1;
        else if (!mkm_cs_n_sync2)
            spi_cnt <= {13{1'b1}};

    always @(posedge clk_osc_lf)
        //
        led_blue <= spi_cnt[10];
    
    
    //
    // serial memory follows
    //
    

    //
    // operation mode
    //
    reg [1:0] opmode = 2'b00;
    
    
    //
    // bit counter
    //
    localparam integer BIT_CNT_W = 16;
    localparam [BIT_CNT_W-1:0] bit_cnt_zero = {BIT_CNT_W{1'b0}};
    reg        [BIT_CNT_W-1:0] bit_cnt      = bit_cnt_zero;
    wire       [BIT_CNT_W-1:0] bit_cnt_next = bit_cnt + 16'd1;
    
    always @(posedge mkm_sclk or posedge mkm_cs_n)
        //
        if (mkm_cs_n) bit_cnt <= bit_cnt_zero;
        else bit_cnt <= bit_cnt_next;
    
    
    //
    // input shifter
    //
    reg [15:0] di_shreg;
    always @(posedge mkm_sclk)
        //
        if (!mkm_cs_n) di_shreg <= {di_shreg[14:0], mkm_di};


    //
    // instruction decoder
    //
    reg [7:0] instr_latch;
    
    wire instr_is_read  = instr_latch == 8'b0000_0011;
    wire instr_is_write = instr_latch == 8'b0000_0010;
    wire instr_is_rdsr  = instr_latch == 8'b0000_0101;
    wire instr_is_wrsr  = instr_latch == 8'b0000_0001;
    
    always @(posedge mkm_sclk)
        //
        if (bit_cnt == 7) instr_latch <= {di_shreg[6:0], mkm_di};

    //
    // address latch
    //
    reg [15:0] addr_latch;
    
    always @(posedge mkm_sclk) begin
        //
        if (bit_cnt == 23) addr_latch <= {di_shreg[14:0], mkm_di};
        //
        if ((bit_cnt >= 31) && (bit_cnt[2:0] == 3'b111) & instr_is_write) begin
            //
            if (opmode == 2'b10) // page mode
                addr_latch[4:0] <= addr_latch[4:0] + 1'b1;
            else if (opmode == 2'b01) // seq mode
                addr_latch[7:0] <= addr_latch[7:0] + 1'b1;
            //
        end
        //
        if ((bit_cnt >= 24) && (bit_cnt[2:0] == 3'b000) && instr_is_read) begin
            //
            if (opmode == 2'b10) // page
                addr_latch[4:0] <= addr_latch[4:0] + 1'b1;
            else if (opmode == 2'b01) // seq
                addr_latch[7:0] <= addr_latch[7:0] + 1'b1;
        end
        //
    end
    

    //
    // mode change
    //
    always @(posedge mkm_sclk)
        //
        if ((bit_cnt == 15) && instr_is_wrsr && (di_shreg[4:0] == {5{1'b0}}))
            //
            opmode <= di_shreg[6:5];

            
    //
    // memory
    //
    localparam MEM_ADDR_W = 6;  // 64 bytes
    
    reg [7:0] sram[0:2**MEM_ADDR_W-1] /* synthesis syn_ramstyle="registers" */; 


    //
    // write logic
    //
    always @(posedge mkm_sclk)
        //
        if ((bit_cnt >= 31) && (bit_cnt[2:0] == 3'b111) & instr_is_write)
            //
            sram[addr_latch[MEM_ADDR_W-1:0]] <= {di_shreg[6:0], mkm_di};


    //
    // serial output
    //
    reg [7:0] do_shreg;
    assign mkm_do = do_shreg[7];
    
    always @(negedge mkm_sclk)
        //
        if (bit_cnt[2:0] == 3'b000) begin
            //
            if ((bit_cnt >= 24) && instr_is_read)
                //
                do_shreg <= sram[addr_latch[MEM_ADDR_W:0]];
                //
            else if ((bit_cnt > 7) && instr_is_rdsr)
                do_shreg <= {opmode, 5'b00000, 1'b1};
            //
        end else
            do_shreg <= {do_shreg[6:0], 1'bX};


    //
    // Map LEDs
    //
    assign leds[0] = led_green; //
    assign leds[1] = 1'b0;      // unused (yellow)
    assign leds[2] = led_red;   //
    assign leds[3] = led_blue;  //


endmodule