/ bit2mcs.scm
bit2mcs.scm
  1  #!/usr/bin/env -S guile --r7rs -e "main" -s
  2  !#
  3  
  4  (import (srfi 1)
  5          (srfi 26)
  6          (rnrs bytevectors)
  7          (rnrs bytevectors gnu)
  8          (ice-9 format)
  9          (ice-9 binary-ports))
 10  
 11  ;;; Print message and exit
 12  (define (abort . fmt)
 13    (apply format (cons (current-error-port) fmt))
 14    (newline (current-error-port))
 15    (exit 1))
 16  
 17  ;;; Read word in big endian
 18  (define (read-word-be n port)
 19    (let ((data (get-bytevector-n port n)))
 20      (if (or (eof-object? data)
 21              (not (= (bytevector-length data) n)))
 22          (abort "Unexpected end of file. Abort.")
 23          (bytevector-uint-ref data 0 (endianness big) n))))
 24  
 25  ;;; Read configuration to bytevector
 26  (define (read-configuration file)
 27    (call-with-input-file file
 28      (lambda (port)
 29        ;; check header
 30        (let* ((golden #vu8(#x00 #x09 #x0f #xf0 #x0f #xf0 #x0f #xf0 #x0f #xf0 #x00 #x00 #x01))
 31               (header (get-bytevector-n port (bytevector-length golden))))
 32          (when (or (not (equal? header golden)))
 33            (abort "This file is not a bitstream. Abort.")))
 34  
 35        ;; find configuration block
 36        (let next-block ()
 37          (let ((type (get-u8 port)))
 38            (cond
 39             ((eof-object? type) (abort ("Configuration block not found.")))
 40             ;; return configuration data
 41             ((= type #x65) (get-bytevector-n port (read-word-be 4 port)))
 42             ;; skip block
 43             (else
 44              (get-bytevector-n port (read-word-be 2 port))
 45              (next-block))))))
 46  
 47      #:binary #t))
 48  
 49  ;;; Calculate Intel HEX checksum
 50  (define (checksum data)
 51    (logand
 52     #xff
 53     (+ 1 (lognot
 54           (apply + (bytevector->u8-list data))))))
 55  
 56  ;;; Return byte n of the number x
 57  (define (byte-ref x n)
 58    (bit-extract x (* n 8) (* (+ 1 n) 8)))
 59  
 60  ;;; Print byte. Use manual conversion for speedup
 61  (define (print-byte b)
 62    (define (print-nibble x)
 63      (display (cond
 64                ((= x 0) "0")
 65                ((= x 1) "1")
 66                ((= x 2) "2")
 67                ((= x 3) "3")
 68                ((= x 4) "4")
 69                ((= x 5) "5")
 70                ((= x 6) "6")
 71                ((= x 7) "7")
 72                ((= x 8) "8")
 73                ((= x 9) "9")
 74                ((= x 10) "A")
 75                ((= x 11) "B")
 76                ((= x 12) "C")
 77                ((= x 13) "D")
 78                ((= x 14) "E")
 79                ((= x 15) "F"))))
 80    (print-nibble (bit-extract b 4 8))
 81    (print-nibble (bit-extract b 0 4)))
 82  
 83  ;;; Print Intel HEX record
 84  (define (print-ihex-record data)
 85    (let ((crc (checksum data)))
 86      (display ":")
 87      (for-each print-byte (bytevector->u8-list data))
 88      (print-byte crc)
 89      (newline)))
 90  
 91  ;;; Print bytevector blob as Intel HEX
 92  (define (bytevector-print-as-ihex data)
 93    (let ((data-len (bytevector-length data)))
 94      (let print-rec ((address 0))
 95        ;; Extended Linear Address (high part of the address)
 96        (when (zero? (logand #xffff address ))
 97          (print-ihex-record
 98           (u8-list->bytevector
 99            `(#x02 #x00 #x00 #x04 ,(byte-ref address 3) ,(byte-ref address 2)))))
100  
101        ;; get piece of bytes
102        (let* ((len (- data-len address))
103               (len (if (< len 16) len 16))
104               (data (bytevector-slice data address len)))
105          (print-ihex-record
106           (u8-list->bytevector
107            (append
108             `(,len ,(byte-ref address 1) ,(byte-ref address 0) 0)
109             (bytevector->u8-list data))))
110  
111          (let ((address (+ address len)))
112            (when (< address data-len)
113              (print-rec address)))))
114      (display ":00000001FF")
115      (newline)))
116  
117  ;;; MAIN
118  (define (main args)
119    (if (null? (cdr args))
120        (format (current-error-port) "Usage: ~a <bitstream.bit> [> bitstream.mcs]\n" (first args))
121        (let* ((bitfile (second args))
122               (conf (read-configuration bitfile)))
123          (format (current-error-port) "Length of bitstream: ~a bytes\n" (bytevector-length conf))
124          (bytevector-print-as-ihex conf))))