My latest project is an assembler for the PIC microcontroller. I figured it'd be an interesting project to embark on, and since I have a whole bunch of the microcontrollers lying around my place, it'd be something I could actually use.
One of the things that makes writing an assembler for the PIC interesting is that there are a few different instruction sets depending on the series you're using, the 18 series have 16 bit instructions and the 12/16 series have 14 bit instructions for example. Because of this, I wanted to make it so an instruction set was something that I could define easily:
(definstructionset pic16-instructions
((addwf :args (f d)
:description "Add W and f"
:opcode "00 0111 dfff ffff")
(andwf :args (f d)
:description "AND W with f"
:opcode "00 0101 dfff ffff")
(bsf :args (f b)
:description "Bit set f"
:opcode "01 01bb bfff ffff")
...))
I decided to describe the opcodes as strings like that, as thats how they are defined in the official data sheets:
Eventually, I'd like to have a script that you could pass the datasheet PDF and it would auto generate the instruction set descriptor.
From that point a macro converts the instruction specs into a hash table of instruction symbols to instruction-spec classes:
(defclass instruction-spec ()
((mnemonic :accessor spec-mnemonic
:initarg :mnemonic)
(description :accessor spec-description
:initarg :description)
(opcode :accessor spec-opcode
:initarg :opcode)
(base :accessor spec-base
:initarg :base)
(byte-specs :accessor spec-byte-specs
:initarg :byte-specs)
(args :accessor spec-args
:initarg :args)))
The base slot of the class is an integer with all the parts of the opcode that are static (e.g the 0101 of the BSF instruction), and the byte-specs will be a list that maps instruction arguments (f, b, etc) to their respective parts of the opcode.
What's next? A way to tell the assembler about the different memory maps of PIC. This will be so that the assembler will automatically be aware of the all the PIC control registers without having to bring in / create an include file for each processor.
And from there the actual assembler/evaluator, right now I'm thinking that it'll be used like this:
(assemble :target pic16f877
:fuses (NO_WATCHDOG NO_CODE_PROTECT)
((:start 0) ;; label with explicit start address
(goto setup)
(:interrupt-service-routine 4)
(goto isr)
(:setup
(bsf latb 2)
(movlw (* 6 7))
(movwf LIFE)
(some-function-call some-arguments)
;; the output of the function called will be evaluated, like
;; macros.
...))) => #
;; and a way to turn the assembled output to into s-records ready for
;; a pic programmer.
Until next time...
Edit: Fixed typos, remind me not to blog without sleep.
Here's a few small emacsisms ive been working on, they're all small things that I've written on a whim to help with work
grep -r to search files and will open each file that returned a match
(defun recursive-grep-open (where pattern)
"searches where for pattern using a recursive grep and will open all files that match"
(interactive "DWhere: \nsPattern: ")
(with-temp-buffer
(call-process "grep"
nil
'(t nil)
nil
"-rl"
pattern
where)
(goto-char (point-min))
(while (< (point) (point-max)) (let ((cp (point))) (end-of-line) (find-file (buffer-substring cp (point))) (beginning-of-line 2)))))
audit-set-destination) with a heading for the filename, the line number and message which is prompted for and the code snippet itself.
(defvar audit-destination-buffer nil)
(defun audit-set-destination (buffer)
(interactive "bDestination Buffer: ")
(setq tm-audit-destination-buffer buffer))
(defun audit-this (beg end message)
(interactive "r\nsMessage: ")
(save-excursion
(let* ((buffer-name (buffer-name))
(source-buf (current-buffer))
(where (or tm-audit-destination-buffer
(read-buffer "Audit buffer: ")))
(file-heading (format "\n* File: %s\n" buffer-name))
(text (buffer-substring beg end))
(start-line (progn (goto-char beg)
(line-number-at-pos)))
(chunk (format "\n** Line: %d\n - %s\n%s\n"
start-line
message
text)))
(switch-to-buffer where)
(save-excursion
(goto-char (point-min))
(if (not (re-search-forward (format "^\\* File: %s$" buffer-name) nil t))
(progn (goto-char (point-max))
(insert file-heading)))
(insert chunk))
(switch-to-buffer source-buf))))
post-command-hook, is there a better place for this?
;; slightly nasty
;; this could probably be optomised, but
(defun add-function-name-to-header-line ()
"adds the name of the current function into the header line"
(if (eq major-mode 'cperl-mode)
(progn
(save-excursion
(if (re-search-backward "^sub\s+\\([a-zA-Z0-9_]+\\)" nil t)
(setq header-line-format (format "function: %s" (match-string 1)))
(setq header-line-format nil))))))
(add-to-list 'post-command-hook 'add-function-name-to-header-line)
(defun helpful-buffer-name ()
(interactive)
(save-excursion
(goto-char (point-min))
(if (re-search-forward "^package \\(.+\\);" nil t)
(let ((pkg (match-string 1)))
(if (get-buffer pkg)
(rename-buffer (format "%s (%s)"
pkg
(buffer-file-name))
t)
(rename-buffer pkg))))))
(add-hook 'cperl-mode-hook (lambda () (helpful-buffer-name)))
I hope some of you out there find this stuff useful!
edit: Changed the headings so they look better on planet lisp.. sorry guys.
I recently switched over to gnus for reading my work email and wanted an interface to LDAP. Having failed to get eudc and ldap working together nicely, I hacked together a very quick interface to pull out fields by name in ldap.
You only need to set the ldap-server variable. The ldap-insert-field function searches by using 'cn' .
I hope this is useful to someone!
r2q2 reminded me of this. It's a module i wrote for DrScheme to generate elementary cellular automata:
Enjoy!
Just don't use rule 30 to generate pseudo-random numbers, because Mr. Wolfram has a patent on it.Another thing that really helps is Work Rave. Except sometimes i skip the breaks, which is very, very bad.
I have it set to 10 minute microbreaks and rest breaks every 50 minutes.
Also, Stuart Sierra pointed the poor man's ergonimic laptop stand out to me. I might try and build one of these.
Seems to me that everyone has a laptop these days, is the desktop truly dead? Having my laptop with me all the time proves to be really useful. It's one of the things that tempts me to getting an Thinkpad X60. But that's a whole different story.
(defun insert-multiple-yow (n)
(interactive "nHow many: ")
(dotimes (i n)
(insert (yow))))
LOU GRANT froze my ASSETS!!Yow! I just went below the poverty line!I'm protected by a ROLL-ON I rented from AVIS..I put aside my copy of ``BOWLING WORLD'' and think about GUN CONTROL legislation..I can't think about that. It doesn't go with HEDGES in the shape of LITTLE LULU -- or ROBOTS making BRICKS...I'm losing my hair..did it go to ATLANTIC CITY??Ask me the DIFFERENCE between PHIL SILVERS and ALEXANDER HAIG!!Why is everything made of Lycra Spandex?.. I wonder if I ought to tell them about my PREVIOUS LIFE as a COMPLETE STRANGER?I'm EMOTIONAL now because I have MERCHANDISING CLOUT!!
I've been given a choice by my boss for a new laptop, a Thinkpad T60 or a Macbook Pro. And I'm having a hell of a choice deciding. If I get a T60, I'll be running ubuntu 6.06. I'm tempted by both.
My main temptation with the macbook is the hardware support and excellent integration, easy to use interface, and my temptation with the T60 is that I'm very familiar with ubuntu, I have access to a *lot* of packages pre-built (albeit some of them are a little crusty) and I can run Windows 2k/XP in VMWare (which, unfortunately, I need to do for work).
What CL implementations work well on OSX/Intel? Including FFI support, etc?
I was all set for going with the T60 until last night I tried to use my laptop running ubuntu on my father-in-laws new HDTV and completely failed to get X to display anything but 800x600 on the TV (and I'm no shrinking violet to an X config file.) And I was pretty sure that this would not have happened on a Mac.
Which would you go for?
p.s there will be no pennies
Edit: I just read a lot of mixed reviews on amazon regarding the MBPro.. and I haven't heard anything bad about the T60...
Edit: I forgot to mention that I used to have a Thinkpad X40 and REALLY liked it (apart from the lack of trackpad). I'm swinging more towards to the thinkpad now.. dillemas, dillemas.
Edit: I also used to have a Mac Mini...
Edit: Since people here have informed me that some of the hardware issues on the MBPro have been fixed and that theres some hardware problems with linux on the T60, i'm swinging more towards the MBPro.
I'm VERY surpised at how easy (I am i speaking too soon?) it is create a FFI using CFFI. I'm slowly hacking out a packet sniffing package using a FFI to pcap.
I've been working on a traffic analysis app for a company I used to work for, it's written in C, and the statement "Every Program sufficiently large, has embedded within in it, a poorly implemented version of Common Lisp." is proving true. Once I'm done on that project, I hope to rewrite in CL using this module. It's a traffic analyser that uses state machines to track individual sessions and connections in real-time. I've written two statemachines inside it to track TCP and HTTP sessions. The HTTP statemachine uses the TCP statemachine embedded inside it, so it can concentrate on the HTTP aspect ignoring the TCP aspect. It works quite well so far!
Generally, I'm enjoying picking up CL coming from a Scheme background.
(labels (...) ...) instead of let in evolves, the funcall there is a little ugly. I need to remember that it's elisp not scheme.
(defun bit-setp (i n)
(not (equal (logand (lsh 1 i) n) 0)))
(defun char-to-bool (ch)
(not (equal ch ? )))
(defmacro defelemca (name ruleno)
(let ((val (make-symbol "val")))
`(defun ,name (cur neighbours)
(let ((,val (+ (if (char-to-bool (first neighbours)) 4 0)
(if (char-to-bool cur) 2 0)
(if (char-to-bool (second neighbours)) 1 0))))
(bit-setp ,val ,ruleno)))))
(defun result-to-string (res char)
"formats a bool result to a string"
(if res (char-to-string char) " "))
(defun get-element (n vline)
"returns the n'th element of vline, returns a space if we're out of bounds"
(cond
((equal n -1) ? )
((>= n (length vline)) ? )
(t (aref vline n))))
(defun get-neighbours (n vline)
"returns the neighbours of char n in vline"
(list (get-element (- n 1) vline)
(get-element (+ n 1) vline)))
(defun evolve-string (ca line on)
"evolve a string using ca"
(let* ((output "")
(evolves
(lambda (line)
(dotimes (i (length line))
(let* ((el (get-element i line))
(ne (get-neighbours i line))
(res (funcall ca el ne))
(ch (result-to-string res on)))
(setq output
(concat output ch)))))))
(funcall evolves line)
output))
(defun center-string (n c)
"Center a char in a line of width n"
(store-substring (make-string n ? )
(/ n 2)
c))
(defun evolve-generations (rn gens on line)
"Evolves an elementry CA for gens generations on string line, using on as the active char"
(let ((result line))
(dotimes (i gens)
(newline)
(insert result)
(setq result (evolve-string rn result on)))))
(defun insert-elem-ca (rule gens width ch)
"Inserts an elementry CA into the current buffer"
(interactive "nRule No: \nnGenerations: \nnwidth: \ncOn char: ")
(defelemca ruleca rule)
(evolve-generations #'ruleca
gens
ch
(center-string width ch )))
; insert-elem-ca:
;
; .
; ...
; .. .
; .. ....
; .. . .
; .. .... ...
; .. . . .
; .. .... ......
; .. . ... .
; .. .... .. . ...
; .. . . .... .. .
; .. .... .. . . ....
; .. . ... .. .. . .
; .. .... .. ... ... .. ...
; .. . . ... . ... . .
;.. .... .. . . ..... ......
Yet another code monkey from London, living in LA.
Links