;; See instructions.wat of soc_print_number test. A lot has been taken from ;; there. ;; Relevant addresses are VGA text memory (0xFFC00), VGA regs (0x100600), ;; lower half of timer reg (0x1BFC08), SPI memory (0x13FC00), ;; SPI bytes_to_output reg (0x13FE00), SPI bytes_to_receive reg (0x13FE02) ;; and SPI operating reg (0x13FE04). (module (memory 0 2) (func $main (local $transfers i32) (local $offset i32) (local $address i32) (local $index i32) ;; power up flash chip ;; set bytes_to_output to 1 (i32.store16 offset=0 align=2 (i32.const 0x13FE00) (i32.const 1)) ;; set bytes_to_receive to 0 (i32.store16 offset=0 align=2 (i32.const 0x13FE02) (i32.const 0)) ;; release power-down SPI command (i32.store8 offset=0 align=1 (i32.const 0x13FC00) (i32.const 0xAB)) ;; start SPI operation (i32.store16 offset=0 align=2 (i32.const 0x13FE04) (i32.const 0x1)) ;; wait for at least 3000 ns after command gets sent ;; reset the timer (i32.store16 offset=0x0 align=2 (i32.const 0x1BFC08) (i32.const 0x0)) ;; loop until 45 ticks pass; 45 ticks is 3600 ns; additional 600ns ;; is enough for power-up command to be sent (loop $again (br_if $again (i32.lt_u (i32.load16_u offset=0x0 align=2 (i32.const 0x1BFC08)) (i32.const 45)))) ;; we'll transfer 2400 bytes by making 5 transfers of 480 bytes; ;; our SPI peripheral can transfer at most 511 bytes in one SPI command (set_local $transfers (i32.const 0)) (loop $outer ;; set bytes_to_output to 5 (i32.store16 offset=0 align=2 (i32.const 0x13FE00) (i32.const 5)) ;; set bytes_to_receive to 480 (i32.store16 offset=0 align=2 (i32.const 0x13FE02) (i32.const 480)) ;; fast read SPI command (i32.store8 offset=0 align=1 (i32.const 0x13FC00) (i32.const 0x0B)) ;; prepare address - first, compute current offset (set_local $offset (i32.mul (get_local $transfers) (i32.const 480))) ;; then, add computed offset to base address of 135100 (set_local $address (i32.add (get_local $offset) (i32.const 135100))) ;; store the address in big endian (i32.store16 offset=0 align=2 (i32.const 0x13FC02) (i32.div_u (get_local $address) (i32.const 256))) (i32.store8 offset=0 align=1 (i32.const 0x13FC03) (get_local $address)) (i32.store8 offset=0 align=1 (i32.const 0x13FC01) (i32.div_u (get_local $address) (i32.const 65536))) ;; start SPI operation (i32.store16 offset=0 align=2 (i32.const 0x13FE04) (i32.const 0x1)) ;; force wait for operation completion (i32.store16 offset=0 align=2 (i32.const 0x13FE00) (i32.const 0)) ;; assume transferred data to be ascii text and print it to screen ;; initialize index to 0 (set_local $index (i32.const 0)) ;; copy characters in a loop (loop $inner ;; copy 4 characters to VGA memory (i32.store offset=0xFFC00 align=4 (i32.add (get_local $index) (get_local $offset)) (i32.load offset=0x13FC00 align=4 (get_local $index))) ;; increase index (set_local $index (i32.add (get_local $index) (i32.const 4))) ;; loop condition (br_if $inner (i32.lt_u (get_local $index) (i32.const 480)))) ;; increase transfers count (set_local $transfers (i32.add (get_local $transfers) (i32.const 1))) ;; switch LED2 (i32.store16 offset=0x0 align=2 (i32.const 0x1BFC06) (i32.rem_u (get_local $transfers) (i32.const 2))) ;; if less than 5 transfers were done, continue with another one (br_if $outer (i32.lt_u (get_local $transfers) (i32.const 5)))) ;; write a non-zero value to the VGA power-on reg at 0x100600 (0x100A00) (i32.store16 offset=0x0 align=2 (i32.const 0x100600) (i32.const 0x1))) (export "main" (func $main)))